source: mainline/uspace/app/bithenge/blob.c@ 50985c34

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 50985c34 was ce683ed3, checked in by Sean Bartell <wingedtachikoma@…>, 13 years ago

bithenge: add blobs created from memory buffers

  • Property mode set to 100644
File size: 8.0 KB
Line 
1/*
2 * Copyright (c) 2012 Sean Bartell
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup bithenge
30 * @{
31 */
32/**
33 * @file
34 * Raw binary blobs.
35 */
36
37#include <assert.h>
38#include <bool.h>
39#include <errno.h>
40#include <macros.h>
41#include <mem.h>
42#include <stdlib.h>
43#include "blob.h"
44
45/** Initialize a random access blob.
46 * @memberof bithenge_blob_t
47 * @param[out] blob The blob to initialize.
48 * @param[in] ops Operations providing random access support. This pointer must
49 * be valid until the blob is destroyed.
50 * @return EOK on success or an error code from errno.h.
51 */
52int bithenge_new_random_access_blob(bithenge_blob_t *blob,
53 const bithenge_random_access_blob_ops_t *ops)
54{
55 assert(blob);
56 assert(ops);
57 assert(ops->destroy);
58 assert(ops->read);
59 assert(ops->size);
60
61 blob->ops = ops;
62 return EOK;
63}
64
65static int sequential_buffer(bithenge_sequential_blob_t *blob, aoff64_t end)
66{
67 bool need_realloc = false;
68 while (end > blob->buffer_size) {
69 blob->buffer_size = max(4096, 2 * blob->buffer_size);
70 need_realloc = true;
71 }
72 if (need_realloc) {
73 char *buffer = realloc(blob->buffer, blob->buffer_size);
74 if (!buffer)
75 return ENOMEM;
76 blob->buffer = buffer;
77 }
78 aoff64_t size = end - blob->data_size;
79 int rc = blob->ops->read(blob, blob->buffer + blob->data_size, &size);
80 if (rc != EOK)
81 return rc;
82 blob->data_size += size;
83 return EOK;
84}
85
86static inline bithenge_sequential_blob_t *sequential_from_blob(
87 bithenge_blob_t *base)
88{
89 return (bithenge_sequential_blob_t *)base;
90}
91
92static inline bithenge_blob_t *blob_from_sequential(
93 bithenge_sequential_blob_t *blob)
94{
95 return &blob->base;
96}
97
98static int sequential_size(bithenge_blob_t *base, aoff64_t *size)
99{
100 bithenge_sequential_blob_t *blob = sequential_from_blob(base);
101 int rc;
102 if (blob->ops->size) {
103 rc = blob->ops->size(blob, size);
104 if (rc == EOK)
105 return EOK;
106 }
107 rc = sequential_buffer(blob, blob->buffer_size);
108 if (rc != EOK)
109 return rc;
110 while (blob->data_size == blob->buffer_size) {
111 rc = sequential_buffer(blob, 2 * blob->buffer_size);
112 if (rc != EOK)
113 return rc;
114 }
115 *size = blob->data_size;
116 return EOK;
117}
118
119static int sequential_read(bithenge_blob_t *base, aoff64_t offset,
120 char *buffer, aoff64_t *size)
121{
122 bithenge_sequential_blob_t *blob = sequential_from_blob(base);
123 aoff64_t end = offset + *size;
124 if (end > blob->data_size) {
125 int rc = sequential_buffer(blob, end);
126 if (rc != EOK)
127 return rc;
128 }
129 if (offset > blob->data_size)
130 return EINVAL;
131 *size = min(*size, blob->data_size - end);
132 memcpy(buffer, blob->buffer + offset, *size);
133 return EOK;
134}
135
136static int sequential_destroy(bithenge_blob_t *base)
137{
138 bithenge_sequential_blob_t *blob = sequential_from_blob(base);
139 free(blob->buffer);
140 return blob->ops->destroy(blob);
141}
142
143static const bithenge_random_access_blob_ops_t sequential_ops = {
144 .size = sequential_size,
145 .read = sequential_read,
146 .destroy = sequential_destroy,
147};
148
149/** Initialize a sequential blob.
150 * @memberof bithenge_sequential_blob_t
151 * @param[out] blob The blob to initialize.
152 * @param[in] ops Operations providing sequential access support. This pointer
153 * must be valid until the blob is destroyed.
154 * @return EOK on success or an error code from errno.h.
155 */
156int bithenge_new_sequential_blob(bithenge_sequential_blob_t *blob,
157 const bithenge_sequential_blob_ops_t *ops)
158{
159 assert(blob);
160 assert(ops);
161 assert(ops->destroy);
162 assert(ops->read);
163 // ops->size is optional
164
165 int rc = bithenge_new_random_access_blob(blob_from_sequential(blob),
166 &sequential_ops);
167 if (rc != EOK)
168 return rc;
169 blob->ops = ops;
170 blob->buffer = NULL; // realloc(NULL, ...) works like malloc
171 blob->buffer_size = 0;
172 blob->data_size = 0;
173 return EOK;
174}
175
176typedef struct {
177 bithenge_blob_t base;
178 const char *buffer;
179 size_t size;
180 bool needs_free;
181} memory_blob_t;
182
183static inline memory_blob_t *memory_from_blob(bithenge_blob_t *base)
184{
185 return (memory_blob_t *)base;
186}
187
188static inline bithenge_blob_t *blob_from_memory(memory_blob_t *blob)
189{
190 return &blob->base;
191}
192
193static int memory_size(bithenge_blob_t *base, aoff64_t *size)
194{
195 memory_blob_t *blob = memory_from_blob(base);
196 *size = blob->size;
197 return EOK;
198}
199
200static int memory_read(bithenge_blob_t *base, aoff64_t offset, char *buffer,
201 aoff64_t *size)
202{
203 memory_blob_t *blob = memory_from_blob(base);
204 if (offset > blob->size)
205 return ELIMIT;
206 *size = min(*size, blob->size - offset);
207 memcpy(buffer, blob->buffer + offset, *size);
208 return EOK;
209}
210
211static int memory_destroy(bithenge_blob_t *base)
212{
213 memory_blob_t *blob = memory_from_blob(base);
214 if (blob->needs_free)
215 free(blob->buffer);
216 free(blob);
217 return EOK;
218}
219
220static const bithenge_random_access_blob_ops_t memory_ops = {
221 .size = memory_size,
222 .read = memory_read,
223 .destroy = memory_destroy,
224};
225
226/** Create a blob from data. Unlike with @a
227 * bithenge_blob_t::bithenge_new_blob_from_buffer, the data is copied into a
228 * new buffer and the original data can be changed after this call. The blob
229 * must be freed with @a bithenge_blob_t::bithenge_blob_destroy after it is
230 * used.
231 * @memberof bithenge_blob_t
232 * @param[out] out Stores the created blob.
233 * @param[in] data The data.
234 * @param len The length of the data.
235 * @return EOK on success or an error code from errno.h. */
236int bithenge_new_blob_from_data(bithenge_blob_t **out, const void *data,
237 size_t len)
238{
239 int rc;
240 assert(data || !len);
241
242 memory_blob_t *blob = malloc(sizeof(*blob));
243 if (!blob)
244 return ENOMEM;
245 rc = bithenge_new_random_access_blob(blob_from_memory(blob),
246 &memory_ops);
247 if (rc != EOK) {
248 free(blob);
249 return rc;
250 }
251 char *buffer = malloc(len);
252 if (!buffer) {
253 free(blob);
254 return rc;
255 }
256 memcpy(buffer, data, len);
257 blob->buffer = buffer;
258 blob->size = len;
259 blob->needs_free = true;
260 *out = blob_from_memory(blob);
261 return EOK;
262}
263
264/** Create a blob from a buffer. The buffer must exist as long as the blob
265 * does. The blob must be freed with @a bithenge_blob_t::bithenge_blob_destroy
266 * after it is used.
267 * @memberof bithenge_blob_t
268 * @param[out] out Stores the created blob.
269 * @param[in] buffer The buffer, which must not be changed until the blob is
270 * destroyed.
271 * @param len The length of the data.
272 * @param needs_free Whether the buffer should be freed with free() when the
273 * blob is destroyed.
274 * @return EOK on success or an error code from errno.h. */
275int bithenge_new_blob_from_buffer(bithenge_blob_t **out, const void *buffer,
276 size_t len, bool needs_free)
277{
278 int rc;
279 assert(buffer || !len);
280
281 memory_blob_t *blob = malloc(sizeof(*blob));
282 if (!blob)
283 return ENOMEM;
284 rc = bithenge_new_random_access_blob(blob_from_memory(blob),
285 &memory_ops);
286 if (rc != EOK) {
287 free(blob);
288 return rc;
289 }
290 blob->buffer = buffer;
291 blob->size = len;
292 blob->needs_free = needs_free;
293 *out = blob_from_memory(blob);
294 return EOK;
295}
296
297/** @}
298 */
Note: See TracBrowser for help on using the repository browser.