1 /*
2 *
3 * Copyright 2015 gRPC authors.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 */
18
19 #include <algorithm>
20 #include <cctype>
21 #include <fstream>
22 #include <iostream>
23 #include <sstream>
24 #include <string>
25 #include <vector>
26
27 #include "absl/flags/flag.h"
28 #include "absl/log/log.h"
29
30 #ifdef BAZEL_BUILD
31 #include "examples/protos/route_guide.grpc.pb.h"
32 #else
33 #include "route_guide.grpc.pb.h"
34 #endif
35
36 #ifdef BAZEL_BUILD
37 ABSL_FLAG(std::string, db_path, "examples/cpp/route_guide/route_guide_db.json",
38 "Path to db file");
39 #else
40 ABSL_FLAG(std::string, db_path, "route_guide_db.json", "Path to db file");
41 #endif
42
43 namespace routeguide {
44
GetDbFileContent(int argc,char ** argv)45 std::string GetDbFileContent(int argc, char** argv) {
46 std::string db_path = absl::GetFlag(FLAGS_db_path);
47 std::ifstream db_file(db_path);
48 if (!db_file.is_open()) {
49 LOG(ERROR) << "Failed to open " << db_path;
50 abort();
51 }
52 std::stringstream db;
53 db << db_file.rdbuf();
54 return db.str();
55 }
56
57 // A simple parser for the json db file. It requires the db file to have the
58 // exact form of [{"location": { "latitude": 123, "longitude": 456}, "name":
59 // "the name can be empty" }, { ... } ... The spaces will be stripped.
60 class Parser {
61 public:
Parser(const std::string & db)62 explicit Parser(const std::string& db) : db_(db) {
63 // Remove all spaces.
64 db_.erase(std::remove_if(db_.begin(), db_.end(), isspace), db_.end());
65 if (!Match("[")) {
66 SetFailedAndReturnFalse();
67 }
68 }
69
Finished()70 bool Finished() { return current_ >= db_.size(); }
71
TryParseOne(Feature * feature)72 bool TryParseOne(Feature* feature) {
73 if (failed_ || Finished() || !Match("{")) {
74 return SetFailedAndReturnFalse();
75 }
76 if (!Match(location_) || !Match("{") || !Match(latitude_)) {
77 return SetFailedAndReturnFalse();
78 }
79 long temp = 0;
80 ReadLong(&temp);
81 feature->mutable_location()->set_latitude(temp);
82 if (!Match(",") || !Match(longitude_)) {
83 return SetFailedAndReturnFalse();
84 }
85 ReadLong(&temp);
86 feature->mutable_location()->set_longitude(temp);
87 if (!Match("},") || !Match(name_) || !Match("\"")) {
88 return SetFailedAndReturnFalse();
89 }
90 size_t name_start = current_;
91 while (current_ != db_.size() && db_[current_++] != '"') {
92 }
93 if (current_ == db_.size()) {
94 return SetFailedAndReturnFalse();
95 }
96 feature->set_name(db_.substr(name_start, current_ - name_start - 1));
97 if (!Match("},")) {
98 if (db_[current_ - 1] == ']' && current_ == db_.size()) {
99 return true;
100 }
101 return SetFailedAndReturnFalse();
102 }
103 return true;
104 }
105
106 private:
SetFailedAndReturnFalse()107 bool SetFailedAndReturnFalse() {
108 failed_ = true;
109 return false;
110 }
111
Match(const std::string & prefix)112 bool Match(const std::string& prefix) {
113 bool eq = db_.substr(current_, prefix.size()) == prefix;
114 current_ += prefix.size();
115 return eq;
116 }
117
ReadLong(long * l)118 void ReadLong(long* l) {
119 size_t start = current_;
120 while (current_ != db_.size() && db_[current_] != ',' &&
121 db_[current_] != '}') {
122 current_++;
123 }
124 // It will throw an exception if fails.
125 *l = std::stol(db_.substr(start, current_ - start));
126 }
127
128 bool failed_ = false;
129 std::string db_;
130 size_t current_ = 0;
131 const std::string location_ = "\"location\":";
132 const std::string latitude_ = "\"latitude\":";
133 const std::string longitude_ = "\"longitude\":";
134 const std::string name_ = "\"name\":";
135 };
136
ParseDb(const std::string & db,std::vector<Feature> * feature_list)137 void ParseDb(const std::string& db, std::vector<Feature>* feature_list) {
138 feature_list->clear();
139 std::string db_content(db);
140 db_content.erase(
141 std::remove_if(db_content.begin(), db_content.end(), isspace),
142 db_content.end());
143
144 Parser parser(db_content);
145 Feature feature;
146 while (!parser.Finished()) {
147 feature_list->push_back(Feature());
148 if (!parser.TryParseOne(&feature_list->back())) {
149 LOG(ERROR) << "Error parsing the db file";
150 feature_list->clear();
151 break;
152 }
153 }
154 LOG(INFO) << "DB parsed, loaded " << feature_list->size() << " features.";
155 }
156
157 } // namespace routeguide
158