/*
* 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;
}