1 // Copyright 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/profile_resetter/jtl_interpreter.h" 6 7 #include <numeric> 8 9 #include "base/memory/scoped_vector.h" 10 #include "base/strings/string_number_conversions.h" 11 #include "base/strings/string_util.h" 12 #include "chrome/browser/profile_resetter/jtl_foundation.h" 13 #include "crypto/hmac.h" 14 #include "net/base/registry_controlled_domains/registry_controlled_domain.h" 15 #include "url/gurl.h" 16 17 namespace { 18 19 class ExecutionContext; 20 21 // An operation in an interpreted program. 22 class Operation { 23 public: 24 virtual ~Operation() {} 25 // Executes the operation on the specified context and instructs the context 26 // to continue execution with the next instruction if appropriate. 27 // Returns true if we should continue with any potential backtracking that 28 // needs to be done. 29 virtual bool Execute(ExecutionContext* context) = 0; 30 }; 31 32 // An execution context of operations. 33 class ExecutionContext { 34 public: 35 // |input| is the root of a dictionary that stores the information the 36 // sentence is evaluated on. 37 ExecutionContext(const jtl_foundation::Hasher* hasher, 38 const std::vector<Operation*>& sentence, 39 const DictionaryValue* input, 40 DictionaryValue* working_memory) 41 : hasher_(hasher), 42 sentence_(sentence), 43 next_instruction_index_(0u), 44 working_memory_(working_memory), 45 error_(false) { 46 stack_.push_back(input); 47 } 48 ~ExecutionContext() {} 49 50 // Returns true in case of success. 51 bool ContinueExecution() { 52 if (error_ || stack_.empty()) { 53 error_ = true; 54 return false; 55 } 56 if (next_instruction_index_ >= sentence_.size()) 57 return true; 58 59 Operation* op = sentence_[next_instruction_index_]; 60 next_instruction_index_++; 61 bool continue_traversal = op->Execute(this); 62 next_instruction_index_--; 63 return continue_traversal; 64 } 65 66 std::string GetHash(const std::string& input) { 67 return hasher_->GetHash(input); 68 } 69 70 // Calculates the |hash| of a string, integer or double |value|, and returns 71 // true. Returns false otherwise. 72 bool GetValueHash(const Value& value, std::string* hash) { 73 DCHECK(hash); 74 std::string value_as_string; 75 int tmp_int = 0; 76 double tmp_double = 0.0; 77 if (value.GetAsInteger(&tmp_int)) 78 value_as_string = base::IntToString(tmp_int); 79 else if (value.GetAsDouble(&tmp_double)) 80 value_as_string = base::DoubleToString(tmp_double); 81 else if (!value.GetAsString(&value_as_string)) 82 return false; 83 *hash = GetHash(value_as_string); 84 return true; 85 } 86 87 const Value* current_node() const { return stack_.back(); } 88 std::vector<const Value*>* stack() { return &stack_; } 89 DictionaryValue* working_memory() { return working_memory_; } 90 bool error() const { return error_; } 91 92 private: 93 // A hasher used to hash node names in a dictionary. 94 const jtl_foundation::Hasher* hasher_; 95 // The sentence to be executed. 96 const std::vector<Operation*> sentence_; 97 // Position in |sentence_|. 98 size_t next_instruction_index_; 99 // A stack of Values, indicating a navigation path from the root node of 100 // |input| (see constructor) to the current node on which the 101 // sentence_[next_instruction_index_] is evaluated. 102 std::vector<const Value*> stack_; 103 // Memory into which values can be stored by the program. 104 DictionaryValue* working_memory_; 105 // Whether a runtime error occurred. 106 bool error_; 107 DISALLOW_COPY_AND_ASSIGN(ExecutionContext); 108 }; 109 110 class NavigateOperation : public Operation { 111 public: 112 explicit NavigateOperation(const std::string& hashed_key) 113 : hashed_key_(hashed_key) {} 114 virtual ~NavigateOperation() {} 115 virtual bool Execute(ExecutionContext* context) OVERRIDE { 116 const DictionaryValue* dict = NULL; 117 if (!context->current_node()->GetAsDictionary(&dict)) { 118 // Just ignore this node gracefully as this navigation is a dead end. 119 // If this NavigateOperation occurred after a NavigateAny operation, those 120 // may still be fulfillable, so we allow continuing the execution of the 121 // sentence on other nodes. 122 return true; 123 } 124 for (DictionaryValue::Iterator i(*dict); !i.IsAtEnd(); i.Advance()) { 125 if (context->GetHash(i.key()) != hashed_key_) 126 continue; 127 context->stack()->push_back(&i.value()); 128 bool continue_traversal = context->ContinueExecution(); 129 context->stack()->pop_back(); 130 if (!continue_traversal) 131 return false; 132 } 133 return true; 134 } 135 136 private: 137 std::string hashed_key_; 138 DISALLOW_COPY_AND_ASSIGN(NavigateOperation); 139 }; 140 141 class NavigateAnyOperation : public Operation { 142 public: 143 NavigateAnyOperation() {} 144 virtual ~NavigateAnyOperation() {} 145 virtual bool Execute(ExecutionContext* context) OVERRIDE { 146 const DictionaryValue* dict = NULL; 147 const ListValue* list = NULL; 148 if (context->current_node()->GetAsDictionary(&dict)) { 149 for (DictionaryValue::Iterator i(*dict); !i.IsAtEnd(); i.Advance()) { 150 context->stack()->push_back(&i.value()); 151 bool continue_traversal = context->ContinueExecution(); 152 context->stack()->pop_back(); 153 if (!continue_traversal) 154 return false; 155 } 156 } else if (context->current_node()->GetAsList(&list)) { 157 for (ListValue::const_iterator i = list->begin(); i != list->end(); ++i) { 158 context->stack()->push_back(*i); 159 bool continue_traversal = context->ContinueExecution(); 160 context->stack()->pop_back(); 161 if (!continue_traversal) 162 return false; 163 } 164 } else { 165 // Do nothing, just ignore this node. 166 } 167 return true; 168 } 169 170 private: 171 DISALLOW_COPY_AND_ASSIGN(NavigateAnyOperation); 172 }; 173 174 class NavigateBackOperation : public Operation { 175 public: 176 NavigateBackOperation() {} 177 virtual ~NavigateBackOperation() {} 178 virtual bool Execute(ExecutionContext* context) OVERRIDE { 179 const Value* current_node = context->current_node(); 180 context->stack()->pop_back(); 181 bool continue_traversal = context->ContinueExecution(); 182 context->stack()->push_back(current_node); 183 return continue_traversal; 184 } 185 186 private: 187 DISALLOW_COPY_AND_ASSIGN(NavigateBackOperation); 188 }; 189 190 class StoreValue : public Operation { 191 public: 192 StoreValue(const std::string& hashed_name, scoped_ptr<Value> value) 193 : hashed_name_(hashed_name), 194 value_(value.Pass()) { 195 DCHECK(IsStringUTF8(hashed_name)); 196 DCHECK(value_); 197 } 198 virtual ~StoreValue() {} 199 virtual bool Execute(ExecutionContext* context) OVERRIDE { 200 context->working_memory()->Set(hashed_name_, value_->DeepCopy()); 201 return context->ContinueExecution(); 202 } 203 204 private: 205 std::string hashed_name_; 206 scoped_ptr<Value> value_; 207 DISALLOW_COPY_AND_ASSIGN(StoreValue); 208 }; 209 210 class CompareStoredValue : public Operation { 211 public: 212 CompareStoredValue(const std::string& hashed_name, 213 scoped_ptr<Value> value, 214 scoped_ptr<Value> default_value) 215 : hashed_name_(hashed_name), 216 value_(value.Pass()), 217 default_value_(default_value.Pass()) { 218 DCHECK(IsStringUTF8(hashed_name)); 219 DCHECK(value_); 220 DCHECK(default_value_); 221 } 222 virtual ~CompareStoredValue() {} 223 virtual bool Execute(ExecutionContext* context) OVERRIDE { 224 const Value* actual_value = NULL; 225 if (!context->working_memory()->Get(hashed_name_, &actual_value)) 226 actual_value = default_value_.get(); 227 if (!value_->Equals(actual_value)) 228 return true; 229 return context->ContinueExecution(); 230 } 231 232 private: 233 std::string hashed_name_; 234 scoped_ptr<Value> value_; 235 scoped_ptr<Value> default_value_; 236 DISALLOW_COPY_AND_ASSIGN(CompareStoredValue); 237 }; 238 239 template<bool ExpectedTypeIsBooleanNotHashable> 240 class StoreNodeValue : public Operation { 241 public: 242 explicit StoreNodeValue(const std::string& hashed_name) 243 : hashed_name_(hashed_name) { 244 DCHECK(IsStringUTF8(hashed_name)); 245 } 246 virtual ~StoreNodeValue() {} 247 virtual bool Execute(ExecutionContext* context) OVERRIDE { 248 scoped_ptr<base::Value> value; 249 if (ExpectedTypeIsBooleanNotHashable) { 250 if (!context->current_node()->IsType(base::Value::TYPE_BOOLEAN)) 251 return true; 252 value.reset(context->current_node()->DeepCopy()); 253 } else { 254 std::string hash; 255 if (!context->GetValueHash(*context->current_node(), &hash)) 256 return true; 257 value.reset(new base::StringValue(hash)); 258 } 259 context->working_memory()->Set(hashed_name_, value.release()); 260 return context->ContinueExecution(); 261 } 262 263 private: 264 std::string hashed_name_; 265 DISALLOW_COPY_AND_ASSIGN(StoreNodeValue); 266 }; 267 268 // Stores the effective SLD (second-level domain) of the URL represented by the 269 // current node into working memory. 270 class StoreNodeEffectiveSLD : public Operation { 271 public: 272 explicit StoreNodeEffectiveSLD(const std::string& hashed_name) 273 : hashed_name_(hashed_name) { 274 DCHECK(IsStringUTF8(hashed_name)); 275 } 276 virtual ~StoreNodeEffectiveSLD() {} 277 virtual bool Execute(ExecutionContext* context) OVERRIDE { 278 std::string possibly_invalid_url; 279 std::string effective_sld; 280 if (!context->current_node()->GetAsString(&possibly_invalid_url) || 281 !GetEffectiveSLD(possibly_invalid_url, &effective_sld)) 282 return true; 283 context->working_memory()->Set( 284 hashed_name_, new StringValue(context->GetHash(effective_sld))); 285 return context->ContinueExecution(); 286 } 287 288 private: 289 // If |possibly_invalid_url| is a valid URL that has an effective second-level 290 // domain part, outputs that in |effective_sld| and returns true. 291 // Returns false otherwise. 292 static bool GetEffectiveSLD(const std::string& possibly_invalid_url, 293 std::string* effective_sld) { 294 namespace domains = net::registry_controlled_domains; 295 DCHECK(effective_sld); 296 GURL url(possibly_invalid_url); 297 if (!url.is_valid()) 298 return false; 299 std::string sld_and_registry = domains::GetDomainAndRegistry( 300 url.host(), domains::EXCLUDE_PRIVATE_REGISTRIES); 301 size_t registry_length = domains::GetRegistryLength( 302 url.host(), 303 domains::EXCLUDE_UNKNOWN_REGISTRIES, 304 domains::EXCLUDE_PRIVATE_REGISTRIES); 305 // Fail unless (1.) the URL has a host part; and (2.) that host part is a 306 // well-formed domain name that ends in, but is not in itself, as a whole, 307 // a recognized registry identifier that is acknowledged by ICANN. 308 if (registry_length == std::string::npos || registry_length == 0) 309 return false; 310 DCHECK_LT(registry_length, sld_and_registry.size()); 311 // Subtract one to cut off the dot separating the SLD and the registry. 312 effective_sld->assign( 313 sld_and_registry, 0, sld_and_registry.size() - registry_length - 1); 314 return true; 315 } 316 317 std::string hashed_name_; 318 DISALLOW_COPY_AND_ASSIGN(StoreNodeEffectiveSLD); 319 }; 320 321 class CompareNodeBool : public Operation { 322 public: 323 explicit CompareNodeBool(bool value) : value_(value) {} 324 virtual ~CompareNodeBool() {} 325 virtual bool Execute(ExecutionContext* context) OVERRIDE { 326 bool actual_value = false; 327 if (!context->current_node()->GetAsBoolean(&actual_value)) 328 return true; 329 if (actual_value != value_) 330 return true; 331 return context->ContinueExecution(); 332 } 333 334 private: 335 bool value_; 336 DISALLOW_COPY_AND_ASSIGN(CompareNodeBool); 337 }; 338 339 class CompareNodeHash : public Operation { 340 public: 341 explicit CompareNodeHash(const std::string& hashed_value) 342 : hashed_value_(hashed_value) {} 343 virtual ~CompareNodeHash() {} 344 virtual bool Execute(ExecutionContext* context) OVERRIDE { 345 std::string actual_hash; 346 if (!context->GetValueHash(*context->current_node(), &actual_hash) || 347 actual_hash != hashed_value_) 348 return true; 349 return context->ContinueExecution(); 350 } 351 352 private: 353 std::string hashed_value_; 354 DISALLOW_COPY_AND_ASSIGN(CompareNodeHash); 355 }; 356 357 class CompareNodeHashNot : public Operation { 358 public: 359 explicit CompareNodeHashNot(const std::string& hashed_value) 360 : hashed_value_(hashed_value) {} 361 virtual ~CompareNodeHashNot() {} 362 virtual bool Execute(ExecutionContext* context) OVERRIDE { 363 std::string actual_hash; 364 if (context->GetValueHash(*context->current_node(), &actual_hash) && 365 actual_hash == hashed_value_) 366 return true; 367 return context->ContinueExecution(); 368 } 369 370 private: 371 std::string hashed_value_; 372 DISALLOW_COPY_AND_ASSIGN(CompareNodeHashNot); 373 }; 374 375 template<bool ExpectedTypeIsBooleanNotHashable> 376 class CompareNodeToStored : public Operation { 377 public: 378 explicit CompareNodeToStored(const std::string& hashed_name) 379 : hashed_name_(hashed_name) {} 380 virtual ~CompareNodeToStored() {} 381 virtual bool Execute(ExecutionContext* context) OVERRIDE { 382 const Value* stored_value = NULL; 383 if (!context->working_memory()->Get(hashed_name_, &stored_value)) 384 return true; 385 if (ExpectedTypeIsBooleanNotHashable) { 386 if (!context->current_node()->IsType(base::Value::TYPE_BOOLEAN) || 387 !context->current_node()->Equals(stored_value)) 388 return true; 389 } else { 390 std::string actual_hash; 391 std::string stored_hash; 392 if (!context->GetValueHash(*context->current_node(), &actual_hash) || 393 !stored_value->GetAsString(&stored_hash) || 394 actual_hash != stored_hash) 395 return true; 396 } 397 return context->ContinueExecution(); 398 } 399 400 private: 401 std::string hashed_name_; 402 DISALLOW_COPY_AND_ASSIGN(CompareNodeToStored); 403 }; 404 405 class CompareNodeSubstring : public Operation { 406 public: 407 explicit CompareNodeSubstring(const std::string& hashed_pattern, 408 size_t pattern_length, 409 uint32 pattern_sum) 410 : hashed_pattern_(hashed_pattern), 411 pattern_length_(pattern_length), 412 pattern_sum_(pattern_sum) { 413 DCHECK(pattern_length_); 414 } 415 virtual ~CompareNodeSubstring() {} 416 virtual bool Execute(ExecutionContext* context) OVERRIDE { 417 std::string value_as_string; 418 if (!context->current_node()->GetAsString(&value_as_string) || 419 !pattern_length_ || value_as_string.size() < pattern_length_) 420 return true; 421 // Go over the string with a sliding window. Meanwhile, maintain the sum in 422 // an incremental fashion, and only calculate the SHA-256 hash when the sum 423 // checks out so as to improve performance. 424 std::string::const_iterator window_begin = value_as_string.begin(); 425 std::string::const_iterator window_end = window_begin + pattern_length_ - 1; 426 uint32 window_sum = 427 std::accumulate(window_begin, window_end, static_cast<uint32>(0u)); 428 while (window_end != value_as_string.end()) { 429 window_sum += *window_end++; 430 if (window_sum == pattern_sum_ && context->GetHash(std::string( 431 window_begin, window_end)) == hashed_pattern_) 432 return context->ContinueExecution(); 433 window_sum -= *window_begin++; 434 } 435 return true; 436 } 437 438 private: 439 std::string hashed_pattern_; 440 size_t pattern_length_; 441 uint32 pattern_sum_; 442 DISALLOW_COPY_AND_ASSIGN(CompareNodeSubstring); 443 }; 444 445 class StopExecutingSentenceOperation : public Operation { 446 public: 447 StopExecutingSentenceOperation() {} 448 virtual ~StopExecutingSentenceOperation() {} 449 virtual bool Execute(ExecutionContext* context) OVERRIDE { 450 return false; 451 } 452 453 private: 454 DISALLOW_COPY_AND_ASSIGN(StopExecutingSentenceOperation); 455 }; 456 457 class Parser { 458 public: 459 explicit Parser(const std::string& program) 460 : program_(program), 461 next_instruction_index_(0u) {} 462 ~Parser() {} 463 bool ParseNextSentence(ScopedVector<Operation>* output) { 464 ScopedVector<Operation> operators; 465 bool sentence_ended = false; 466 while (next_instruction_index_ < program_.size() && !sentence_ended) { 467 uint8 op_code = 0; 468 if (!ReadOpCode(&op_code)) 469 return false; 470 switch (static_cast<jtl_foundation::OpCodes>(op_code)) { 471 case jtl_foundation::NAVIGATE: { 472 std::string hashed_key; 473 if (!ReadHash(&hashed_key)) 474 return false; 475 operators.push_back(new NavigateOperation(hashed_key)); 476 break; 477 } 478 case jtl_foundation::NAVIGATE_ANY: 479 operators.push_back(new NavigateAnyOperation); 480 break; 481 case jtl_foundation::NAVIGATE_BACK: 482 operators.push_back(new NavigateBackOperation); 483 break; 484 case jtl_foundation::STORE_BOOL: { 485 std::string hashed_name; 486 if (!ReadHash(&hashed_name) || !IsStringUTF8(hashed_name)) 487 return false; 488 bool value = false; 489 if (!ReadBool(&value)) 490 return false; 491 operators.push_back(new StoreValue( 492 hashed_name, 493 scoped_ptr<Value>(new base::FundamentalValue(value)))); 494 break; 495 } 496 case jtl_foundation::COMPARE_STORED_BOOL: { 497 std::string hashed_name; 498 if (!ReadHash(&hashed_name) || !IsStringUTF8(hashed_name)) 499 return false; 500 bool value = false; 501 if (!ReadBool(&value)) 502 return false; 503 bool default_value = false; 504 if (!ReadBool(&default_value)) 505 return false; 506 operators.push_back(new CompareStoredValue( 507 hashed_name, 508 scoped_ptr<Value>(new base::FundamentalValue(value)), 509 scoped_ptr<Value>(new base::FundamentalValue(default_value)))); 510 break; 511 } 512 case jtl_foundation::STORE_HASH: { 513 std::string hashed_name; 514 if (!ReadHash(&hashed_name) || !IsStringUTF8(hashed_name)) 515 return false; 516 std::string hashed_value; 517 if (!ReadHash(&hashed_value)) 518 return false; 519 operators.push_back(new StoreValue( 520 hashed_name, 521 scoped_ptr<Value>(new base::StringValue(hashed_value)))); 522 break; 523 } 524 case jtl_foundation::COMPARE_STORED_HASH: { 525 std::string hashed_name; 526 if (!ReadHash(&hashed_name) || !IsStringUTF8(hashed_name)) 527 return false; 528 std::string hashed_value; 529 if (!ReadHash(&hashed_value)) 530 return false; 531 std::string hashed_default_value; 532 if (!ReadHash(&hashed_default_value)) 533 return false; 534 operators.push_back(new CompareStoredValue( 535 hashed_name, 536 scoped_ptr<Value>(new base::StringValue(hashed_value)), 537 scoped_ptr<Value>(new base::StringValue(hashed_default_value)))); 538 break; 539 } 540 case jtl_foundation::STORE_NODE_BOOL: { 541 std::string hashed_name; 542 if (!ReadHash(&hashed_name) || !IsStringUTF8(hashed_name)) 543 return false; 544 operators.push_back(new StoreNodeValue<true>(hashed_name)); 545 break; 546 } 547 case jtl_foundation::STORE_NODE_HASH: { 548 std::string hashed_name; 549 if (!ReadHash(&hashed_name) || !IsStringUTF8(hashed_name)) 550 return false; 551 operators.push_back(new StoreNodeValue<false>(hashed_name)); 552 break; 553 } 554 case jtl_foundation::STORE_NODE_EFFECTIVE_SLD_HASH: { 555 std::string hashed_name; 556 if (!ReadHash(&hashed_name) || !IsStringUTF8(hashed_name)) 557 return false; 558 operators.push_back(new StoreNodeEffectiveSLD(hashed_name)); 559 break; 560 } 561 case jtl_foundation::COMPARE_NODE_BOOL: { 562 bool value = false; 563 if (!ReadBool(&value)) 564 return false; 565 operators.push_back(new CompareNodeBool(value)); 566 break; 567 } 568 case jtl_foundation::COMPARE_NODE_HASH: { 569 std::string hashed_value; 570 if (!ReadHash(&hashed_value)) 571 return false; 572 operators.push_back(new CompareNodeHash(hashed_value)); 573 break; 574 } 575 case jtl_foundation::COMPARE_NODE_HASH_NOT: { 576 std::string hashed_value; 577 if (!ReadHash(&hashed_value)) 578 return false; 579 operators.push_back(new CompareNodeHashNot(hashed_value)); 580 break; 581 } 582 case jtl_foundation::COMPARE_NODE_TO_STORED_BOOL: { 583 std::string hashed_name; 584 if (!ReadHash(&hashed_name) || !IsStringUTF8(hashed_name)) 585 return false; 586 operators.push_back(new CompareNodeToStored<true>(hashed_name)); 587 break; 588 } 589 case jtl_foundation::COMPARE_NODE_TO_STORED_HASH: { 590 std::string hashed_name; 591 if (!ReadHash(&hashed_name) || !IsStringUTF8(hashed_name)) 592 return false; 593 operators.push_back(new CompareNodeToStored<false>(hashed_name)); 594 break; 595 } 596 case jtl_foundation::COMPARE_NODE_SUBSTRING: { 597 std::string hashed_pattern; 598 uint32 pattern_length = 0, pattern_sum = 0; 599 if (!ReadHash(&hashed_pattern)) 600 return false; 601 if (!ReadUint32(&pattern_length) || pattern_length == 0) 602 return false; 603 if (!ReadUint32(&pattern_sum)) 604 return false; 605 operators.push_back(new CompareNodeSubstring( 606 hashed_pattern, pattern_length, pattern_sum)); 607 break; 608 } 609 case jtl_foundation::STOP_EXECUTING_SENTENCE: 610 operators.push_back(new StopExecutingSentenceOperation); 611 break; 612 case jtl_foundation::END_OF_SENTENCE: 613 sentence_ended = true; 614 break; 615 default: 616 return false; 617 } 618 } 619 output->swap(operators); 620 return true; 621 } 622 623 bool HasNextSentence() const { 624 return next_instruction_index_ < program_.size(); 625 } 626 627 private: 628 // Reads an uint8 and returns whether this operation was successful. 629 bool ReadUint8(uint8* out) { 630 DCHECK(out); 631 if (next_instruction_index_ + 1u > program_.size()) 632 return false; 633 *out = static_cast<uint8>(program_[next_instruction_index_]); 634 ++next_instruction_index_; 635 return true; 636 } 637 638 // Reads an uint32 and returns whether this operation was successful. 639 bool ReadUint32(uint32* out) { 640 DCHECK(out); 641 if (next_instruction_index_ + 4u > program_.size()) 642 return false; 643 *out = 0u; 644 for (int i = 0; i < 4; ++i) { 645 *out >>= 8; 646 *out |= static_cast<uint8>(program_[next_instruction_index_]) << 24; 647 ++next_instruction_index_; 648 } 649 return true; 650 } 651 652 // Reads an operator code and returns whether this operation was successful. 653 bool ReadOpCode(uint8* out) { return ReadUint8(out); } 654 655 bool ReadHash(std::string* out) { 656 DCHECK(out); 657 if (next_instruction_index_ + jtl_foundation::kHashSizeInBytes > 658 program_.size()) 659 return false; 660 *out = program_.substr(next_instruction_index_, 661 jtl_foundation::kHashSizeInBytes); 662 next_instruction_index_ += jtl_foundation::kHashSizeInBytes; 663 DCHECK(jtl_foundation::Hasher::IsHash(*out)); 664 return true; 665 } 666 667 bool ReadBool(bool* out) { 668 DCHECK(out); 669 uint8 value = 0; 670 if (!ReadUint8(&value)) 671 return false; 672 if (value == 0) 673 *out = false; 674 else if (value == 1) 675 *out = true; 676 else 677 return false; 678 return true; 679 } 680 681 std::string program_; 682 size_t next_instruction_index_; 683 DISALLOW_COPY_AND_ASSIGN(Parser); 684 }; 685 686 } // namespace 687 688 JtlInterpreter::JtlInterpreter( 689 const std::string& hasher_seed, 690 const std::string& program, 691 const DictionaryValue* input) 692 : hasher_seed_(hasher_seed), 693 program_(program), 694 input_(input), 695 working_memory_(new DictionaryValue), 696 result_(OK) { 697 DCHECK(input->IsType(Value::TYPE_DICTIONARY)); 698 } 699 700 JtlInterpreter::~JtlInterpreter() {} 701 702 void JtlInterpreter::Execute() { 703 jtl_foundation::Hasher hasher(hasher_seed_); 704 Parser parser(program_); 705 while (parser.HasNextSentence()) { 706 ScopedVector<Operation> sentence; 707 if (!parser.ParseNextSentence(&sentence)) { 708 result_ = PARSE_ERROR; 709 return; 710 } 711 ExecutionContext context( 712 &hasher, sentence.get(), input_, working_memory_.get()); 713 context.ContinueExecution(); 714 if (context.error()) { 715 result_ = RUNTIME_ERROR; 716 return; 717 } 718 } 719 } 720 721 bool JtlInterpreter::GetOutputBoolean(const std::string& unhashed_key, 722 bool* output) const { 723 std::string hashed_key = 724 jtl_foundation::Hasher(hasher_seed_).GetHash(unhashed_key); 725 return working_memory_->GetBoolean(hashed_key, output); 726 } 727 728 bool JtlInterpreter::GetOutputString(const std::string& unhashed_key, 729 std::string* output) const { 730 std::string hashed_key = 731 jtl_foundation::Hasher(hasher_seed_).GetHash(unhashed_key); 732 return working_memory_->GetString(hashed_key, output); 733 } 734