C++程序  |  122行  |  3.47 KB

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