blob: 4ff6d787cf0f71b03f75cae56112876b882afd56 [file] [log] [blame]
Adam Lesinski00451162017-10-03 07:44:08 -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#include "io/FileStream.h"
18
19#include <errno.h> // for errno
20#include <fcntl.h> // for O_RDONLY
21#include <unistd.h> // for read
22
23#include "android-base/errors.h"
24#include "android-base/file.h" // for O_BINARY
25#include "android-base/macros.h"
26#include "android-base/utf8.h"
27
28using ::android::base::SystemErrorCodeToString;
Adam Lesinski93190b72017-11-03 15:20:17 -070029using ::android::base::unique_fd;
Adam Lesinski00451162017-10-03 07:44:08 -070030
31namespace aapt {
32namespace io {
33
34FileInputStream::FileInputStream(const std::string& path, size_t buffer_capacity)
35 : FileInputStream(::android::base::utf8::open(path.c_str(), O_RDONLY | O_BINARY),
36 buffer_capacity) {
37}
38
39FileInputStream::FileInputStream(int fd, size_t buffer_capacity)
40 : fd_(fd),
41 buffer_capacity_(buffer_capacity),
42 buffer_offset_(0u),
43 buffer_size_(0u),
44 total_byte_count_(0u) {
45 if (fd_ == -1) {
46 error_ = SystemErrorCodeToString(errno);
47 } else {
48 buffer_.reset(new uint8_t[buffer_capacity_]);
49 }
50}
51
52bool FileInputStream::Next(const void** data, size_t* size) {
53 if (HadError()) {
54 return false;
55 }
56
57 // Deal with any remaining bytes after BackUp was called.
58 if (buffer_offset_ != buffer_size_) {
59 *data = buffer_.get() + buffer_offset_;
60 *size = buffer_size_ - buffer_offset_;
61 total_byte_count_ += buffer_size_ - buffer_offset_;
62 buffer_offset_ = buffer_size_;
63 return true;
64 }
65
66 ssize_t n = TEMP_FAILURE_RETRY(read(fd_, buffer_.get(), buffer_capacity_));
67 if (n < 0) {
68 error_ = SystemErrorCodeToString(errno);
69 fd_.reset();
70 buffer_.reset();
71 return false;
72 }
73
74 buffer_size_ = static_cast<size_t>(n);
75 buffer_offset_ = buffer_size_;
76 total_byte_count_ += buffer_size_;
77
78 *data = buffer_.get();
79 *size = buffer_size_;
80 return buffer_size_ != 0u;
81}
82
83void FileInputStream::BackUp(size_t count) {
84 if (count > buffer_offset_) {
85 count = buffer_offset_;
86 }
87 buffer_offset_ -= count;
88 total_byte_count_ -= count;
89}
90
91size_t FileInputStream::ByteCount() const {
92 return total_byte_count_;
93}
94
95bool FileInputStream::HadError() const {
96 return fd_ == -1;
97}
98
99std::string FileInputStream::GetError() const {
100 return error_;
101}
102
103FileOutputStream::FileOutputStream(const std::string& path, int mode, size_t buffer_capacity)
Adam Lesinski93190b72017-11-03 15:20:17 -0700104 : FileOutputStream(unique_fd(::android::base::utf8::open(path.c_str(), mode)),
105 buffer_capacity) {
106}
107
108FileOutputStream::FileOutputStream(unique_fd fd, size_t buffer_capacity)
109 : FileOutputStream(fd.get(), buffer_capacity) {
110 owned_fd_ = std::move(fd);
Adam Lesinski00451162017-10-03 07:44:08 -0700111}
112
113FileOutputStream::FileOutputStream(int fd, size_t buffer_capacity)
114 : fd_(fd), buffer_capacity_(buffer_capacity), buffer_offset_(0u), total_byte_count_(0u) {
115 if (fd_ == -1) {
116 error_ = SystemErrorCodeToString(errno);
117 } else {
118 buffer_.reset(new uint8_t[buffer_capacity_]);
119 }
120}
121
122FileOutputStream::~FileOutputStream() {
123 // Flush the buffer.
124 Flush();
125}
126
127bool FileOutputStream::Next(void** data, size_t* size) {
Adam Lesinski93190b72017-11-03 15:20:17 -0700128 if (HadError()) {
Adam Lesinski00451162017-10-03 07:44:08 -0700129 return false;
130 }
131
132 if (buffer_offset_ == buffer_capacity_) {
133 if (!FlushImpl()) {
134 return false;
135 }
136 }
137
138 const size_t buffer_size = buffer_capacity_ - buffer_offset_;
139 *data = buffer_.get() + buffer_offset_;
140 *size = buffer_size;
141 total_byte_count_ += buffer_size;
142 buffer_offset_ = buffer_capacity_;
143 return true;
144}
145
146void FileOutputStream::BackUp(size_t count) {
147 if (count > buffer_offset_) {
148 count = buffer_offset_;
149 }
150 buffer_offset_ -= count;
151 total_byte_count_ -= count;
152}
153
154size_t FileOutputStream::ByteCount() const {
155 return total_byte_count_;
156}
157
158bool FileOutputStream::Flush() {
159 if (!HadError()) {
160 return FlushImpl();
161 }
162 return false;
163}
164
165bool FileOutputStream::FlushImpl() {
166 ssize_t n = TEMP_FAILURE_RETRY(write(fd_, buffer_.get(), buffer_offset_));
167 if (n < 0) {
168 error_ = SystemErrorCodeToString(errno);
Adam Lesinski93190b72017-11-03 15:20:17 -0700169 owned_fd_.reset();
170 fd_ = -1;
Adam Lesinski00451162017-10-03 07:44:08 -0700171 buffer_.reset();
172 return false;
173 }
174
175 buffer_offset_ = 0u;
176 return true;
177}
178
179bool FileOutputStream::HadError() const {
180 return fd_ == -1;
181}
182
183std::string FileOutputStream::GetError() const {
184 return error_;
185}
186
187} // namespace io
188} // namespace aapt