Home | History | Annotate | Download | only in hidl
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "Hash.h"
     18 
     19 #include <fstream>
     20 #include <iomanip>
     21 #include <map>
     22 #include <regex>
     23 #include <sstream>
     24 
     25 #include <android-base/logging.h>
     26 #include <openssl/sha.h>
     27 
     28 namespace android {
     29 
     30 const Hash &Hash::getHash(const std::string &path) {
     31     static std::map<std::string, Hash> hashes;
     32 
     33     auto it = hashes.find(path);
     34 
     35     if (hashes.find(path) == hashes.end()) {
     36         it = hashes.insert(it, {path, Hash(path)});
     37     }
     38 
     39     return it->second;
     40 }
     41 
     42 static std::vector<uint8_t> sha256File(const std::string &path) {
     43     std::ifstream stream(path);
     44     std::stringstream fileStream;
     45     fileStream << stream.rdbuf();
     46     std::string fileContent = fileStream.str();
     47 
     48     std::vector<uint8_t> ret = std::vector<uint8_t>(SHA256_DIGEST_LENGTH);
     49 
     50     SHA256(reinterpret_cast<const uint8_t *>(fileContent.c_str()),
     51             fileContent.size(), ret.data());
     52 
     53     return ret;
     54 }
     55 
     56 Hash::Hash(const std::string &path)
     57   : mPath(path),
     58     mHash(sha256File(path)) {}
     59 
     60 std::string Hash::hexString(const std::vector<uint8_t> &hash) {
     61     std::ostringstream s;
     62     s << std::hex << std::setfill('0');
     63     for (uint8_t i : hash) {
     64         s << std::setw(2) << static_cast<int>(i);
     65     }
     66     return s.str();
     67 }
     68 
     69 std::string Hash::hexString() const {
     70     return hexString(mHash);
     71 }
     72 
     73 const std::vector<uint8_t> &Hash::raw() const {
     74     return mHash;
     75 }
     76 
     77 const std::string &Hash::getPath() const {
     78     return mPath;
     79 }
     80 
     81 #define HASH "([0-9a-f]+)"
     82 #define FQNAME "([^\\s]+)"
     83 #define SPACES " +"
     84 #define MAYBE_SPACES " *"
     85 #define OPTIONAL_COMMENT "(?:#.*)?"
     86 static const std::regex kHashLine(
     87     "(?:"
     88         MAYBE_SPACES HASH SPACES FQNAME MAYBE_SPACES
     89     ")?"
     90     OPTIONAL_COMMENT);
     91 
     92 struct HashFile {
     93     static const HashFile *parse(const std::string &path, std::string *err) {
     94         static std::map<std::string, HashFile*> hashfiles;
     95         auto it = hashfiles.find(path);
     96 
     97         if (it == hashfiles.end()) {
     98             it = hashfiles.insert(it, {path, readHashFile(path, err)});
     99         }
    100 
    101         return it->second;
    102     }
    103 
    104     std::vector<std::string> lookup(const std::string &fqName) const {
    105         auto it = hashes.find(fqName);
    106 
    107         if (it == hashes.end()) {
    108             return {};
    109         }
    110 
    111         return it->second;
    112     }
    113 
    114 private:
    115     static HashFile *readHashFile(const std::string &path, std::string *err) {
    116         std::ifstream stream(path);
    117         if (!stream) {
    118             return nullptr;
    119         }
    120 
    121         HashFile *file = new HashFile();
    122         file->path = path;
    123 
    124         std::string line;
    125         while(std::getline(stream, line)) {
    126             std::smatch match;
    127             bool valid = std::regex_match(line, match, kHashLine);
    128 
    129             if (!valid) {
    130                 *err = "Error reading line from " + path + ": " + line;
    131                 delete file;
    132                 return nullptr;
    133             }
    134 
    135             CHECK_EQ(match.size(), 3u);
    136 
    137             std::string hash = match.str(1);
    138             std::string fqName = match.str(2);
    139 
    140             if (hash.size() == 0 && fqName.size() == 0) {
    141                 continue;
    142             }
    143 
    144             if (hash.size() == 0 || fqName.size() == 0) {
    145                 *err = "Hash or fqName empty on " + path + ": " + line;
    146                 delete file;
    147                 return nullptr;
    148             }
    149 
    150             file->hashes[fqName].push_back(hash);
    151         }
    152         return file;
    153     }
    154 
    155     std::string path;
    156     std::map<std::string,std::vector<std::string>> hashes;
    157 };
    158 
    159 std::vector<std::string> Hash::lookupHash(const std::string &path,
    160                                           const std::string &interfaceName,
    161                                           std::string *err) {
    162     *err = "";
    163     const HashFile *file = HashFile::parse(path, err);
    164 
    165     if (file == nullptr || err->size() > 0) {
    166         return {};
    167     }
    168 
    169     return file->lookup(interfaceName);
    170 }
    171 
    172 }  // android
    173