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 #ifdef BAZEL_BUILD
27 #include "examples/protos/route_guide.grpc.pb.h"
28 #else
29 #include "route_guide.grpc.pb.h"
30 #endif
31
32 namespace routeguide {
33
GetDbFileContent(int argc,char ** argv)34 std::string GetDbFileContent(int argc, char** argv) {
35 std::string db_path;
36 std::string arg_str("--db_path");
37 if (argc > 1) {
38 std::string argv_1 = argv[1];
39 size_t start_position = argv_1.find(arg_str);
40 if (start_position != std::string::npos) {
41 start_position += arg_str.size();
42 if (argv_1[start_position] == ' ' || argv_1[start_position] == '=') {
43 db_path = argv_1.substr(start_position + 1);
44 }
45 }
46 } else {
47 #ifdef BAZEL_BUILD
48 db_path = "cpp/route_guide/route_guide_db.json";
49 #else
50 db_path = "route_guide_db.json";
51 #endif
52 }
53 std::ifstream db_file(db_path);
54 if (!db_file.is_open()) {
55 std::cout << "Failed to open " << db_path << std::endl;
56 return "";
57 }
58 std::stringstream db;
59 db << db_file.rdbuf();
60 return db.str();
61 }
62
63 // A simple parser for the json db file. It requires the db file to have the
64 // exact form of [{"location": { "latitude": 123, "longitude": 456}, "name":
65 // "the name can be empty" }, { ... } ... The spaces will be stripped.
66 class Parser {
67 public:
Parser(const std::string & db)68 explicit Parser(const std::string& db) : db_(db) {
69 // Remove all spaces.
70 db_.erase(std::remove_if(db_.begin(), db_.end(), isspace), db_.end());
71 if (!Match("[")) {
72 SetFailedAndReturnFalse();
73 }
74 }
75
Finished()76 bool Finished() { return current_ >= db_.size(); }
77
TryParseOne(Feature * feature)78 bool TryParseOne(Feature* feature) {
79 if (failed_ || Finished() || !Match("{")) {
80 return SetFailedAndReturnFalse();
81 }
82 if (!Match(location_) || !Match("{") || !Match(latitude_)) {
83 return SetFailedAndReturnFalse();
84 }
85 long temp = 0;
86 ReadLong(&temp);
87 feature->mutable_location()->set_latitude(temp);
88 if (!Match(",") || !Match(longitude_)) {
89 return SetFailedAndReturnFalse();
90 }
91 ReadLong(&temp);
92 feature->mutable_location()->set_longitude(temp);
93 if (!Match("},") || !Match(name_) || !Match("\"")) {
94 return SetFailedAndReturnFalse();
95 }
96 size_t name_start = current_;
97 while (current_ != db_.size() && db_[current_++] != '"') {
98 }
99 if (current_ == db_.size()) {
100 return SetFailedAndReturnFalse();
101 }
102 feature->set_name(db_.substr(name_start, current_ - name_start - 1));
103 if (!Match("},")) {
104 if (db_[current_ - 1] == ']' && current_ == db_.size()) {
105 return true;
106 }
107 return SetFailedAndReturnFalse();
108 }
109 return true;
110 }
111
112 private:
SetFailedAndReturnFalse()113 bool SetFailedAndReturnFalse() {
114 failed_ = true;
115 return false;
116 }
117
Match(const std::string & prefix)118 bool Match(const std::string& prefix) {
119 bool eq = db_.substr(current_, prefix.size()) == prefix;
120 current_ += prefix.size();
121 return eq;
122 }
123
ReadLong(long * l)124 void ReadLong(long* l) {
125 size_t start = current_;
126 while (current_ != db_.size() && db_[current_] != ',' &&
127 db_[current_] != '}') {
128 current_++;
129 }
130 // It will throw an exception if fails.
131 *l = std::stol(db_.substr(start, current_ - start));
132 }
133
134 bool failed_ = false;
135 std::string db_;
136 size_t current_ = 0;
137 const std::string location_ = "\"location\":";
138 const std::string latitude_ = "\"latitude\":";
139 const std::string longitude_ = "\"longitude\":";
140 const std::string name_ = "\"name\":";
141 };
142
ParseDb(const std::string & db,std::vector<Feature> * feature_list)143 void ParseDb(const std::string& db, std::vector<Feature>* feature_list) {
144 feature_list->clear();
145 std::string db_content(db);
146 db_content.erase(
147 std::remove_if(db_content.begin(), db_content.end(), isspace),
148 db_content.end());
149
150 Parser parser(db_content);
151 Feature feature;
152 while (!parser.Finished()) {
153 feature_list->push_back(Feature());
154 if (!parser.TryParseOne(&feature_list->back())) {
155 std::cout << "Error parsing the db file";
156 feature_list->clear();
157 break;
158 }
159 }
160 std::cout << "DB parsed, loaded " << feature_list->size() << " features."
161 << std::endl;
162 }
163
164 } // namespace routeguide
165