1b44f7d46b647e24d8ea4fdf45742bbcbbfb03113Yi Jin/* 2b44f7d46b647e24d8ea4fdf45742bbcbbfb03113Yi Jin * Copyright (C) 2017 The Android Open Source Project 3b44f7d46b647e24d8ea4fdf45742bbcbbfb03113Yi Jin * 4b44f7d46b647e24d8ea4fdf45742bbcbbfb03113Yi Jin * Licensed under the Apache License, Version 2.0 (the "License"); 5b44f7d46b647e24d8ea4fdf45742bbcbbfb03113Yi Jin * you may not use this file except in compliance with the License. 6b44f7d46b647e24d8ea4fdf45742bbcbbfb03113Yi Jin * You may obtain a copy of the License at 7b44f7d46b647e24d8ea4fdf45742bbcbbfb03113Yi Jin * 8b44f7d46b647e24d8ea4fdf45742bbcbbfb03113Yi Jin * http://www.apache.org/licenses/LICENSE-2.0 9b44f7d46b647e24d8ea4fdf45742bbcbbfb03113Yi Jin * 10b44f7d46b647e24d8ea4fdf45742bbcbbfb03113Yi Jin * Unless required by applicable law or agreed to in writing, software 11b44f7d46b647e24d8ea4fdf45742bbcbbfb03113Yi Jin * distributed under the License is distributed on an "AS IS" BASIS, 12b44f7d46b647e24d8ea4fdf45742bbcbbfb03113Yi Jin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13b44f7d46b647e24d8ea4fdf45742bbcbbfb03113Yi Jin * See the License for the specific language governing permissions and 14b44f7d46b647e24d8ea4fdf45742bbcbbfb03113Yi Jin * limitations under the License. 15b44f7d46b647e24d8ea4fdf45742bbcbbfb03113Yi Jin */ 16b44f7d46b647e24d8ea4fdf45742bbcbbfb03113Yi Jin 17b44f7d46b647e24d8ea4fdf45742bbcbbfb03113Yi Jin#define LOG_TAG "incident_helper" 18b44f7d46b647e24d8ea4fdf45742bbcbbfb03113Yi Jin 19b44f7d46b647e24d8ea4fdf45742bbcbbfb03113Yi Jin#include "ih_util.h" 20b44f7d46b647e24d8ea4fdf45742bbcbbfb03113Yi Jin 21810b14f5c24a9517dd6ded3ce5a38cfc8e29b3edYi Jin#include <algorithm> 22b44f7d46b647e24d8ea4fdf45742bbcbbfb03113Yi Jin#include <sstream> 23b44f7d46b647e24d8ea4fdf45742bbcbbfb03113Yi Jin#include <unistd.h> 24b44f7d46b647e24d8ea4fdf45742bbcbbfb03113Yi Jin 25e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jinbool isValidChar(char c) { 26e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin uint8_t v = (uint8_t)c; 27e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin return (v >= (uint8_t)'a' && v <= (uint8_t)'z') 28e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin || (v >= (uint8_t)'A' && v <= (uint8_t)'Z') 29e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin || (v >= (uint8_t)'0' && v <= (uint8_t)'9') 30e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin || (v == (uint8_t)'_'); 31e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin} 324ef28b73533765867aa4d61ba6e0d27a7632ff02Yi Jin 330dfa752e67116940f04a988ca4a264f7140dd81fYi Jinstd::string trim(const std::string& s, const std::string& charset) { 340dfa752e67116940f04a988ca4a264f7140dd81fYi Jin const auto head = s.find_first_not_of(charset); 35b44f7d46b647e24d8ea4fdf45742bbcbbfb03113Yi Jin if (head == std::string::npos) return ""; 36b44f7d46b647e24d8ea4fdf45742bbcbbfb03113Yi Jin 370dfa752e67116940f04a988ca4a264f7140dd81fYi Jin const auto tail = s.find_last_not_of(charset); 38b44f7d46b647e24d8ea4fdf45742bbcbbfb03113Yi Jin return s.substr(head, tail - head + 1); 39b44f7d46b647e24d8ea4fdf45742bbcbbfb03113Yi Jin} 40b44f7d46b647e24d8ea4fdf45742bbcbbfb03113Yi Jin 410dfa752e67116940f04a988ca4a264f7140dd81fYi Jinstatic inline std::string toLowerStr(const std::string& s) { 420dfa752e67116940f04a988ca4a264f7140dd81fYi Jin std::string res(s); 430dfa752e67116940f04a988ca4a264f7140dd81fYi Jin std::transform(res.begin(), res.end(), res.begin(), ::tolower); 440dfa752e67116940f04a988ca4a264f7140dd81fYi Jin return res; 450dfa752e67116940f04a988ca4a264f7140dd81fYi Jin} 460dfa752e67116940f04a988ca4a264f7140dd81fYi Jin 470dfa752e67116940f04a988ca4a264f7140dd81fYi Jinstatic inline std::string trimDefault(const std::string& s) { 48e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin return trim(s, DEFAULT_WHITESPACE); 49e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin} 50e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin 510dfa752e67116940f04a988ca4a264f7140dd81fYi Jinstatic inline std::string trimHeader(const std::string& s) { 520dfa752e67116940f04a988ca4a264f7140dd81fYi Jin return toLowerStr(trimDefault(s)); 534ef28b73533765867aa4d61ba6e0d27a7632ff02Yi Jin} 544ef28b73533765867aa4d61ba6e0d27a7632ff02Yi Jin 55f5cc5759d55f803cd230c7a595e89e634c3c36eeKweku Adamsstatic inline bool isNumber(const std::string& s) { 56f5cc5759d55f803cd230c7a595e89e634c3c36eeKweku Adams std::string::const_iterator it = s.begin(); 57f5cc5759d55f803cd230c7a595e89e634c3c36eeKweku Adams while (it != s.end() && std::isdigit(*it)) ++it; 58f5cc5759d55f803cd230c7a595e89e634c3c36eeKweku Adams return !s.empty() && it == s.end(); 59f5cc5759d55f803cd230c7a595e89e634c3c36eeKweku Adams} 60f5cc5759d55f803cd230c7a595e89e634c3c36eeKweku Adams 61b44f7d46b647e24d8ea4fdf45742bbcbbfb03113Yi Jin// This is similiar to Split in android-base/file.h, but it won't add empty string 624ef28b73533765867aa4d61ba6e0d27a7632ff02Yi Jinstatic void split(const std::string& line, std::vector<std::string>& words, 634ef28b73533765867aa4d61ba6e0d27a7632ff02Yi Jin const trans_func& func, const std::string& delimiters) { 64b44f7d46b647e24d8ea4fdf45742bbcbbfb03113Yi Jin words.clear(); // clear the buffer before split 65b44f7d46b647e24d8ea4fdf45742bbcbbfb03113Yi Jin 66b44f7d46b647e24d8ea4fdf45742bbcbbfb03113Yi Jin size_t base = 0; 67b44f7d46b647e24d8ea4fdf45742bbcbbfb03113Yi Jin size_t found; 68b44f7d46b647e24d8ea4fdf45742bbcbbfb03113Yi Jin while (true) { 69b44f7d46b647e24d8ea4fdf45742bbcbbfb03113Yi Jin found = line.find_first_of(delimiters, base); 70b44f7d46b647e24d8ea4fdf45742bbcbbfb03113Yi Jin if (found != base) { 714ef28b73533765867aa4d61ba6e0d27a7632ff02Yi Jin std::string word = (*func) (line.substr(base, found - base)); 72b44f7d46b647e24d8ea4fdf45742bbcbbfb03113Yi Jin if (!word.empty()) { 73b44f7d46b647e24d8ea4fdf45742bbcbbfb03113Yi Jin words.push_back(word); 74b44f7d46b647e24d8ea4fdf45742bbcbbfb03113Yi Jin } 75b44f7d46b647e24d8ea4fdf45742bbcbbfb03113Yi Jin } 76b44f7d46b647e24d8ea4fdf45742bbcbbfb03113Yi Jin if (found == line.npos) break; 77b44f7d46b647e24d8ea4fdf45742bbcbbfb03113Yi Jin base = found + 1; 78b44f7d46b647e24d8ea4fdf45742bbcbbfb03113Yi Jin } 79b44f7d46b647e24d8ea4fdf45742bbcbbfb03113Yi Jin} 80b44f7d46b647e24d8ea4fdf45742bbcbbfb03113Yi Jin 814ef28b73533765867aa4d61ba6e0d27a7632ff02Yi Jinheader_t parseHeader(const std::string& line, const std::string& delimiters) { 824ef28b73533765867aa4d61ba6e0d27a7632ff02Yi Jin header_t header; 834ef28b73533765867aa4d61ba6e0d27a7632ff02Yi Jin trans_func f = &trimHeader; 844ef28b73533765867aa4d61ba6e0d27a7632ff02Yi Jin split(line, header, f, delimiters); 854ef28b73533765867aa4d61ba6e0d27a7632ff02Yi Jin return header; 864ef28b73533765867aa4d61ba6e0d27a7632ff02Yi Jin} 874ef28b73533765867aa4d61ba6e0d27a7632ff02Yi Jin 884ef28b73533765867aa4d61ba6e0d27a7632ff02Yi Jinrecord_t parseRecord(const std::string& line, const std::string& delimiters) { 894ef28b73533765867aa4d61ba6e0d27a7632ff02Yi Jin record_t record; 90e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin trans_func f = &trimDefault; 914ef28b73533765867aa4d61ba6e0d27a7632ff02Yi Jin split(line, record, f, delimiters); 924ef28b73533765867aa4d61ba6e0d27a7632ff02Yi Jin return record; 93b44f7d46b647e24d8ea4fdf45742bbcbbfb03113Yi Jin} 94b44f7d46b647e24d8ea4fdf45742bbcbbfb03113Yi Jin 95f5cc5759d55f803cd230c7a595e89e634c3c36eeKweku Adamsbool getColumnIndices(std::vector<int>& indices, const char** headerNames, const std::string& line) { 96f5cc5759d55f803cd230c7a595e89e634c3c36eeKweku Adams indices.clear(); 97f5cc5759d55f803cd230c7a595e89e634c3c36eeKweku Adams 98f5cc5759d55f803cd230c7a595e89e634c3c36eeKweku Adams size_t lastIndex = 0; 99f5cc5759d55f803cd230c7a595e89e634c3c36eeKweku Adams int i = 0; 100f5cc5759d55f803cd230c7a595e89e634c3c36eeKweku Adams while (headerNames[i] != NULL) { 1016cacbcbf436be744a34f7ea0d4f838ff97757446Yi Jin std::string s = headerNames[i]; 102f5cc5759d55f803cd230c7a595e89e634c3c36eeKweku Adams lastIndex = line.find(s, lastIndex); 1036cacbcbf436be744a34f7ea0d4f838ff97757446Yi Jin if (lastIndex == std::string::npos) { 104f5cc5759d55f803cd230c7a595e89e634c3c36eeKweku Adams fprintf(stderr, "Bad Task Header: %s\n", line.c_str()); 105f5cc5759d55f803cd230c7a595e89e634c3c36eeKweku Adams return false; 106f5cc5759d55f803cd230c7a595e89e634c3c36eeKweku Adams } 107f5cc5759d55f803cd230c7a595e89e634c3c36eeKweku Adams lastIndex += s.length(); 108f5cc5759d55f803cd230c7a595e89e634c3c36eeKweku Adams indices.push_back(lastIndex); 109f5cc5759d55f803cd230c7a595e89e634c3c36eeKweku Adams i++; 110f5cc5759d55f803cd230c7a595e89e634c3c36eeKweku Adams } 111f5cc5759d55f803cd230c7a595e89e634c3c36eeKweku Adams 112f5cc5759d55f803cd230c7a595e89e634c3c36eeKweku Adams return true; 113f5cc5759d55f803cd230c7a595e89e634c3c36eeKweku Adams} 114f5cc5759d55f803cd230c7a595e89e634c3c36eeKweku Adams 115e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jinrecord_t parseRecordByColumns(const std::string& line, const std::vector<int>& indices, const std::string& delimiters) { 116e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin record_t record; 117e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin int lastIndex = 0; 118f5cc5759d55f803cd230c7a595e89e634c3c36eeKweku Adams int lastBeginning = 0; 119e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin int lineSize = (int)line.size(); 120e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin for (std::vector<int>::const_iterator it = indices.begin(); it != indices.end(); ++it) { 121e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin int idx = *it; 122f5cc5759d55f803cd230c7a595e89e634c3c36eeKweku Adams if (idx <= lastIndex) { 123f5cc5759d55f803cd230c7a595e89e634c3c36eeKweku Adams // We saved up until lastIndex last time, so we should start at 124f5cc5759d55f803cd230c7a595e89e634c3c36eeKweku Adams // lastIndex + 1 this time. 125f5cc5759d55f803cd230c7a595e89e634c3c36eeKweku Adams idx = lastIndex + 1; 126f5cc5759d55f803cd230c7a595e89e634c3c36eeKweku Adams } 127f5cc5759d55f803cd230c7a595e89e634c3c36eeKweku Adams if (idx > lineSize) { 128f5cc5759d55f803cd230c7a595e89e634c3c36eeKweku Adams if (lastIndex < idx && lastIndex < lineSize) { 129f5cc5759d55f803cd230c7a595e89e634c3c36eeKweku Adams // There's a little bit more for us to save, which we'll do 130f5cc5759d55f803cd230c7a595e89e634c3c36eeKweku Adams // outside of the loop. 131f5cc5759d55f803cd230c7a595e89e634c3c36eeKweku Adams break; 132f5cc5759d55f803cd230c7a595e89e634c3c36eeKweku Adams } 133f5cc5759d55f803cd230c7a595e89e634c3c36eeKweku Adams // If we're past the end of the line AND we've already saved everything up to the end. 134f5cc5759d55f803cd230c7a595e89e634c3c36eeKweku Adams fprintf(stderr, "index wrong: lastIndex: %d, idx: %d, lineSize: %d\n", lastIndex, idx, lineSize); 135f5cc5759d55f803cd230c7a595e89e634c3c36eeKweku Adams record.clear(); // The indices are wrong, return empty. 136e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin return record; 137e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin } 138e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin while (idx < lineSize && delimiters.find(line[idx++]) == std::string::npos); 139e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin record.push_back(trimDefault(line.substr(lastIndex, idx - lastIndex))); 140f5cc5759d55f803cd230c7a595e89e634c3c36eeKweku Adams lastBeginning = lastIndex; 141e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin lastIndex = idx; 142e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin } 143f5cc5759d55f803cd230c7a595e89e634c3c36eeKweku Adams if (lineSize - lastIndex > 0) { 144f5cc5759d55f803cd230c7a595e89e634c3c36eeKweku Adams int beginning = lastIndex; 145f5cc5759d55f803cd230c7a595e89e634c3c36eeKweku Adams if (record.size() == indices.size()) { 146f5cc5759d55f803cd230c7a595e89e634c3c36eeKweku Adams // We've already encountered all of the columns...put whatever is 147f5cc5759d55f803cd230c7a595e89e634c3c36eeKweku Adams // left in the last column. 148f5cc5759d55f803cd230c7a595e89e634c3c36eeKweku Adams record.pop_back(); 149f5cc5759d55f803cd230c7a595e89e634c3c36eeKweku Adams beginning = lastBeginning; 150f5cc5759d55f803cd230c7a595e89e634c3c36eeKweku Adams } 151f5cc5759d55f803cd230c7a595e89e634c3c36eeKweku Adams record.push_back(trimDefault(line.substr(beginning, lineSize - beginning))); 152f5cc5759d55f803cd230c7a595e89e634c3c36eeKweku Adams } 153e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin return record; 154e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin} 155e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin 156f5cc5759d55f803cd230c7a595e89e634c3c36eeKweku Adamsvoid printRecord(const record_t& record) { 157f5cc5759d55f803cd230c7a595e89e634c3c36eeKweku Adams fprintf(stderr, "Record: { "); 158f5cc5759d55f803cd230c7a595e89e634c3c36eeKweku Adams if (record.size() == 0) { 159f5cc5759d55f803cd230c7a595e89e634c3c36eeKweku Adams fprintf(stderr, "}\n"); 160f5cc5759d55f803cd230c7a595e89e634c3c36eeKweku Adams return; 161f5cc5759d55f803cd230c7a595e89e634c3c36eeKweku Adams } 162f5cc5759d55f803cd230c7a595e89e634c3c36eeKweku Adams for(size_t i = 0; i < record.size(); ++i) { 163f5cc5759d55f803cd230c7a595e89e634c3c36eeKweku Adams if(i != 0) fprintf(stderr, "\", "); 164f5cc5759d55f803cd230c7a595e89e634c3c36eeKweku Adams fprintf(stderr, "\"%s", record[i].c_str()); 165f5cc5759d55f803cd230c7a595e89e634c3c36eeKweku Adams } 166f5cc5759d55f803cd230c7a595e89e634c3c36eeKweku Adams fprintf(stderr, "\" }\n"); 167f5cc5759d55f803cd230c7a595e89e634c3c36eeKweku Adams} 168f5cc5759d55f803cd230c7a595e89e634c3c36eeKweku Adams 169e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jinbool stripPrefix(std::string* line, const char* key, bool endAtDelimiter) { 170810b14f5c24a9517dd6ded3ce5a38cfc8e29b3edYi Jin const auto head = line->find_first_not_of(DEFAULT_WHITESPACE); 171810b14f5c24a9517dd6ded3ce5a38cfc8e29b3edYi Jin if (head == std::string::npos) return false; 172e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin int len = (int)line->length(); 173e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin int i = 0; 174e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin int j = head; 175810b14f5c24a9517dd6ded3ce5a38cfc8e29b3edYi Jin while (key[i] != '\0') { 176e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin if (j >= len || key[i++] != line->at(j++)) { 177e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin return false; 178e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin } 179e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin } 180e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin 181e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin if (endAtDelimiter) { 182e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin // this means if the line only have prefix or no delimiter, we still return false. 183e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin if (j == len || isValidChar(line->at(j))) return false; 184e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin } 185e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin 186e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin line->assign(trimDefault(line->substr(j))); 187e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin return true; 188e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin} 189e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin 190e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jinbool stripSuffix(std::string* line, const char* key, bool endAtDelimiter) { 191e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin const auto tail = line->find_last_not_of(DEFAULT_WHITESPACE); 192e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin if (tail == std::string::npos) return false; 193e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin int i = 0; 194e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin while (key[++i] != '\0'); // compute the size of the key 195e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin int j = tail; 196e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin while (i > 0) { 197e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin if (j < 0 || key[--i] != line->at(j--)) { 198810b14f5c24a9517dd6ded3ce5a38cfc8e29b3edYi Jin return false; 199810b14f5c24a9517dd6ded3ce5a38cfc8e29b3edYi Jin } 200810b14f5c24a9517dd6ded3ce5a38cfc8e29b3edYi Jin } 201e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin 202e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin if (endAtDelimiter) { 203e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin // this means if the line only have suffix or no delimiter, we still return false. 204e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin if (j < 0 || isValidChar(line->at(j))) return false; 205e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin } 206e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin 207e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin line->assign(trimDefault(line->substr(0, j+1))); 208810b14f5c24a9517dd6ded3ce5a38cfc8e29b3edYi Jin return true; 209810b14f5c24a9517dd6ded3ce5a38cfc8e29b3edYi Jin} 210810b14f5c24a9517dd6ded3ce5a38cfc8e29b3edYi Jin 2113c034c987e1eeb49660fb62d3426c292a01412c9Yi Jinstd::string behead(std::string* line, const char cut) { 2123c034c987e1eeb49660fb62d3426c292a01412c9Yi Jin auto found = line->find_first_of(cut); 2133c034c987e1eeb49660fb62d3426c292a01412c9Yi Jin if (found == std::string::npos) { 2143c034c987e1eeb49660fb62d3426c292a01412c9Yi Jin std::string head = line->substr(0); 2153c034c987e1eeb49660fb62d3426c292a01412c9Yi Jin line->assign(""); 2163c034c987e1eeb49660fb62d3426c292a01412c9Yi Jin return head; 2173c034c987e1eeb49660fb62d3426c292a01412c9Yi Jin } 2183c034c987e1eeb49660fb62d3426c292a01412c9Yi Jin std::string head = line->substr(0, found); 2193c034c987e1eeb49660fb62d3426c292a01412c9Yi Jin while(line->at(found) == cut) found++; // trim more cut of the rest 2203c034c987e1eeb49660fb62d3426c292a01412c9Yi Jin line->assign(line->substr(found)); 2213c034c987e1eeb49660fb62d3426c292a01412c9Yi Jin return head; 2223c034c987e1eeb49660fb62d3426c292a01412c9Yi Jin} 2233c034c987e1eeb49660fb62d3426c292a01412c9Yi Jin 22404625ad4886a478bf74bbfc13937c10fa63eb272Yi Jinint toInt(const std::string& s) { 22504625ad4886a478bf74bbfc13937c10fa63eb272Yi Jin return atoi(s.c_str()); 22604625ad4886a478bf74bbfc13937c10fa63eb272Yi Jin} 22704625ad4886a478bf74bbfc13937c10fa63eb272Yi Jin 22804625ad4886a478bf74bbfc13937c10fa63eb272Yi Jinlong long toLongLong(const std::string& s) { 22904625ad4886a478bf74bbfc13937c10fa63eb272Yi Jin return atoll(s.c_str()); 23004625ad4886a478bf74bbfc13937c10fa63eb272Yi Jin} 23104625ad4886a478bf74bbfc13937c10fa63eb272Yi Jin 232e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jindouble toDouble(const std::string& s) { 233e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin return atof(s.c_str()); 234e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin} 235b44f7d46b647e24d8ea4fdf45742bbcbbfb03113Yi Jin 236e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin// ============================================================================== 237e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi JinReader::Reader(const int fd) 238b44f7d46b647e24d8ea4fdf45742bbcbbfb03113Yi Jin{ 239e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin mFile = fdopen(fd, "r"); 240e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin mStatus = mFile == NULL ? "Invalid fd " + std::to_string(fd) : ""; 241b44f7d46b647e24d8ea4fdf45742bbcbbfb03113Yi Jin} 242b44f7d46b647e24d8ea4fdf45742bbcbbfb03113Yi Jin 243b44f7d46b647e24d8ea4fdf45742bbcbbfb03113Yi JinReader::~Reader() 244b44f7d46b647e24d8ea4fdf45742bbcbbfb03113Yi Jin{ 245e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin if (mFile != NULL) fclose(mFile); 246e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin} 247b44f7d46b647e24d8ea4fdf45742bbcbbfb03113Yi Jin 248e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jinbool Reader::readLine(std::string* line) { 249e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin if (mFile == NULL) return false; 250b44f7d46b647e24d8ea4fdf45742bbcbbfb03113Yi Jin 251e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin char* buf = NULL; 252e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin size_t len = 0; 253e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin ssize_t read = getline(&buf, &len, mFile); 254e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin if (read != -1) { 255e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin std::string s(buf); 256e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin line->assign(trim(s, DEFAULT_NEWLINE)); 257e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin } else if (errno == EINVAL) { 258e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin mStatus = "Bad Argument"; 259b44f7d46b647e24d8ea4fdf45742bbcbbfb03113Yi Jin } 260e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin free(buf); 261e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin return read != -1; 262b44f7d46b647e24d8ea4fdf45742bbcbbfb03113Yi Jin} 263b44f7d46b647e24d8ea4fdf45742bbcbbfb03113Yi Jin 264810b14f5c24a9517dd6ded3ce5a38cfc8e29b3edYi Jinbool Reader::ok(std::string* error) { 265810b14f5c24a9517dd6ded3ce5a38cfc8e29b3edYi Jin error->assign(mStatus); 266b44f7d46b647e24d8ea4fdf45742bbcbbfb03113Yi Jin return mStatus.empty(); 267b44f7d46b647e24d8ea4fdf45742bbcbbfb03113Yi Jin} 26804625ad4886a478bf74bbfc13937c10fa63eb272Yi Jin 26904625ad4886a478bf74bbfc13937c10fa63eb272Yi Jin// ============================================================================== 2700dfa752e67116940f04a988ca4a264f7140dd81fYi JinTable::Table(const char* names[], const uint64_t ids[], const int count) 2710dfa752e67116940f04a988ca4a264f7140dd81fYi Jin :mEnums(), 2720dfa752e67116940f04a988ca4a264f7140dd81fYi Jin mEnumValuesByName() 273e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin{ 2746cacbcbf436be744a34f7ea0d4f838ff97757446Yi Jin std::map<std::string, uint64_t> fields; 2750dfa752e67116940f04a988ca4a264f7140dd81fYi Jin for (int i = 0; i < count; i++) { 2760dfa752e67116940f04a988ca4a264f7140dd81fYi Jin fields[names[i]] = ids[i]; 277e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin } 2780dfa752e67116940f04a988ca4a264f7140dd81fYi Jin mFields = fields; 279e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin} 280e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin 2810dfa752e67116940f04a988ca4a264f7140dd81fYi JinTable::~Table() 282e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin{ 283e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin} 284e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin 2850dfa752e67116940f04a988ca4a264f7140dd81fYi Jinvoid 2860dfa752e67116940f04a988ca4a264f7140dd81fYi JinTable::addEnumTypeMap(const char* field, const char* enumNames[], const int enumValues[], const int enumSize) 28704625ad4886a478bf74bbfc13937c10fa63eb272Yi Jin{ 288f5cc5759d55f803cd230c7a595e89e634c3c36eeKweku Adams if (mFields.find(field) == mFields.end()) { 2896cacbcbf436be744a34f7ea0d4f838ff97757446Yi Jin fprintf(stderr, "Field '%s' not found", field); 290f5cc5759d55f803cd230c7a595e89e634c3c36eeKweku Adams return; 291f5cc5759d55f803cd230c7a595e89e634c3c36eeKweku Adams } 29204625ad4886a478bf74bbfc13937c10fa63eb272Yi Jin 2936cacbcbf436be744a34f7ea0d4f838ff97757446Yi Jin std::map<std::string, int> enu; 2940dfa752e67116940f04a988ca4a264f7140dd81fYi Jin for (int i = 0; i < enumSize; i++) { 2950dfa752e67116940f04a988ca4a264f7140dd81fYi Jin enu[enumNames[i]] = enumValues[i]; 2960dfa752e67116940f04a988ca4a264f7140dd81fYi Jin } 2970dfa752e67116940f04a988ca4a264f7140dd81fYi Jin mEnums[field] = enu; 29804625ad4886a478bf74bbfc13937c10fa63eb272Yi Jin} 29904625ad4886a478bf74bbfc13937c10fa63eb272Yi Jin 300e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jinvoid 3010dfa752e67116940f04a988ca4a264f7140dd81fYi JinTable::addEnumNameToValue(const char* enumName, const int enumValue) 302e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin{ 3030dfa752e67116940f04a988ca4a264f7140dd81fYi Jin mEnumValuesByName[enumName] = enumValue; 304e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin} 305e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin 30604625ad4886a478bf74bbfc13937c10fa63eb272Yi Jinbool 307e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi JinTable::insertField(ProtoOutputStream* proto, const std::string& name, const std::string& value) 30804625ad4886a478bf74bbfc13937c10fa63eb272Yi Jin{ 3090dfa752e67116940f04a988ca4a264f7140dd81fYi Jin if (mFields.find(name) == mFields.end()) return false; 31004625ad4886a478bf74bbfc13937c10fa63eb272Yi Jin 3110dfa752e67116940f04a988ca4a264f7140dd81fYi Jin uint64_t found = mFields[name]; 3120dfa752e67116940f04a988ca4a264f7140dd81fYi Jin record_t repeats; // used for repeated fields 3130dfa752e67116940f04a988ca4a264f7140dd81fYi Jin switch ((found & FIELD_COUNT_MASK) | (found & FIELD_TYPE_MASK)) { 3140dfa752e67116940f04a988ca4a264f7140dd81fYi Jin case FIELD_COUNT_SINGLE | FIELD_TYPE_DOUBLE: 3150dfa752e67116940f04a988ca4a264f7140dd81fYi Jin case FIELD_COUNT_SINGLE | FIELD_TYPE_FLOAT: 316e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin proto->write(found, toDouble(value)); 317e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin break; 3180dfa752e67116940f04a988ca4a264f7140dd81fYi Jin case FIELD_COUNT_SINGLE | FIELD_TYPE_STRING: 3190dfa752e67116940f04a988ca4a264f7140dd81fYi Jin case FIELD_COUNT_SINGLE | FIELD_TYPE_BYTES: 320e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin proto->write(found, value); 32104625ad4886a478bf74bbfc13937c10fa63eb272Yi Jin break; 3220dfa752e67116940f04a988ca4a264f7140dd81fYi Jin case FIELD_COUNT_SINGLE | FIELD_TYPE_INT64: 3230dfa752e67116940f04a988ca4a264f7140dd81fYi Jin case FIELD_COUNT_SINGLE | FIELD_TYPE_SINT64: 3240dfa752e67116940f04a988ca4a264f7140dd81fYi Jin case FIELD_COUNT_SINGLE | FIELD_TYPE_UINT64: 3250dfa752e67116940f04a988ca4a264f7140dd81fYi Jin case FIELD_COUNT_SINGLE | FIELD_TYPE_FIXED64: 3260dfa752e67116940f04a988ca4a264f7140dd81fYi Jin case FIELD_COUNT_SINGLE | FIELD_TYPE_SFIXED64: 327e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin proto->write(found, toLongLong(value)); 32804625ad4886a478bf74bbfc13937c10fa63eb272Yi Jin break; 3290dfa752e67116940f04a988ca4a264f7140dd81fYi Jin case FIELD_COUNT_SINGLE | FIELD_TYPE_BOOL: 3300dfa752e67116940f04a988ca4a264f7140dd81fYi Jin if (strcmp(toLowerStr(value).c_str(), "true") == 0 || strcmp(value.c_str(), "1") == 0) { 3310dfa752e67116940f04a988ca4a264f7140dd81fYi Jin proto->write(found, true); 3320dfa752e67116940f04a988ca4a264f7140dd81fYi Jin break; 3330dfa752e67116940f04a988ca4a264f7140dd81fYi Jin } 3340dfa752e67116940f04a988ca4a264f7140dd81fYi Jin if (strcmp(toLowerStr(value).c_str(), "false") == 0 || strcmp(value.c_str(), "0") == 0) { 3350dfa752e67116940f04a988ca4a264f7140dd81fYi Jin proto->write(found, false); 3360dfa752e67116940f04a988ca4a264f7140dd81fYi Jin break; 3370dfa752e67116940f04a988ca4a264f7140dd81fYi Jin } 338e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin return false; 3390dfa752e67116940f04a988ca4a264f7140dd81fYi Jin case FIELD_COUNT_SINGLE | FIELD_TYPE_ENUM: 3400dfa752e67116940f04a988ca4a264f7140dd81fYi Jin // if the field has its own enum mapping, use this, otherwise use general name to value mapping. 3410dfa752e67116940f04a988ca4a264f7140dd81fYi Jin if (mEnums.find(name) != mEnums.end()) { 3420dfa752e67116940f04a988ca4a264f7140dd81fYi Jin if (mEnums[name].find(value) != mEnums[name].end()) { 3430dfa752e67116940f04a988ca4a264f7140dd81fYi Jin proto->write(found, mEnums[name][value]); 3440dfa752e67116940f04a988ca4a264f7140dd81fYi Jin } else { 3450dfa752e67116940f04a988ca4a264f7140dd81fYi Jin proto->write(found, 0); // TODO: should get the default enum value (Unknown) 3460dfa752e67116940f04a988ca4a264f7140dd81fYi Jin } 3470dfa752e67116940f04a988ca4a264f7140dd81fYi Jin } else if (mEnumValuesByName.find(value) != mEnumValuesByName.end()) { 3480dfa752e67116940f04a988ca4a264f7140dd81fYi Jin proto->write(found, mEnumValuesByName[value]); 349f5cc5759d55f803cd230c7a595e89e634c3c36eeKweku Adams } else if (isNumber(value)) { 350f5cc5759d55f803cd230c7a595e89e634c3c36eeKweku Adams proto->write(found, toInt(value)); 3510dfa752e67116940f04a988ca4a264f7140dd81fYi Jin } else { 352e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin return false; 353e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin } 354e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin break; 3550dfa752e67116940f04a988ca4a264f7140dd81fYi Jin case FIELD_COUNT_SINGLE | FIELD_TYPE_INT32: 3560dfa752e67116940f04a988ca4a264f7140dd81fYi Jin case FIELD_COUNT_SINGLE | FIELD_TYPE_SINT32: 3570dfa752e67116940f04a988ca4a264f7140dd81fYi Jin case FIELD_COUNT_SINGLE | FIELD_TYPE_UINT32: 3580dfa752e67116940f04a988ca4a264f7140dd81fYi Jin case FIELD_COUNT_SINGLE | FIELD_TYPE_FIXED32: 3590dfa752e67116940f04a988ca4a264f7140dd81fYi Jin case FIELD_COUNT_SINGLE | FIELD_TYPE_SFIXED32: 360e2f7f79d023f0b3ba2fee374492dde61f525ece6Yi Jin proto->write(found, toInt(value)); 36104625ad4886a478bf74bbfc13937c10fa63eb272Yi Jin break; 3620dfa752e67116940f04a988ca4a264f7140dd81fYi Jin // REPEATED TYPE below: 3630dfa752e67116940f04a988ca4a264f7140dd81fYi Jin case FIELD_COUNT_REPEATED | FIELD_TYPE_INT32: 3640dfa752e67116940f04a988ca4a264f7140dd81fYi Jin repeats = parseRecord(value, COMMA_DELIMITER); 3650dfa752e67116940f04a988ca4a264f7140dd81fYi Jin for (size_t i=0; i<repeats.size(); i++) { 3660dfa752e67116940f04a988ca4a264f7140dd81fYi Jin proto->write(found, toInt(repeats[i])); 3670dfa752e67116940f04a988ca4a264f7140dd81fYi Jin } 3680dfa752e67116940f04a988ca4a264f7140dd81fYi Jin break; 3690dfa752e67116940f04a988ca4a264f7140dd81fYi Jin case FIELD_COUNT_REPEATED | FIELD_TYPE_STRING: 3700dfa752e67116940f04a988ca4a264f7140dd81fYi Jin repeats = parseRecord(value, COMMA_DELIMITER); 3710dfa752e67116940f04a988ca4a264f7140dd81fYi Jin for (size_t i=0; i<repeats.size(); i++) { 3720dfa752e67116940f04a988ca4a264f7140dd81fYi Jin proto->write(found, repeats[i]); 3730dfa752e67116940f04a988ca4a264f7140dd81fYi Jin } 3740dfa752e67116940f04a988ca4a264f7140dd81fYi Jin break; 37504625ad4886a478bf74bbfc13937c10fa63eb272Yi Jin default: 37604625ad4886a478bf74bbfc13937c10fa63eb272Yi Jin return false; 37704625ad4886a478bf74bbfc13937c10fa63eb272Yi Jin } 37804625ad4886a478bf74bbfc13937c10fa63eb272Yi Jin return true; 37904625ad4886a478bf74bbfc13937c10fa63eb272Yi Jin} 3809299af93945376c4390cc24f5a0c1844997a694bYi Jin 3819299af93945376c4390cc24f5a0c1844997a694bYi Jin// ================================================================================ 3829299af93945376c4390cc24f5a0c1844997a694bYi JinMessage::Message(Table* table) 3839299af93945376c4390cc24f5a0c1844997a694bYi Jin :mTable(table), 3849299af93945376c4390cc24f5a0c1844997a694bYi Jin mPreviousField(""), 3859299af93945376c4390cc24f5a0c1844997a694bYi Jin mTokens(), 3869299af93945376c4390cc24f5a0c1844997a694bYi Jin mSubMessages() 3879299af93945376c4390cc24f5a0c1844997a694bYi Jin{ 3889299af93945376c4390cc24f5a0c1844997a694bYi Jin} 3899299af93945376c4390cc24f5a0c1844997a694bYi Jin 3909299af93945376c4390cc24f5a0c1844997a694bYi JinMessage::~Message() 3919299af93945376c4390cc24f5a0c1844997a694bYi Jin{ 3929299af93945376c4390cc24f5a0c1844997a694bYi Jin} 3939299af93945376c4390cc24f5a0c1844997a694bYi Jin 3949299af93945376c4390cc24f5a0c1844997a694bYi Jinvoid 3959299af93945376c4390cc24f5a0c1844997a694bYi JinMessage::addSubMessage(uint64_t fieldId, Message* fieldMsg) 3969299af93945376c4390cc24f5a0c1844997a694bYi Jin{ 3979299af93945376c4390cc24f5a0c1844997a694bYi Jin for (auto iter = mTable->mFields.begin(); iter != mTable->mFields.end(); iter++) { 3989299af93945376c4390cc24f5a0c1844997a694bYi Jin if (iter->second == fieldId) { 3999299af93945376c4390cc24f5a0c1844997a694bYi Jin mSubMessages[iter->first] = fieldMsg; 4009299af93945376c4390cc24f5a0c1844997a694bYi Jin return; 4019299af93945376c4390cc24f5a0c1844997a694bYi Jin } 4029299af93945376c4390cc24f5a0c1844997a694bYi Jin } 4039299af93945376c4390cc24f5a0c1844997a694bYi Jin} 4049299af93945376c4390cc24f5a0c1844997a694bYi Jin 4059299af93945376c4390cc24f5a0c1844997a694bYi Jinbool 4069299af93945376c4390cc24f5a0c1844997a694bYi JinMessage::insertField(ProtoOutputStream* proto, const std::string& name, const std::string& value) 4079299af93945376c4390cc24f5a0c1844997a694bYi Jin{ 4089299af93945376c4390cc24f5a0c1844997a694bYi Jin // If the field name can be found, it means the name is a primitive field. 4099299af93945376c4390cc24f5a0c1844997a694bYi Jin if (mTable->mFields.find(name) != mTable->mFields.end()) { 4109299af93945376c4390cc24f5a0c1844997a694bYi Jin endSession(proto); 4119299af93945376c4390cc24f5a0c1844997a694bYi Jin // The only edge case is for example ro.hardware itself is a message, so a field called "value" 4129299af93945376c4390cc24f5a0c1844997a694bYi Jin // would be defined in proto Ro::Hardware and it must be the first field. 4139299af93945376c4390cc24f5a0c1844997a694bYi Jin if (mSubMessages.find(name) != mSubMessages.end()) { 4149299af93945376c4390cc24f5a0c1844997a694bYi Jin startSession(proto, name); 4159299af93945376c4390cc24f5a0c1844997a694bYi Jin return mSubMessages[name]->insertField(proto, "value", value); 4169299af93945376c4390cc24f5a0c1844997a694bYi Jin } else { 4179299af93945376c4390cc24f5a0c1844997a694bYi Jin return mTable->insertField(proto, name, value); 4189299af93945376c4390cc24f5a0c1844997a694bYi Jin } 4199299af93945376c4390cc24f5a0c1844997a694bYi Jin } 4209299af93945376c4390cc24f5a0c1844997a694bYi Jin 4219299af93945376c4390cc24f5a0c1844997a694bYi Jin // Try to find the message field which is the prefix of name, so the value would be inserted 4229299af93945376c4390cc24f5a0c1844997a694bYi Jin // recursively into the submessage. 4236cacbcbf436be744a34f7ea0d4f838ff97757446Yi Jin std::string mutableName = name; 4249299af93945376c4390cc24f5a0c1844997a694bYi Jin for (auto iter = mSubMessages.begin(); iter != mSubMessages.end(); iter++) { 4256cacbcbf436be744a34f7ea0d4f838ff97757446Yi Jin std::string fieldName = iter->first; 4266cacbcbf436be744a34f7ea0d4f838ff97757446Yi Jin std::string prefix = fieldName + "_"; // underscore is the delimiter in the name 4279299af93945376c4390cc24f5a0c1844997a694bYi Jin if (stripPrefix(&mutableName, prefix.c_str())) { 4289299af93945376c4390cc24f5a0c1844997a694bYi Jin if (mPreviousField != fieldName) { 4299299af93945376c4390cc24f5a0c1844997a694bYi Jin endSession(proto); 4309299af93945376c4390cc24f5a0c1844997a694bYi Jin startSession(proto, fieldName); 4319299af93945376c4390cc24f5a0c1844997a694bYi Jin } 4329299af93945376c4390cc24f5a0c1844997a694bYi Jin return mSubMessages[fieldName]->insertField(proto, mutableName, value); 4339299af93945376c4390cc24f5a0c1844997a694bYi Jin } 4349299af93945376c4390cc24f5a0c1844997a694bYi Jin } 4359299af93945376c4390cc24f5a0c1844997a694bYi Jin // Can't find the name in proto definition, handle it separately. 4369299af93945376c4390cc24f5a0c1844997a694bYi Jin return false; 4379299af93945376c4390cc24f5a0c1844997a694bYi Jin} 4389299af93945376c4390cc24f5a0c1844997a694bYi Jin 4399299af93945376c4390cc24f5a0c1844997a694bYi Jinvoid 4406cacbcbf436be744a34f7ea0d4f838ff97757446Yi JinMessage::startSession(ProtoOutputStream* proto, const std::string& name) 4419299af93945376c4390cc24f5a0c1844997a694bYi Jin{ 4429299af93945376c4390cc24f5a0c1844997a694bYi Jin uint64_t fieldId = mTable->mFields[name]; 4435ee0787024cc446a21008ff5710dec19c6afc834Yi Jin uint64_t token = proto->start(fieldId); 4449299af93945376c4390cc24f5a0c1844997a694bYi Jin mPreviousField = name; 4459299af93945376c4390cc24f5a0c1844997a694bYi Jin mTokens.push(token); 4469299af93945376c4390cc24f5a0c1844997a694bYi Jin} 4479299af93945376c4390cc24f5a0c1844997a694bYi Jin 4489299af93945376c4390cc24f5a0c1844997a694bYi Jinvoid 4499299af93945376c4390cc24f5a0c1844997a694bYi JinMessage::endSession(ProtoOutputStream* proto) 4509299af93945376c4390cc24f5a0c1844997a694bYi Jin{ 4519299af93945376c4390cc24f5a0c1844997a694bYi Jin if (mPreviousField == "") return; 4529299af93945376c4390cc24f5a0c1844997a694bYi Jin if (mSubMessages.find(mPreviousField) != mSubMessages.end()) { 4539299af93945376c4390cc24f5a0c1844997a694bYi Jin mSubMessages[mPreviousField]->endSession(proto); 4549299af93945376c4390cc24f5a0c1844997a694bYi Jin } 4559299af93945376c4390cc24f5a0c1844997a694bYi Jin proto->end(mTokens.top()); 4569299af93945376c4390cc24f5a0c1844997a694bYi Jin mTokens.pop(); 4579299af93945376c4390cc24f5a0c1844997a694bYi Jin mPreviousField = ""; 4589299af93945376c4390cc24f5a0c1844997a694bYi Jin} 459