add more fiddle hash checks

Convert some of bookmaker to use real json instead
of rolling its own. Also check to see if all
hashes are read.

TBR=jcgregario@google.com

Docs-Preview: https://skia.org/?cl=142166
Bug: skia:8151
Change-Id: Ib35ecd69648faec3522903e0b552d37b04b73f8b
Reviewed-on: https://skia-review.googlesource.com/142166
Commit-Queue: Cary Clark <caryclark@skia.org>
Auto-Submit: Cary Clark <caryclark@skia.org>
Reviewed-by: Cary Clark <caryclark@skia.org>
diff --git a/tools/bookmaker/bookmaker.cpp b/tools/bookmaker/bookmaker.cpp
index ffd3012..1b8e76e 100644
--- a/tools/bookmaker/bookmaker.cpp
+++ b/tools/bookmaker/bookmaker.cpp
@@ -703,6 +703,55 @@
     return nullptr;
 }
 
+static bool check_example_hashes(Definition* def) {
+    if (MarkType::kExample == def->fMarkType) {
+        if (def->fHash.length()) {
+            return true;
+        }
+        for (auto child : def->fChildren) {
+            if (MarkType::kPlatform == child->fMarkType) {
+                if (string::npos != string(child->fContentStart, child->length()).find("!fiddle")) {
+                    return true;
+                }
+            }
+        }
+        return def->reportError<bool>("missing hash");
+    }
+    for (auto& child : def->fChildren) {
+        if (!check_example_hashes(child)) {
+            return false;
+        }
+    }
+    return true;
+}
+
+bool BmhParser::checkExampleHashes() const {
+    for (const auto& topic : fTopicMap) {
+        if (!topic.second->fParent && !check_example_hashes(topic.second)) {
+            return false;
+        }
+    }
+    return true;
+}
+
+static void reset_example_hashes(Definition* def) {
+    if (MarkType::kExample == def->fMarkType) {
+        def->fHash.clear();
+        return;
+    }
+    for (auto& child : def->fChildren) {
+        reset_example_hashes(child);
+    }
+}
+
+void BmhParser::resetExampleHashes() {
+    for (const auto& topic : fTopicMap) {
+        if (!topic.second->fParent) {
+            reset_example_hashes(topic.second);
+        }
+    }
+}
+
 static void find_examples(const Definition& def, vector<string>* exampleNames) {
     if (MarkType::kExample == def.fMarkType) {
         exampleNames->push_back(def.fFiddle);
@@ -2640,7 +2689,7 @@
     }
     if (!done && !FLAGS_fiddle.isEmpty() && FLAGS_examples.isEmpty()) {
         FiddleParser fparser(&bmhParser);
-        if (!fparser.parseFile(FLAGS_fiddle[0], ".txt", ParserCommon::OneFile::kNo)) {
+        if (!fparser.parseFromFile(FLAGS_fiddle[0])) {
             return -1;
         }
     }