Coverage for /Syzygy/pehacker/variables.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
97.9%1391420.C++source

Line-by-line coverage:

   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

Coverage information generated Thu Jan 14 17:40:38 2016.