blob: b2fda23ac391b475a49710935a4299b78cd10e95 [file] [log] [blame]
Yi Jinb44f7d42017-07-21 12:12:59 -07001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "incident_helper"
18
19#include "ih_util.h"
20
21#include <sstream>
22#include <unistd.h>
23
24const ssize_t BUFFER_SIZE = 16 * 1024; // 4KB
25
Yi Jin4ef28b72017-08-14 14:45:28 -070026
27static std::string trim(const std::string& s) {
28 const auto head = s.find_first_not_of(DEFAULT_WHITESPACE);
Yi Jinb44f7d42017-07-21 12:12:59 -070029 if (head == std::string::npos) return "";
30
Yi Jin4ef28b72017-08-14 14:45:28 -070031 const auto tail = s.find_last_not_of(DEFAULT_WHITESPACE);
Yi Jinb44f7d42017-07-21 12:12:59 -070032 return s.substr(head, tail - head + 1);
33}
34
Yi Jin4ef28b72017-08-14 14:45:28 -070035static std::string trimHeader(const std::string& s) {
36 std::string res = trim(s);
37 std::transform(res.begin(), res.end(), res.begin(), ::tolower);
38 return res;
39}
40
Yi Jinb44f7d42017-07-21 12:12:59 -070041// This is similiar to Split in android-base/file.h, but it won't add empty string
Yi Jin4ef28b72017-08-14 14:45:28 -070042static void split(const std::string& line, std::vector<std::string>& words,
43 const trans_func& func, const std::string& delimiters) {
Yi Jinb44f7d42017-07-21 12:12:59 -070044 words.clear(); // clear the buffer before split
45
46 size_t base = 0;
47 size_t found;
48 while (true) {
49 found = line.find_first_of(delimiters, base);
50 if (found != base) {
Yi Jin4ef28b72017-08-14 14:45:28 -070051 std::string word = (*func) (line.substr(base, found - base));
Yi Jinb44f7d42017-07-21 12:12:59 -070052 if (!word.empty()) {
53 words.push_back(word);
54 }
55 }
56 if (found == line.npos) break;
57 base = found + 1;
58 }
59}
60
Yi Jin4ef28b72017-08-14 14:45:28 -070061header_t parseHeader(const std::string& line, const std::string& delimiters) {
62 header_t header;
63 trans_func f = &trimHeader;
64 split(line, header, f, delimiters);
65 return header;
66}
67
68record_t parseRecord(const std::string& line, const std::string& delimiters) {
69 record_t record;
70 trans_func f = &trim;
71 split(line, record, f, delimiters);
72 return record;
Yi Jinb44f7d42017-07-21 12:12:59 -070073}
74
75Reader::Reader(const int fd) : Reader(fd, BUFFER_SIZE) {};
76
77Reader::Reader(const int fd, const size_t capacity)
78 : mFd(fd), mMaxSize(capacity), mBufSize(0), mRead(0), mFlushed(0)
79{
80 mBuf = capacity > 0 ? (char*)malloc(capacity * sizeof(char)) : NULL;
81 mStatus = mFd < 0 ? "Negative fd" : (capacity == 0 ? "Zero buffer capacity" : "");
82}
83
84Reader::~Reader()
85{
86 free(mBuf);
87}
88
89bool Reader::readLine(std::string& line, const char newline) {
90 if (!ok(line)) return false; // bad status
91 std::stringstream ss;
92 while (!EOR()) {
93 // read if available
94 if (mFd != -1 && mBufSize != mMaxSize) {
95 ssize_t amt = 0;
96 if (mRead >= mFlushed) {
97 amt = ::read(mFd, mBuf + mRead, mMaxSize - mRead);
98 } else {
99 amt = ::read(mFd, mBuf + mRead, mFlushed - mRead);
100 }
101 if (amt < 0) {
102 mStatus = "Fail to read from fd";
103 return false;
104 } else if (amt == 0) {
105 close(mFd);
106 mFd = -1;
107 }
108 mRead += amt;
109 mBufSize += amt;
110 }
111
112 bool meetsNewLine = false;
113 if (mBufSize > 0) {
114 int start = mFlushed;
115 int end = mFlushed < mRead ? mRead : mMaxSize;
116 while (mFlushed < end && mBuf[mFlushed++] != newline && mBufSize > 0) mBufSize--;
117 meetsNewLine = (mBuf[mFlushed-1] == newline);
118 if (meetsNewLine) mBufSize--; // deduct the new line character
119 size_t len = meetsNewLine ? mFlushed - start - 1 : mFlushed - start;
120 ss.write(mBuf + start, len);
121 }
122
123 if (mRead >= (int) mMaxSize) mRead = 0;
124 if (mFlushed >= (int) mMaxSize) mFlushed = 0;
125
126 if (EOR() || meetsNewLine) {
127 line.assign(ss.str());
128 return true;
129 }
130 }
131 return false;
132}
133
134bool Reader::ok(std::string& error) {
135 error.assign(mStatus);
136 return mStatus.empty();
137}