| /* |
| * Copyright (C) 2016 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 "common/libs/auto_resources/auto_resources.h" |
| |
| #include <errno.h> |
| #include <stdlib.h> |
| #include <string.h> |
| |
| bool AutoCloseFILE::CopyFrom(const AutoCloseFILE& in) { |
| char buffer[8192]; |
| while (!in.IsEOF()) { |
| size_t num_read = fread(buffer, 1, sizeof(buffer), in); |
| if (!num_read) { |
| if (in.IsEOF()) { |
| return true; |
| } |
| printf("%s: unable to fread %s:%d (%s)\n", |
| __FUNCTION__, __FILE__, __LINE__, strerror(errno)); |
| return false; |
| } |
| size_t num_written = fwrite(buffer, 1, num_read, *this); |
| if (num_written != num_read) { |
| printf("%s: unable to fwrite, %zu != %zu %s:%d (%s)\n", |
| __FUNCTION__, num_read, num_written, __FILE__, __LINE__, |
| strerror(errno)); |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| AutoFreeBuffer::~AutoFreeBuffer() { |
| if (data_) free(data_); |
| } |
| |
| void AutoFreeBuffer::Clear() { |
| size_ = 0; |
| } |
| |
| bool AutoFreeBuffer::Reserve(size_t newsize) { |
| if (newsize > reserve_size_ || |
| reserve_size_ > kAutoBufferShrinkReserveThreshold) { |
| char* newdata = static_cast<char*>(realloc(data_, newsize)); |
| // If realloc fails, everything remains unchanged. |
| if (!newdata && newsize) return false; |
| |
| reserve_size_ = newsize; |
| data_ = newdata; |
| } |
| if (size_ > newsize) size_ = newsize; |
| return true; |
| } |
| |
| bool AutoFreeBuffer::Resize(size_t newsize) { |
| // If reservation is small, and we get a shrink request, simply reduce size_. |
| if (reserve_size_ < kAutoBufferShrinkReserveThreshold && newsize < size_) { |
| size_ = newsize; |
| return true; |
| } |
| |
| if (!Reserve(newsize)) return false; |
| |
| // Should we keep this? Sounds like it should be called Grow(). |
| if (newsize > size_) memset(&data_[size_], 0, newsize - size_); |
| size_ = newsize; |
| return true; |
| } |
| |
| bool AutoFreeBuffer::SetToString(const char* in) { |
| size_t newsz = strlen(in) + 1; |
| if (!Resize(newsz)) return false; |
| memcpy(data_, in, newsz); |
| return true; |
| } |
| |
| bool AutoFreeBuffer::Append(const void* new_data, size_t new_data_size) { |
| size_t offset = size_; |
| if (!Resize(offset + new_data_size)) return false; |
| memcpy(&data_[offset], new_data, new_data_size); |
| return true; |
| } |
| |
| size_t AutoFreeBuffer::PrintF(const char* format, ... ) { |
| va_list args; |
| |
| // Optimize: Use whatever reservation left we have for initial printf. |
| // If reservation is not long enough, resize and try again. |
| |
| va_start(args, format); |
| size_t printf_size = vsnprintf(data_, reserve_size_, format, args); |
| va_end(args); |
| |
| // vsnprintf write no more than |reserve_size_| bytes including trailing \0. |
| // Result value equal or greater than |reserve_size_| signals truncated |
| // output. |
| if (printf_size < reserve_size_) { |
| size_ = printf_size + 1; |
| return printf_size; |
| } |
| |
| // Grow buffer and re-try printf. |
| if (!Resize(printf_size + 1)) return 0; |
| va_start(args, format); |
| vsprintf(data_, format, args); |
| va_end(args); |
| return printf_size; |
| } |
| |