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