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