blob: c7f1129fbbaadcab594cded23394de1229a324b6 [file] [log] [blame]
Joe Onorato99598ee2019-02-11 15:55:13 +00001/*
2 * Copyright (C) 2018 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#define LOG_TAG "libprotoutil"
17
18#include <android/util/ProtoFileReader.h>
19#include <cutils/log.h>
20
21#include <cinttypes>
22#include <type_traits>
23
24#include <unistd.h>
25
26namespace android {
27namespace util {
28
29/**
30 * Get the amount of data remaining in the file in fd, or -1 if the file size can't be measured.
31 * It's not the whole file, but this allows us to skip any preamble that might have already
32 * been passed over.
33 */
34ssize_t get_file_size(int fd) {
35 off_t current = lseek(fd, 0, SEEK_CUR);
36 if (current < 0) {
37 return -1;
38 }
39 off_t end = lseek(fd, 0, SEEK_END);
40 if (end < 0) {
41 return -1;
42 }
43 off_t err = lseek(fd, current, SEEK_SET);
44 if (err < 0) {
45 ALOGW("get_file_size could do SEEK_END but not SEEK_SET. We might have skipped data.");
46 return -1;
47 }
48 return (ssize_t)(end-current);
49}
50
51// =========================================================================
52ProtoFileReader::ProtoFileReader(int fd)
53 :mFd(fd),
54 mStatus(NO_ERROR),
55 mSize(get_file_size(fd)),
56 mPos(0),
57 mOffset(0),
Joe Onorato4796ae62019-04-03 16:17:16 -070058 mMaxOffset(0),
Joe Onorato99598ee2019-02-11 15:55:13 +000059 mChunkSize(sizeof(mBuffer)) {
60}
61
62ProtoFileReader::~ProtoFileReader() {
63}
64
65ssize_t
66ProtoFileReader::size() const
67{
68 return (ssize_t)mSize;
69}
70
71size_t
72ProtoFileReader::bytesRead() const
73{
74 return mPos;
75}
76
77uint8_t const*
78ProtoFileReader::readBuffer()
79{
80 return hasNext() ? mBuffer + mOffset : NULL;
81}
82
83size_t
84ProtoFileReader::currentToRead()
85{
86 return mMaxOffset - mOffset;
87}
88
89bool
90ProtoFileReader::hasNext()
91{
92 return ensure_data();
93}
94
95uint8_t
96ProtoFileReader::next()
97{
98 if (!ensure_data()) {
99 // Shouldn't get to here. Always call hasNext() before calling next().
100 return 0;
101 }
Yao Chen43706b42019-04-21 14:34:30 -0700102 mPos++;
Joe Onorato99598ee2019-02-11 15:55:13 +0000103 return mBuffer[mOffset++];
104}
105
106uint64_t
107ProtoFileReader::readRawVarint()
108{
109 uint64_t val = 0, shift = 0;
110 while (true) {
111 if (!hasNext()) {
112 ALOGW("readRawVarint() called without hasNext() called first.");
113 mStatus = NOT_ENOUGH_DATA;
114 return 0;
115 }
116 uint8_t byte = next();
117 val |= (INT64_C(0x7F) & byte) << shift;
118 if ((byte & 0x80) == 0) break;
119 shift += 7;
120 }
121 return val;
122}
123
124void
125ProtoFileReader::move(size_t amt)
126{
127 while (mStatus == NO_ERROR && amt > 0) {
128 if (!ensure_data()) {
129 return;
130 }
Yao Chen9f433c82019-04-21 20:10:27 -0700131 const size_t chunk =
132 mMaxOffset - mOffset > amt ? amt : mMaxOffset - mOffset;
Joe Onorato99598ee2019-02-11 15:55:13 +0000133 mOffset += chunk;
Yao Chen43706b42019-04-21 14:34:30 -0700134 mPos += chunk;
Joe Onorato99598ee2019-02-11 15:55:13 +0000135 amt -= chunk;
136 }
137}
138
139status_t
140ProtoFileReader::getError() const {
141 return mStatus;
142}
143
144bool
145ProtoFileReader::ensure_data() {
146 if (mStatus != NO_ERROR) {
147 return false;
148 }
149 if (mOffset < mMaxOffset) {
150 return true;
151 }
152 ssize_t amt = TEMP_FAILURE_RETRY(read(mFd, mBuffer, mChunkSize));
153 if (amt == 0) {
154 return false;
155 } else if (amt < 0) {
156 mStatus = -errno;
157 return false;
158 } else {
159 mOffset = 0;
160 mMaxOffset = amt;
161 return true;
162 }
163}
164
165
166} // util
167} // android
168