1 /*------------------------------------------------------------------------------
2 *
3 * Copyright (c) 2011-2021, EURid vzw. All rights reserved.
4 * The YADIFA TM software product is provided under the BSD 3-clause license:
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * * Neither the name of EURid nor the names of its contributors may be
16 * used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 *
31 *------------------------------------------------------------------------------
32 *
33 */
34
35 /** @defgroup streaming Streams
36 * @ingroup dnscore
37 * @brief
38 *
39 *
40 *
41 * @{
42 *
43 *----------------------------------------------------------------------------*/
44 #include "dnscore/dnscore-config.h"
45 #include <stdio.h>
46 #include <stdlib.h>
47
48 #include "dnscore/bytezarray_output_stream.h"
49 #include "dnscore/zalloc.h"
50
51 #define BYTE_ARRAY_OUTPUT_STREAM_TAG 0x534f4142 /* BAOS */
52 #define BYTE_ARRAY_OUTPUT_STREAM_DATA_TAG 0x41544144534f4142 /* BAOSDATA */
53 #define BYTE_ARRAY_OUTPUT_STREAM_BUFF_TAG 0x46465542534f4142 /* BAOSBUFF */
54
55 #define BYTEARRAY_STARTSIZE 1024
56
57 typedef struct bytezarray_output_stream_data bytezarray_output_stream_data;
58
59 /**
60 * @NOTE: if this changes, take care that bytezarray_output_stream_context in the header file has at least the SAME SIZE
61 */
62
63 struct bytezarray_output_stream_data
64 {
65 u8* buffer;
66 u32 buffer_size;
67 u32 buffer_offset;
68 u8 flags;
69 };
70
71 static ya_result
bytezarray_output_stream_write(output_stream * stream,const u8 * buffer,u32 len)72 bytezarray_output_stream_write(output_stream* stream, const u8* buffer, u32 len)
73 {
74 if(len == 0)
75 {
76 return 0;
77 }
78
79 bytezarray_output_stream_data* data = (bytezarray_output_stream_data*)stream->data;
80
81 u32 remaining = data->buffer_size - data->buffer_offset;
82
83 if(len > remaining)
84 {
85 /* Either we can resize, either we have to trunk */
86
87 if((data->flags & BYTEARRAY_DYNAMIC) != 0)
88 {
89 u8* newbuffer;
90 u32 newsize = data->buffer_size;
91
92 do
93 {
94 newsize = newsize * 2;
95 }
96 while(newsize < data->buffer_size + len);
97
98 ZALLOC_OBJECT_ARRAY_OR_DIE(newbuffer, u8, newsize, BYTE_ARRAY_OUTPUT_STREAM_TAG);
99
100 MEMCOPY(newbuffer, data->buffer, data->buffer_offset);
101
102 if((data->flags & BYTEARRAY_OWNED) != 0)
103 {
104 ZFREE_ARRAY(data->buffer, data->buffer_size);
105 }
106
107 data->buffer = newbuffer;
108 data->buffer_size = newsize;
109
110 data->flags |= BYTEARRAY_OWNED;
111 }
112 else
113 {
114 len = remaining;
115 }
116 }
117
118 MEMCOPY(&data->buffer[data->buffer_offset], buffer, len);
119 data->buffer_offset += len;
120
121 return len;
122 }
123
124 static ya_result
bytezarray_output_stream_flush(output_stream * stream)125 bytezarray_output_stream_flush(output_stream* stream)
126 {
127 (void)stream;
128
129 return SUCCESS;
130 }
131
132 static void
bytezarray_output_stream_close(output_stream * stream)133 bytezarray_output_stream_close(output_stream* stream)
134 {
135 bytezarray_output_stream_data* data = (bytezarray_output_stream_data*)stream->data;
136
137 if((data->flags & BYTEARRAY_OWNED) != 0)
138 {
139 #if DEBUG
140 memset(data->buffer, 0xe5, data->buffer_size);
141 #endif
142 ZFREE_ARRAY(data->buffer, data->buffer_size);
143 }
144
145 if((data->flags & BYTEARRAY_ZALLOC_CONTEXT) != 0)
146 {
147 ZFREE(data, bytezarray_output_stream_data);
148 }
149
150 output_stream_set_void(stream);
151 }
152
153 static const output_stream_vtbl bytezarray_output_stream_vtbl =
154 {
155 bytezarray_output_stream_write,
156 bytezarray_output_stream_flush,
157 bytezarray_output_stream_close,
158 "bytezarray_output_stream",
159 };
160
161 void
bytezarray_output_stream_init_ex_static(output_stream * out_stream,u8 * array,u32 size,u8 flags,bytezarray_output_stream_context * ctx)162 bytezarray_output_stream_init_ex_static(output_stream* out_stream, u8* array,u32 size, u8 flags, bytezarray_output_stream_context *ctx)
163 {
164 bytezarray_output_stream_data *data = (bytezarray_output_stream_data*)ctx;
165
166 if(array == NULL)
167 {
168 flags |= BYTEARRAY_OWNED;
169
170 if(size == 0)
171 {
172 flags |= BYTEARRAY_DYNAMIC;
173
174 size = BYTEARRAY_STARTSIZE;
175 }
176
177 ZALLOC_OBJECT_ARRAY_OR_DIE(array, u8, size, BYTE_ARRAY_OUTPUT_STREAM_BUFF_TAG);
178 }
179
180 data->buffer = array;
181 data->buffer_size = size;
182 data->buffer_offset = 0;
183 data->flags = flags;
184
185 out_stream->data = data;
186 out_stream->vtbl = &bytezarray_output_stream_vtbl;
187 }
188
189 void
bytezarray_output_stream_init_ex(output_stream * out_stream,u8 * array,u32 size,u8 flags)190 bytezarray_output_stream_init_ex(output_stream* out_stream, u8* array, u32 size, u8 flags)
191 {
192 bytezarray_output_stream_data* data;
193
194 ZALLOC_OBJECT_OR_DIE( data, bytezarray_output_stream_data, BYTE_ARRAY_OUTPUT_STREAM_DATA_TAG);
195
196 flags |= BYTEARRAY_ZALLOC_CONTEXT;
197
198 bytezarray_output_stream_init_ex_static(out_stream, array, size, flags, (bytezarray_output_stream_context*)data);
199 }
200
201 void
bytezarray_output_stream_init(output_stream * out_stream,u8 * array,u32 size)202 bytezarray_output_stream_init(output_stream* out_stream, u8* array, u32 size)
203 {
204 bytezarray_output_stream_init_ex(out_stream, array, size, 0);
205 }
206
207 void
bytezarray_output_stream_reset(output_stream * stream)208 bytezarray_output_stream_reset(output_stream* stream)
209 {
210 bytezarray_output_stream_data* data = (bytezarray_output_stream_data*)stream->data;
211 data->buffer_offset = 0;
212 }
213
214 u32
bytezarray_output_stream_size(output_stream * stream)215 bytezarray_output_stream_size(output_stream* stream)
216 {
217 bytezarray_output_stream_data* data = (bytezarray_output_stream_data*)stream->data;
218 return data->buffer_offset;
219 }
220
221 u32
bytezarray_output_stream_buffer_size(output_stream * stream)222 bytezarray_output_stream_buffer_size(output_stream* stream)
223 {
224 bytezarray_output_stream_data* data = (bytezarray_output_stream_data*)stream->data;
225 return data->buffer_size;
226 }
227
228 u32
bytezarray_output_stream_buffer_offset(output_stream * stream)229 bytezarray_output_stream_buffer_offset(output_stream* stream)
230 {
231 bytezarray_output_stream_data* data = (bytezarray_output_stream_data*)stream->data;
232 return data->buffer_offset;
233 }
234
235 u8*
bytezarray_output_stream_buffer(output_stream * stream)236 bytezarray_output_stream_buffer(output_stream* stream)
237 {
238 bytezarray_output_stream_data* data = (bytezarray_output_stream_data*)stream->data;
239
240 return data->buffer;
241 }
242
243 u8*
bytezarray_output_stream_detach(output_stream * stream)244 bytezarray_output_stream_detach(output_stream* stream)
245 {
246 bytezarray_output_stream_data* data = (bytezarray_output_stream_data*)stream->data;
247
248 data->flags &= ~BYTEARRAY_OWNED;
249
250 return data->buffer;
251 }
252
253 void
bytezarray_output_stream_set(output_stream * stream,u8 * buffer,u32 buffer_size,bool owned)254 bytezarray_output_stream_set(output_stream* stream, u8 *buffer, u32 buffer_size, bool owned)
255 {
256 bytezarray_output_stream_data* data = (bytezarray_output_stream_data*)stream->data;
257 if((data->buffer != buffer) && ((data->flags & BYTEARRAY_OWNED) != 0))
258 {
259 ZFREE_ARRAY(data->buffer, data->buffer_size);
260 }
261 data->buffer = buffer;
262 data->buffer_offset = buffer_size;
263 data->buffer_size = buffer_size;
264 data->flags = (data->flags & BYTEARRAY_ZALLOC_CONTEXT) | ((owned)?BYTEARRAY_OWNED:0);
265 }
266
267 /** @} */
268