1 : // Copyright 2013 Google Inc. All Rights Reserved.
2 : //
3 : // Licensed under the Apache License, Version 2.0 (the "License");
4 : // you may not use this file except in compliance with the License.
5 : // You may obtain a copy of the License at
6 : //
7 : // http://www.apache.org/licenses/LICENSE-2.0
8 : //
9 : // Unless required by applicable law or agreed to in writing, software
10 : // distributed under the License is distributed on an "AS IS" BASIS,
11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : // See the License for the specific language governing permissions and
13 : // limitations under the License.
14 :
15 : #include "syzygy/pehacker/variables.h"
16 :
17 : #include "base/logging.h"
18 : #include "base/json/json_reader.h"
19 : #include "base/strings/stringprintf.h"
20 : #include "base/strings/utf_string_conversions.h"
21 :
22 : namespace pehacker {
23 :
24 : namespace {
25 :
26 : // Converts a variable to a string.
27 : bool ConvertVariableToString(bool quote_strings,
28 : const base::Value& value,
29 E : std::string* s) {
30 E : DCHECK_NE(reinterpret_cast<std::string*>(NULL), s);
31 :
32 E : switch (value.GetType()) {
33 : case base::Value::TYPE_BOOLEAN: {
34 E : bool b = false;
35 E : CHECK(value.GetAsBoolean(&b));
36 E : *s = b ? "1" : "0";
37 E : return true;
38 : }
39 :
40 : case base::Value::TYPE_INTEGER: {
41 E : int i = 0;
42 E : CHECK(value.GetAsInteger(&i));
43 E : *s = base::StringPrintf("%d", i);
44 E : return true;
45 : }
46 :
47 : case base::Value::TYPE_STRING: {
48 E : CHECK(value.GetAsString(s));
49 E : if (quote_strings) {
50 E : s->insert(s->begin(), 1, '"');
51 E : s->append(1, '"');
52 : }
53 E : return true;
54 : }
55 :
56 : default: {
57 E : LOG(ERROR) << "Variables must be strings, booleans or integers.";
58 E : return false;
59 : }
60 : }
61 E : }
62 :
63 : // Expands |value| using the given |variables|, placing the result in
64 : // |expanded|. |expanded| and |value| may refer to the same string. An
65 : // initial expansion should pass in |depth| of 0, as this is used to limit
66 : // the depth of the expansion. Returns true on success, false otherwise.
67 : bool ExpandVariables(size_t depth,
68 : const base::DictionaryValue& variables,
69 : const std::string& value,
70 E : std::string* expanded) {
71 E : DCHECK_NE(reinterpret_cast<std::string*>(NULL), expanded);
72 :
73 E : VLOG(1) << "Expanding variables in \"" << value << "\" (depth="
74 : << depth << ").";
75 :
76 E : std::string temp;
77 :
78 : // Arbitrarily limit ourselves to a recursion depth of 100.
79 E : if (depth > 100) {
80 E : LOG(ERROR) << "Recursion too deep in variable expansion of \""
81 : << value << "\".";
82 E : return false;
83 : }
84 :
85 : // Scan through the input looking for $(var_name) sequences.
86 E : size_t open = std::string::npos;
87 E : size_t i = 0;
88 E : while (i < value.size()) {
89 : // Reading normal string data, keeping an eye out for an opening delimiter.
90 E : if (open == std::string::npos) {
91 E : if (value[i] == '$') {
92 : // Handle $$ and $( sequences.
93 E : if (i + 1 < value.size()) {
94 : // Two $$ are treated as a single literal $.
95 E : if (value[i + 1] == '$') {
96 E : i += 2;
97 E : temp.append(1, '$');
98 E : continue;
99 E : } else if (value[i + 1] == '(') {
100 : // A $( is treated as the opening of a variable name.
101 E : i += 2;
102 E : open = i;
103 E : continue;
104 : }
105 : }
106 :
107 : // If we get here then we have a trailing $, or a $ not followed by
108 : // a $ or a (. These are all malformed.
109 E : LOG(ERROR) << "Expect $$ or $( in \"" << value << "\".";
110 E : return false;
111 : }
112 :
113 : // If we get here we're simply appending the character to the output.
114 E : temp.append(1, value[i]);
115 E : i += 1;
116 E : continue;
117 : }
118 :
119 : // If we get here we're reading a variable name, waiting for a closing
120 : // parenthesis.
121 E : if (value[i] == ')') {
122 : // Lookup the variable name and recursively expand it. We limit
123 : // recursion depth to deal with circular definitions.
124 E : std::string name(value.begin() + open, value.begin() + i);
125 :
126 : // Ensure the variable name is valid. This rejects invalid characters,
127 : // empty names, etc.
128 E : if (!VariableNameIsValid(name)) {
129 E : LOG(ERROR) << "Invalid variable name \"" << name << "\" in \""
130 : << value << "\".";
131 E : return false;
132 : }
133 :
134 E : const base::Value* value = NULL;
135 E : if (!variables.Get(name, &value)) {
136 E : LOG(ERROR) << "Variable \"" << name << "\" not defined.";
137 E : return false;
138 : }
139 :
140 : // Convert the variable to a string representation, which is the final
141 : // type of all variables.
142 E : std::string s1;
143 E : if (!ConvertVariableToString(false, *value, &s1))
144 i : return false;
145 :
146 : // Recursively expand.
147 E : std::string s2;
148 E : if (!ExpandVariables(depth + 1, variables, s1, &s2))
149 E : return false;
150 :
151 : // Append the expanded value.
152 E : temp.append(s2);
153 :
154 : // Transition back to reading normal characters.
155 E : open = std::string::npos;
156 E : }
157 :
158 : // This steps past the close parenthesis, or a character that is part of
159 : // a variable name.
160 E : i += 1;
161 E : }
162 :
163 : // If waiting for a closing parenthesis then the string is malformed.
164 E : if (open != std::string::npos) {
165 E : LOG(ERROR) << "Unbalanced parentheses in value \"" << value << "\".";
166 E : return false;
167 : }
168 :
169 : // Swap the expanded result with the output. This allows 'in-place' expansion
170 : // where |expanded| and |value| refer to the same string.
171 E : expanded->swap(temp);
172 :
173 E : VLOG(1) << "Expanded to \"" << *expanded << "\" (depth=" << depth << ").";
174 :
175 E : return true;
176 E : }
177 :
178 : } // namespace
179 :
180 E : bool VariableNameIsValid(const std::string& name) {
181 E : if (name.empty())
182 E : return false;
183 :
184 E : for (size_t i = 0; i < name.size(); ++i) {
185 E : if (name[i] == '_' || ::isalnum(name[i]))
186 E : continue;
187 E : return false;
188 i : }
189 :
190 E : return true;
191 E : }
192 :
193 E : bool ConvertVariableToString(const base::Value& value, std::string* s) {
194 E : DCHECK_NE(reinterpret_cast<std::string*>(NULL), s);
195 E : if (!ConvertVariableToString(false, value, s))
196 E : return false;
197 E : return true;
198 E : }
199 :
200 E : bool ConvertVariableToJson(const base::Value& value, std::string* s) {
201 E : DCHECK_NE(reinterpret_cast<std::string*>(NULL), s);
202 E : if (!ConvertVariableToString(true, value, s))
203 E : return false;
204 E : return true;
205 E : }
206 :
207 : bool ParseVariable(const std::string& raw_name,
208 : const base::Value& value,
209 E : base::DictionaryValue* dict) {
210 E : DCHECK_NE(reinterpret_cast<base::DictionaryValue*>(NULL), dict);
211 :
212 E : std::string name = raw_name;
213 :
214 : // Remove any modifiers.
215 E : bool set_default = false;
216 E : if (name.back() == '%') {
217 E : set_default = true;
218 E : name.resize(name.size() - 1);
219 : }
220 :
221 E : if (!VariableNameIsValid(name)) {
222 E : LOG(ERROR) << "Invalid variable name \"" << name << "\".";
223 E : return false;
224 : }
225 :
226 E : if (dict->HasKey(name)) {
227 E : if (set_default) {
228 E : VLOG(1) << "Ignoring default value for already set variable \""
229 : << name << "\".";
230 E : return true;
231 i : } else {
232 E : LOG(ERROR) << "Variable already defined \"" << name << "\".";
233 E : return false;
234 : }
235 : }
236 :
237 : // For now we only accept simple types that are unambiguously converted to
238 : // strings.
239 : if (value.GetType() != base::Value::TYPE_STRING &&
240 : value.GetType() != base::Value::TYPE_BOOLEAN &&
241 E : value.GetType() != base::Value::TYPE_INTEGER) {
242 E : LOG(ERROR) << "Variables must be strings, booleans or integers.";
243 E : return false;
244 : }
245 :
246 : // Finally, set the value of the variable. Ownership is passed to the
247 : // dictionary.
248 E : VLOG(1) << "Setting " << (set_default ? "default " : "") << "value of \""
249 : << name << "\" to " << value;
250 E : dict->Set(name, value.DeepCopy());
251 E : return true;
252 E : }
253 :
254 : bool ParseVariable(const std::string& raw_name,
255 : const std::string& value_string,
256 E : base::DictionaryValue* dict) {
257 E : DCHECK_NE(reinterpret_cast<base::DictionaryValue*>(NULL), dict);
258 :
259 : // Parse the value. We first try to parse it as valid JSON. If that
260 : // fails we treat it as a raw string.
261 E : scoped_ptr<base::Value> value(base::JSONReader::Read(value_string, 0));
262 E : if (value.get() == NULL)
263 E : value.reset(new base::StringValue(value_string));
264 :
265 E : if (!ParseVariable(raw_name, *value.get(), dict))
266 E : return false;
267 E : return true;
268 E : }
269 :
270 : bool MergeVariables(const base::DictionaryValue& src,
271 E : base::DictionaryValue* dst) {
272 E : DCHECK_NE(reinterpret_cast<base::DictionaryValue*>(NULL), dst);
273 :
274 : // Iterate over the values in the source dictionary and add them to the
275 : // destination dictionary. This logs verbosely on failure, and handles
276 : // variable directives (default values, etc).
277 E : base::DictionaryValue::Iterator it(src);
278 E : for (; !it.IsAtEnd(); it.Advance()) {
279 E : if (!ParseVariable(it.key(), it.value(), dst))
280 E : return false;
281 E : }
282 :
283 E : return true;
284 E : }
285 :
286 : bool ExpandVariables(const base::DictionaryValue& variables,
287 : const std::string& value,
288 E : std::string* expanded) {
289 E : DCHECK_NE(reinterpret_cast<std::string*>(NULL), expanded);
290 E : if (!ExpandVariables(0, variables, value, expanded))
291 E : return false;
292 E : return true;
293 E : }
294 :
295 : } // namespace pehacker
|