diff options
Diffstat (limited to 'tools/aapt2/io/FileStream.cpp')
-rw-r--r-- | tools/aapt2/io/FileStream.cpp | 203 |
1 files changed, 203 insertions, 0 deletions
diff --git a/tools/aapt2/io/FileStream.cpp b/tools/aapt2/io/FileStream.cpp new file mode 100644 index 000000000000..27529bc08a16 --- /dev/null +++ b/tools/aapt2/io/FileStream.cpp @@ -0,0 +1,203 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "io/FileStream.h" + +#include <errno.h> // for errno +#include <fcntl.h> // for O_RDONLY +#include <unistd.h> // for read + +#include "android-base/errors.h" +#include "android-base/file.h" // for O_BINARY +#include "android-base/macros.h" +#include "android-base/utf8.h" + +#if defined(_WIN32) +// This is only needed for O_CLOEXEC. +#include <windows.h> +#define O_CLOEXEC O_NOINHERIT +#endif + +using ::android::base::SystemErrorCodeToString; +using ::android::base::unique_fd; + +namespace aapt { +namespace io { + +FileInputStream::FileInputStream(const std::string& path, size_t buffer_capacity) + : buffer_capacity_(buffer_capacity) { + int mode = O_RDONLY | O_CLOEXEC | O_BINARY; + fd_.reset(TEMP_FAILURE_RETRY(::android::base::utf8::open(path.c_str(), mode))); + if (fd_ == -1) { + error_ = SystemErrorCodeToString(errno); + } else { + buffer_.reset(new uint8_t[buffer_capacity_]); + } +} + +FileInputStream::FileInputStream(int fd, size_t buffer_capacity) + : fd_(fd), buffer_capacity_(buffer_capacity) { + if (fd_ < 0) { + error_ = "Bad File Descriptor"; + } else { + buffer_.reset(new uint8_t[buffer_capacity_]); + } +} + +bool FileInputStream::Next(const void** data, size_t* size) { + if (HadError()) { + return false; + } + + // Deal with any remaining bytes after BackUp was called. + if (buffer_offset_ != buffer_size_) { + *data = buffer_.get() + buffer_offset_; + *size = buffer_size_ - buffer_offset_; + total_byte_count_ += buffer_size_ - buffer_offset_; + buffer_offset_ = buffer_size_; + return true; + } + + ssize_t n = TEMP_FAILURE_RETRY(read(fd_, buffer_.get(), buffer_capacity_)); + if (n < 0) { + error_ = SystemErrorCodeToString(errno); + fd_.reset(); + buffer_.reset(); + return false; + } + + buffer_size_ = static_cast<size_t>(n); + buffer_offset_ = buffer_size_; + total_byte_count_ += buffer_size_; + + *data = buffer_.get(); + *size = buffer_size_; + return buffer_size_ != 0u; +} + +void FileInputStream::BackUp(size_t count) { + if (count > buffer_offset_) { + count = buffer_offset_; + } + buffer_offset_ -= count; + total_byte_count_ -= count; +} + +size_t FileInputStream::ByteCount() const { + return total_byte_count_; +} + +bool FileInputStream::HadError() const { + return fd_ == -1; +} + +std::string FileInputStream::GetError() const { + return error_; +} + +FileOutputStream::FileOutputStream(const std::string& path, size_t buffer_capacity) + : buffer_capacity_(buffer_capacity) { + int mode = O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_BINARY; + owned_fd_.reset(TEMP_FAILURE_RETRY(::android::base::utf8::open(path.c_str(), mode, 0666))); + fd_ = owned_fd_.get(); + if (fd_ < 0) { + error_ = SystemErrorCodeToString(errno); + } else { + buffer_.reset(new uint8_t[buffer_capacity_]); + } +} + +FileOutputStream::FileOutputStream(unique_fd fd, size_t buffer_capacity) + : FileOutputStream(fd.get(), buffer_capacity) { + owned_fd_ = std::move(fd); +} + +FileOutputStream::FileOutputStream(int fd, size_t buffer_capacity) + : fd_(fd), buffer_capacity_(buffer_capacity) { + if (fd_ < 0) { + error_ = "Bad File Descriptor"; + } else { + buffer_.reset(new uint8_t[buffer_capacity_]); + } +} + +FileOutputStream::~FileOutputStream() { + // Flush the buffer. + Flush(); +} + +bool FileOutputStream::Next(void** data, size_t* size) { + if (HadError()) { + return false; + } + + if (buffer_offset_ == buffer_capacity_) { + if (!FlushImpl()) { + return false; + } + } + + const size_t buffer_size = buffer_capacity_ - buffer_offset_; + *data = buffer_.get() + buffer_offset_; + *size = buffer_size; + total_byte_count_ += buffer_size; + buffer_offset_ = buffer_capacity_; + return true; +} + +void FileOutputStream::BackUp(size_t count) { + if (count > buffer_offset_) { + count = buffer_offset_; + } + buffer_offset_ -= count; + total_byte_count_ -= count; +} + +size_t FileOutputStream::ByteCount() const { + return total_byte_count_; +} + +bool FileOutputStream::Flush() { + if (!HadError()) { + return FlushImpl(); + } + return false; +} + +bool FileOutputStream::FlushImpl() { + ssize_t n = TEMP_FAILURE_RETRY(write(fd_, buffer_.get(), buffer_offset_)); + if (n < 0) { + error_ = SystemErrorCodeToString(errno); + owned_fd_.reset(); + fd_ = -1; + buffer_.reset(); + return false; + } + + buffer_offset_ = 0u; + return true; +} + +bool FileOutputStream::HadError() const { + return fd_ == -1; +} + +std::string FileOutputStream::GetError() const { + return error_; +} + +} // namespace io +} // namespace aapt |