1 /*
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
CopyFrom(const AutoCloseFILE & in)22 bool AutoCloseFILE::CopyFrom(const AutoCloseFILE& in) {
23 char buffer[8192];
24 while (!in.IsEOF()) {
25 size_t num_read = fread(buffer, 1, sizeof(buffer), in);
26 if (!num_read) {
27 if (in.IsEOF()) {
28 return true;
29 }
30 printf("%s: unable to fread %s:%d (%s)\n",
31 __FUNCTION__, __FILE__, __LINE__, strerror(errno));
32 return false;
33 }
34 size_t num_written = fwrite(buffer, 1, num_read, *this);
35 if (num_written != num_read) {
36 printf("%s: unable to fwrite, %zu != %zu %s:%d (%s)\n",
37 __FUNCTION__, num_read, num_written, __FILE__, __LINE__,
38 strerror(errno));
39 return false;
40 }
41 }
42 return true;
43 }
44
~AutoFreeBuffer()45 AutoFreeBuffer::~AutoFreeBuffer() {
46 if (data_) free(data_);
47 }
48
Clear()49 void AutoFreeBuffer::Clear() {
50 size_ = 0;
51 }
52
Reserve(size_t newsize)53 bool AutoFreeBuffer::Reserve(size_t newsize) {
54 if (newsize > reserve_size_ ||
55 reserve_size_ > kAutoBufferShrinkReserveThreshold) {
56 char* newdata = static_cast<char*>(realloc(data_, newsize));
57 // If realloc fails, everything remains unchanged.
58 if (!newdata && newsize) return false;
59
60 reserve_size_ = newsize;
61 data_ = newdata;
62 }
63 if (size_ > newsize) size_ = newsize;
64 return true;
65 }
66
Resize(size_t newsize)67 bool AutoFreeBuffer::Resize(size_t newsize) {
68 // If reservation is small, and we get a shrink request, simply reduce size_.
69 if (reserve_size_ < kAutoBufferShrinkReserveThreshold && newsize < size_) {
70 size_ = newsize;
71 return true;
72 }
73
74 if (!Reserve(newsize)) return false;
75
76 // Should we keep this? Sounds like it should be called Grow().
77 if (newsize > size_) memset(&data_[size_], 0, newsize - size_);
78 size_ = newsize;
79 return true;
80 }
81
SetToString(const char * in)82 bool AutoFreeBuffer::SetToString(const char* in) {
83 size_t newsz = strlen(in) + 1;
84 if (!Resize(newsz)) return false;
85 memcpy(data_, in, newsz);
86 return true;
87 }
88
Append(const void * new_data,size_t new_data_size)89 bool AutoFreeBuffer::Append(const void* new_data, size_t new_data_size) {
90 size_t offset = size_;
91 if (!Resize(offset + new_data_size)) return false;
92 memcpy(&data_[offset], new_data, new_data_size);
93 return true;
94 }
95
PrintF(const char * format,...)96 size_t AutoFreeBuffer::PrintF(const char* format, ... ) {
97 va_list args;
98
99 // Optimize: Use whatever reservation left we have for initial printf.
100 // If reservation is not long enough, resize and try again.
101
102 va_start(args, format);
103 size_t printf_size = vsnprintf(data_, reserve_size_, format, args);
104 va_end(args);
105
106 // vsnprintf write no more than |reserve_size_| bytes including trailing \0.
107 // Result value equal or greater than |reserve_size_| signals truncated
108 // output.
109 if (printf_size < reserve_size_) {
110 size_ = printf_size + 1;
111 return printf_size;
112 }
113
114 // Grow buffer and re-try printf.
115 if (!Resize(printf_size + 1)) return 0;
116 va_start(args, format);
117 vsprintf(data_, format, args);
118 va_end(args);
119 return printf_size;
120 }
121
122