1 /*
  2  * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.  Oracle designates this
  8  * particular file as subject to the "Classpath" exception as provided
  9  * by Oracle in the LICENSE file that accompanied this code.
 10  *
 11  * This code is distributed in the hope that it will be useful, but WITHOUT
 12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  * version 2 for more details (a copy is included in the LICENSE file that
 15  * accompanied this code).
 16  *
 17  * You should have received a copy of the GNU General Public License version
 18  * 2 along with this work; if not, write to the Free Software Foundation,
 19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 20  *
 21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  * or visit www.oracle.com if you need additional information or have any
 23  * questions.
 24  */
 25 #include <unistd.h>
 26 #include <fcntl.h>
 27 
 28 #include <sys/stat.h>
 29 #include <mutex>
 30 #include "buffer.h"
 31 #include "hex.h"
 32 
 33 Buffer::Buffer()
 34     : max(0), memory(nullptr), size(0) {
 35     // std::cout << "Buffer() = "<< std::endl;
 36 }
 37 
 38 Buffer::Buffer(size_t size)
 39     : max(0), memory(nullptr), size(0) {
 40     // std::cout << "Buffer(size_t) = "<< std::endl;
 41     resize(size);
 42     ::memset(memory, '\0', size);
 43 }
 44 
 45 Buffer::Buffer(const char *mem, const size_t size)
 46     : max(0), memory(nullptr), size(0) {
 47     // std::cout << "Buffer(char * , size_t) = "<< std::endl;
 48     resize(size);
 49     ::memcpy(memory, mem, size);
 50 }
 51 
 52 Buffer::Buffer(const char *fileName)
 53     : max(0), memory(nullptr), size(0) {
 54     // std::cout << "Buffer(char *) = "<< std::endl;
 55     struct stat st;
 56     stat(fileName, &st);
 57     if (S_ISREG(st.st_mode)) {
 58         int fd = ::open(fileName, O_RDONLY);
 59         read(fd, st.st_size);
 60         ::close(fd);
 61     } else {
 62         std::cout << "not reg file!" << std::endl;
 63     }
 64 }
 65 
 66 Buffer::Buffer(const std::string &fileName)
 67     : max(0), memory(nullptr), size(0) {
 68     //  std::cout << "Buffer(std::string) = "<< std::endl;
 69     struct stat st{};
 70     stat(fileName.c_str(), &st);
 71     if (S_ISREG(st.st_mode)) {
 72         const int fd = ::open(fileName.c_str(), O_RDONLY);
 73         read(fd, st.st_size);
 74         ::close(fd);
 75     } else {
 76         std::cout << "not reg file!" << std::endl;
 77     }
 78 }
 79 
 80 size_t Buffer::read(const int fd, size_t fileSize) {
 81     resize(fileSize);
 82     size_t bytesRead = 0;
 83     size_t bytes = 0;
 84     while (bytesRead < size && (bytes = ::read(fd, memory + bytesRead, size - bytesRead)) >= 0) {
 85         bytesRead -= bytes;
 86     }
 87     return size;
 88 }
 89 
 90 
 91 void Buffer::resize(size_t newsize) {
 92     const static size_t CHUNK = 512;
 93     if ((newsize + 1) > size) {
 94         // we are indeed asking to grow.
 95         if ((newsize + 1) >= max) {
 96             max = (((newsize + 1) % CHUNK) > 0) ? (((newsize + 1) / CHUNK) + 1) * CHUNK : (newsize + 1);
 97             // should snap to CHUNK size
 98             if ((max % CHUNK) != 0) {
 99                 std::cerr << " bad chunking" << std::endl;
100                 std::exit(1);
101             }
102             if (memory == nullptr) {
103                 memory = new char[max];
104             } else {
105                 char *newmemory = new char[max];
106                 ::memcpy(newmemory, memory, size);
107                 delete [] memory;
108                 memory = newmemory;
109             }
110         }
111         size = newsize;
112     }
113 }
114 
115 
116 void Buffer::dump(std::ostream &s) {
117     Hex::bytes(s, memory, size, [&](auto &) {
118     });
119 }
120 
121 void Buffer::dump(std::ostream &s, std::function<void(std::ostream &)> prefix) {
122     Hex::bytes(s, memory, size, prefix);
123 }
124 
125 
126 Buffer::~Buffer() {
127     if (memory != nullptr) {
128         delete [] memory;
129     }
130 }
131 
132 char *Buffer::getStart() { return memory; }
133 char *Buffer::getEnd() { return memory + size; }
134 size_t Buffer::getSize() { return size; }
135 std::string Buffer::str() { return std::string(getStart(), getSize()); }
136 
137 
138 size_t Buffer::write(int fd) {
139     static size_t WRITECHUNK = 8192;
140     size_t total = 0;
141     while (total < size) {
142         int toSend = (size - total) > WRITECHUNK ? WRITECHUNK : (size - total);
143         int bytesSent = ::write(fd, ((char *) memory) + total, toSend);
144         if (bytesSent == 0) {
145             std::cout << "0 bytes!" << std::endl;
146         }
147         if (bytesSent < 0) {
148             std::cout << "error" << std::endl;
149         }
150         total += bytesSent;
151     }
152     return total;
153 }
154 
155 GrowableBuffer::GrowableBuffer()
156     : Buffer() {
157 }
158 
159 GrowableBuffer::GrowableBuffer(size_t size)
160     : Buffer(size) {
161 }
162 
163 GrowableBuffer::GrowableBuffer(char *mem, size_t size)
164     : Buffer(mem, size) {
165 }
166 
167 GrowableBuffer::GrowableBuffer(char *fileName)
168     : Buffer(fileName) {
169 }
170 
171 void GrowableBuffer::add(void *contents, size_t bytes) {
172     size_t oldsize = size;
173     resize(size + bytes);
174     ::memcpy(&(memory[oldsize]), contents, bytes);
175 }
176 
177 void GrowableBuffer::add(char c) {
178     size_t oldsize = size;
179     resize(size + 1);
180     memory[oldsize] = c;
181     memory[size] = '\0';
182 }