blob: a57c968989769750b15facfefaeddfab620a5330 [file] [log] [blame]
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -07001/*
2 * Copyright (C) 2016 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#include "common/libs/auto_resources/auto_resources.h"
17
18#include <errno.h>
19#include <stdlib.h>
20#include <string.h>
21
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -070022AutoFreeBuffer::~AutoFreeBuffer() {
23 if (data_) free(data_);
24}
25
26void AutoFreeBuffer::Clear() {
27 size_ = 0;
28}
29
30bool AutoFreeBuffer::Reserve(size_t newsize) {
31 if (newsize > reserve_size_ ||
32 reserve_size_ > kAutoBufferShrinkReserveThreshold) {
33 char* newdata = static_cast<char*>(realloc(data_, newsize));
34 // If realloc fails, everything remains unchanged.
35 if (!newdata && newsize) return false;
36
37 reserve_size_ = newsize;
38 data_ = newdata;
39 }
40 if (size_ > newsize) size_ = newsize;
41 return true;
42}
43
44bool AutoFreeBuffer::Resize(size_t newsize) {
45 // If reservation is small, and we get a shrink request, simply reduce size_.
46 if (reserve_size_ < kAutoBufferShrinkReserveThreshold && newsize < size_) {
47 size_ = newsize;
48 return true;
49 }
50
51 if (!Reserve(newsize)) return false;
52
53 // Should we keep this? Sounds like it should be called Grow().
54 if (newsize > size_) memset(&data_[size_], 0, newsize - size_);
55 size_ = newsize;
56 return true;
57}
58
59bool AutoFreeBuffer::SetToString(const char* in) {
60 size_t newsz = strlen(in) + 1;
61 if (!Resize(newsz)) return false;
62 memcpy(data_, in, newsz);
63 return true;
64}
65
66bool AutoFreeBuffer::Append(const void* new_data, size_t new_data_size) {
67 size_t offset = size_;
68 if (!Resize(offset + new_data_size)) return false;
69 memcpy(&data_[offset], new_data, new_data_size);
70 return true;
71}
72
73size_t AutoFreeBuffer::PrintF(const char* format, ... ) {
74 va_list args;
75
76 // Optimize: Use whatever reservation left we have for initial printf.
77 // If reservation is not long enough, resize and try again.
78
79 va_start(args, format);
80 size_t printf_size = vsnprintf(data_, reserve_size_, format, args);
81 va_end(args);
82
83 // vsnprintf write no more than |reserve_size_| bytes including trailing \0.
84 // Result value equal or greater than |reserve_size_| signals truncated
85 // output.
86 if (printf_size < reserve_size_) {
87 size_ = printf_size + 1;
88 return printf_size;
89 }
90
91 // Grow buffer and re-try printf.
92 if (!Resize(printf_size + 1)) return 0;
93 va_start(args, format);
94 vsprintf(data_, format, args);
95 va_end(args);
96 return printf_size;
97}
98