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