You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
172 lines
4.4 KiB
172 lines
4.4 KiB
/* |
|
* Copyright (C) 2017 The Android Open Source Project |
|
* |
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
* you may not use this file except in compliance with the License. |
|
* You may obtain a copy of the License at |
|
* |
|
* http://www.apache.org/licenses/LICENSE-2.0 |
|
* |
|
* Unless required by applicable law or agreed to in writing, software |
|
* distributed under the License is distributed on an "AS IS" BASIS, |
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
* See the License for the specific language governing permissions and |
|
* limitations under the License. |
|
*/ |
|
|
|
#include "Hash.h" |
|
|
|
#include <fstream> |
|
#include <iomanip> |
|
#include <map> |
|
#include <regex> |
|
#include <sstream> |
|
|
|
#include <android-base/logging.h> |
|
#include <openssl/sha.h> |
|
|
|
namespace android { |
|
|
|
const Hash &Hash::getHash(const std::string &path) { |
|
static std::map<std::string, Hash> hashes; |
|
|
|
auto it = hashes.find(path); |
|
|
|
if (hashes.find(path) == hashes.end()) { |
|
it = hashes.insert(it, {path, Hash(path)}); |
|
} |
|
|
|
return it->second; |
|
} |
|
|
|
static std::vector<uint8_t> sha256File(const std::string &path) { |
|
std::ifstream stream(path); |
|
std::stringstream fileStream; |
|
fileStream << stream.rdbuf(); |
|
std::string fileContent = fileStream.str(); |
|
|
|
std::vector<uint8_t> ret = std::vector<uint8_t>(SHA256_DIGEST_LENGTH); |
|
|
|
SHA256(reinterpret_cast<const uint8_t *>(fileContent.c_str()), |
|
fileContent.size(), ret.data()); |
|
|
|
return ret; |
|
} |
|
|
|
Hash::Hash(const std::string &path) |
|
: mPath(path), |
|
mHash(sha256File(path)) {} |
|
|
|
std::string Hash::hexString(const std::vector<uint8_t> &hash) { |
|
std::ostringstream s; |
|
s << std::hex << std::setfill('0'); |
|
for (uint8_t i : hash) { |
|
s << std::setw(2) << static_cast<int>(i); |
|
} |
|
return s.str(); |
|
} |
|
|
|
std::string Hash::hexString() const { |
|
return hexString(mHash); |
|
} |
|
|
|
const std::vector<uint8_t> &Hash::raw() const { |
|
return mHash; |
|
} |
|
|
|
const std::string &Hash::getPath() const { |
|
return mPath; |
|
} |
|
|
|
#define HASH "([0-9a-f]+)" |
|
#define FQNAME "([^\\s]+)" |
|
#define SPACES " +" |
|
#define MAYBE_SPACES " *" |
|
#define OPTIONAL_COMMENT "(?:#.*)?" |
|
static const std::regex kHashLine( |
|
"(?:" |
|
MAYBE_SPACES HASH SPACES FQNAME MAYBE_SPACES |
|
")?" |
|
OPTIONAL_COMMENT); |
|
|
|
struct HashFile { |
|
static const HashFile *parse(const std::string &path, std::string *err) { |
|
static std::map<std::string, HashFile*> hashfiles; |
|
auto it = hashfiles.find(path); |
|
|
|
if (it == hashfiles.end()) { |
|
it = hashfiles.insert(it, {path, readHashFile(path, err)}); |
|
} |
|
|
|
return it->second; |
|
} |
|
|
|
std::vector<std::string> lookup(const std::string &fqName) const { |
|
auto it = hashes.find(fqName); |
|
|
|
if (it == hashes.end()) { |
|
return {}; |
|
} |
|
|
|
return it->second; |
|
} |
|
|
|
private: |
|
static HashFile *readHashFile(const std::string &path, std::string *err) { |
|
std::ifstream stream(path); |
|
if (!stream) { |
|
return nullptr; |
|
} |
|
|
|
HashFile *file = new HashFile(); |
|
file->path = path; |
|
|
|
std::string line; |
|
while(std::getline(stream, line)) { |
|
std::smatch match; |
|
bool valid = std::regex_match(line, match, kHashLine); |
|
|
|
if (!valid) { |
|
*err = "Error reading line from " + path + ": " + line; |
|
delete file; |
|
return nullptr; |
|
} |
|
|
|
CHECK_EQ(match.size(), 3u); |
|
|
|
std::string hash = match.str(1); |
|
std::string fqName = match.str(2); |
|
|
|
if (hash.size() == 0 && fqName.size() == 0) { |
|
continue; |
|
} |
|
|
|
if (hash.size() == 0 || fqName.size() == 0) { |
|
*err = "Hash or fqName empty on " + path + ": " + line; |
|
delete file; |
|
return nullptr; |
|
} |
|
|
|
file->hashes[fqName].push_back(hash); |
|
} |
|
return file; |
|
} |
|
|
|
std::string path; |
|
std::map<std::string,std::vector<std::string>> hashes; |
|
}; |
|
|
|
std::vector<std::string> Hash::lookupHash(const std::string &path, |
|
const std::string &interfaceName, |
|
std::string *err) { |
|
*err = ""; |
|
const HashFile *file = HashFile::parse(path, err); |
|
|
|
if (file == nullptr || err->size() > 0) { |
|
return {}; |
|
} |
|
|
|
return file->lookup(interfaceName); |
|
} |
|
|
|
} // android
|
|
|