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