blob: 032227f01dfc6465484b1c9d8129e032a9f607e6 [file] [log] [blame]
Steven Moreland0e4be1e2017-04-18 19:50:29 -07001/*
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>
Steven Moreland218625a2017-04-18 22:31:50 -070022#include <regex>
Steven Moreland0e4be1e2017-04-18 19:50:29 -070023#include <sstream>
24
Steven Moreland218625a2017-04-18 22:31:50 -070025#include <android-base/logging.h>
Steven Moreland0e4be1e2017-04-18 19:50:29 -070026#include <openssl/sha.h>
27
28namespace android {
29
30const 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
42static 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
56Hash::Hash(const std::string &path)
57 : mPath(path),
58 mHash(sha256File(path)) {}
59
Tri Vo59ce7422017-04-26 10:53:54 -070060std::string Hash::hexString(const std::vector<uint8_t> &hash) {
Steven Moreland0e4be1e2017-04-18 19:50:29 -070061 std::ostringstream s;
62 s << std::hex << std::setfill('0');
Tri Vo59ce7422017-04-26 10:53:54 -070063 for (uint8_t i : hash) {
Steven Moreland0e4be1e2017-04-18 19:50:29 -070064 s << std::setw(2) << static_cast<int>(i);
65 }
66 return s.str();
67}
68
Tri Vo59ce7422017-04-26 10:53:54 -070069std::string Hash::hexString() const {
70 return hexString(mHash);
71}
72
Steven Moreland0e4be1e2017-04-18 19:50:29 -070073const std::vector<uint8_t> &Hash::raw() const {
74 return mHash;
75}
76
77const std::string &Hash::getPath() const {
78 return mPath;
79}
80
Steven Moreland5bdfa702017-04-18 23:20:39 -070081#define HASH "([0-9a-f]+)"
82#define FQNAME "([^\\s]+)"
Steven Moreland218625a2017-04-18 22:31:50 -070083#define SPACES " +"
84#define MAYBE_SPACES " *"
85#define OPTIONAL_COMMENT "(?:#.*)?"
86static const std::regex kHashLine(
87 "(?:"
88 MAYBE_SPACES HASH SPACES FQNAME MAYBE_SPACES
89 ")?"
90 OPTIONAL_COMMENT);
91
92struct 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
114private:
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
Steven Moreland218625a2017-04-18 22:31:50 -0700159std::vector<std::string> Hash::lookupHash(const std::string &path,
160 const std::string &interfaceName,
161 std::string *err) {
162 *err = "";
Steven Moreland5bdfa702017-04-18 23:20:39 -0700163 const HashFile *file = HashFile::parse(path, err);
Steven Moreland218625a2017-04-18 22:31:50 -0700164
165 if (file == nullptr || err->size() > 0) {
166 return {};
167 }
168
169 return file->lookup(interfaceName);
170}
171
Tri Vo59ce7422017-04-26 10:53:54 -0700172} // android