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/shared-heap.h"
49 #include "dnscore/shared-heap-bytearray-output-stream.h"
50 
51 #include "dnscore/zalloc.h"
52 
53 #define BYTE_ARRAY_OUTPUT_STREAM_DATA_TAG 0x41544144534f4853 /* SHOSDATA */
54 
55 #define SHARED_HEAP_STARTSIZE 48
56 
57 typedef struct shared_heap_output_stream_data shared_heap_output_stream_data;
58 
59 /**
60  * @NOTE: if this changes, take care that shared_heap_output_stream_context in the header file has at least the SAME SIZE
61  */
62 
63 struct shared_heap_output_stream_data
64 {
65     u8* buffer;
66     u32 buffer_size;
67     u32 buffer_offset;
68     u8 flags;
69     u8 id;
70 };
71 
72 static ya_result
shared_heap_output_stream_write(output_stream * stream,const u8 * buffer,u32 len)73 shared_heap_output_stream_write(output_stream* stream, const u8* buffer, u32 len)
74 {
75     if(len == 0)
76     {
77         return 0;
78     }
79 
80     shared_heap_output_stream_data* data = (shared_heap_output_stream_data*)stream->data;
81 
82     u32 remaining = data->buffer_size - data->buffer_offset;
83     /*
84     1;48    -> 48
85     49;112  -> 112
86     */
87     if(len > remaining)
88     {
89         /* Either we can resize, either we have to trunk */
90 
91         if((data->flags & SHARED_HEAP_DYNAMIC) != 0)
92         {
93             u8* newbuffer;
94             u32 newsize = (((data->buffer_offset + len) + 16 + 63) & ~63) - 16;
95 
96             newbuffer = (u8*)shared_heap_wait_alloc(data->id, newsize);
97             MEMCOPY(newbuffer, data->buffer, data->buffer_offset);
98 
99             if((data->flags & SHARED_HEAP_OWNED) != 0)
100             {
101                 shared_heap_free(data->buffer);
102             }
103 
104             data->buffer = newbuffer;
105             data->buffer_size = newsize;
106 
107             data->flags |= SHARED_HEAP_OWNED;
108         }
109         else
110         {
111             len = remaining;
112         }
113     }
114 
115     MEMCOPY(&data->buffer[data->buffer_offset], buffer, len);
116     data->buffer_offset += len;
117 
118     return len;
119 }
120 
121 static ya_result
shared_heap_output_stream_flush(output_stream * stream)122 shared_heap_output_stream_flush(output_stream* stream)
123 {
124     (void)stream;
125     return SUCCESS;
126 }
127 
128 static void
shared_heap_output_stream_close(output_stream * stream)129 shared_heap_output_stream_close(output_stream* stream)
130 {
131     shared_heap_output_stream_data* data = (shared_heap_output_stream_data*)stream->data;
132 
133     if((data->flags & SHARED_HEAP_OWNED) != 0)
134     {
135 #if DEBUG
136         memset(data->buffer, 0xe5, data->buffer_size);
137 #endif
138         shared_heap_free(data->buffer);
139     }
140 
141     if((data->flags & SHARED_HEAP_ZALLOC_CONTEXT) != 0)
142     {
143         ZFREE_OBJECT(data);
144     }
145 
146     output_stream_set_void(stream);
147 }
148 
149 static const output_stream_vtbl shared_heap_output_stream_vtbl =
150 {
151     shared_heap_output_stream_write,
152     shared_heap_output_stream_flush,
153     shared_heap_output_stream_close,
154     "shared_heap_output_stream",
155 };
156 
157 void
shared_heap_output_stream_init_ex_static(output_stream * out_stream,u8 id,u8 * array,u32 size,u8 flags,shared_heap_output_stream_context * ctx)158 shared_heap_output_stream_init_ex_static(output_stream* out_stream, u8 id, u8* array,u32 size, u8 flags, shared_heap_output_stream_context *ctx)
159 {
160     shared_heap_output_stream_data *data = (shared_heap_output_stream_data*)ctx;
161 
162     if(array == NULL)
163     {
164         flags |= SHARED_HEAP_OWNED;
165 
166         if(size == 0)
167         {
168             flags |= SHARED_HEAP_DYNAMIC;
169 
170             size = SHARED_HEAP_STARTSIZE;
171         }
172         else
173         {
174             // size = ((size + 63) & ~63) - 16;
175         }
176 
177         array = (u8*)shared_heap_wait_alloc(id, size);
178     }
179 
180     data->buffer = array;
181     data->buffer_size = size;
182     data->buffer_offset = 0;
183     data->flags = flags;
184     data->id = id;
185 
186     out_stream->data = data;
187     out_stream->vtbl = &shared_heap_output_stream_vtbl;
188 }
189 
190 void
shared_heap_output_stream_try_init_ex_static(output_stream * out_stream,u8 id,u8 * array,u32 size,u8 flags,shared_heap_output_stream_context * ctx)191 shared_heap_output_stream_try_init_ex_static(output_stream* out_stream, u8 id, u8* array,u32 size, u8 flags, shared_heap_output_stream_context *ctx)
192 {
193     shared_heap_output_stream_data *data = (shared_heap_output_stream_data*)ctx;
194 
195     if(array == NULL)
196     {
197         flags |= SHARED_HEAP_OWNED;
198 
199         if(size == 0)
200         {
201             flags |= SHARED_HEAP_DYNAMIC;
202 
203             size = SHARED_HEAP_STARTSIZE;
204         }
205         else
206         {
207             // size = ((size + 63) & ~63) - 16;
208         }
209 
210         array = (u8*)shared_heap_try_alloc(id, size);
211     }
212 
213     data->buffer = array;
214     data->buffer_size = size;
215     data->buffer_offset = 0;
216     data->flags = flags;
217     data->id = id;
218 
219     out_stream->data = data;
220     out_stream->vtbl = &shared_heap_output_stream_vtbl;
221 }
222 
223 void
shared_heap_output_stream_init_ex(output_stream * out_stream,u8 id,u8 * array,u32 size,u8 flags)224 shared_heap_output_stream_init_ex(output_stream* out_stream, u8 id, u8* array, u32 size, u8 flags)
225 {
226     shared_heap_output_stream_data* data;
227 
228     ZALLOC_OBJECT_OR_DIE( data, shared_heap_output_stream_data, BYTE_ARRAY_OUTPUT_STREAM_DATA_TAG);
229 
230     array = (u8*)shared_heap_wait_alloc(id, size);
231     flags |= SHARED_HEAP_ZALLOC_CONTEXT;
232 
233     shared_heap_output_stream_init_ex_static(out_stream, id, array, size, flags, (shared_heap_output_stream_context*)data);
234 }
235 
236 void
shared_heap_output_stream_init(output_stream * out_stream,u8 id,u8 * array,u32 size)237 shared_heap_output_stream_init(output_stream* out_stream, u8 id, u8* array, u32 size)
238 {
239     shared_heap_output_stream_init_ex(out_stream, id, array, size, 0);
240 }
241 
242 void
shared_heap_output_stream_reset(output_stream * stream)243 shared_heap_output_stream_reset(output_stream* stream)
244 {
245     shared_heap_output_stream_data* data = (shared_heap_output_stream_data*)stream->data;
246     data->buffer_offset = 0;
247 }
248 
249 u32
shared_heap_output_stream_size(output_stream * stream)250 shared_heap_output_stream_size(output_stream* stream)
251 {
252     shared_heap_output_stream_data* data = (shared_heap_output_stream_data*)stream->data;
253     return data->buffer_offset;
254 }
255 
256 u32
shared_heap_output_stream_buffer_size(output_stream * stream)257 shared_heap_output_stream_buffer_size(output_stream* stream)
258 {
259     shared_heap_output_stream_data* data = (shared_heap_output_stream_data*)stream->data;
260     return data->buffer_size;
261 }
262 
263 u8*
shared_heap_output_stream_buffer(output_stream * stream)264 shared_heap_output_stream_buffer(output_stream* stream)
265 {
266     shared_heap_output_stream_data* data = (shared_heap_output_stream_data*)stream->data;
267 
268     return data->buffer;
269 }
270 
271 u8*
shared_heap_output_stream_detach(output_stream * stream)272 shared_heap_output_stream_detach(output_stream* stream)
273 {
274     shared_heap_output_stream_data* data = (shared_heap_output_stream_data*)stream->data;
275 
276     data->flags &= ~SHARED_HEAP_OWNED;
277 
278     return data->buffer;
279 }
280 
281 
282 
283 /** @} */
284