GCC Code Coverage Report


Directory: src/gate/
File: src/gate/tech/copymachines.c
Date: 2025-09-14 13:10:38
Exec Total Coverage
Lines: 0 132 0.0%
Functions: 0 3 0.0%
Branches: 0 90 0.0%

Line Branch Exec Source
1 /* GATE PROJECT LICENSE:
2 +----------------------------------------------------------------------------+
3 | Copyright(c) 2018-2025, Stefan Meislinger |
4 | All rights reserved. |
5 | |
6 | Redistribution and use in source and binary forms, with or without |
7 | modification, are permitted provided that the following conditions are met:|
8 | |
9 | 1. Redistributions of source code must retain the above copyright notice, |
10 | this list of conditions and the following disclaimer. |
11 | 2. 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 | |
15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"|
16 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
18 | ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
19 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
20 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
21 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
22 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
23 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
24 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
25 | THE POSSIBILITY OF SUCH DAMAGE. |
26 +----------------------------------------------------------------------------+
27 */
28
29 #include "gate/tech/copymachines.h"
30 #include "gate/results.h"
31
32
33 gate_result_t gate_stream_copier_init(gate_stream_copier_config_t* config, void* user_param)
34 {
35 if (config)
36 {
37 gate_mem_clear(config, sizeof(gate_stream_copier_config_t));
38
39 config->block_size = GATE_MAX_COPYBUFFER_LENGTH;
40 config->copy_limit = 0; /* no limit */
41 config->read_offset = 0; /* at beginning */
42 config->write_offset = 0; /* at beginning */
43
44 gate_atomic_int_set(&config->cancel, 0);
45 config->user_param = user_param;
46 return GATE_RESULT_OK;
47 }
48 else
49 {
50 return GATE_RESULT_NULLPOINTER;
51 }
52 }
53
54 gate_result_t gate_stream_copier_run(gate_stream_copier_config_t* config,
55 gate_stream_t* input, gate_stream_t* output,
56 gate_stream_copier_result_t* result)
57 {
58 gate_result_t ret = GATE_RESULT_OK;
59 gate_controlstream_t* input_res = NULL;
60 gate_controlstream_t* output_res = NULL;
61 gate_int64_t new_position = 0;
62 char buffer[GATE_MAX_COPYBUFFER_LENGTH];
63 char* ptr_buffer = &buffer[0];
64 gate_size_t block_size;
65 gate_size_t block_size_backup;
66 gate_size_t next_block_size;
67 gate_size_t bytes_retrieved;
68 gate_size_t bytes_written;
69 gate_uint64_t copy_limit = 0;
70 gate_uint64_t bytes_copied = 0;
71 gate_uint64_t bytes_to_copy = 0;
72 gate_uint64_t input_position = 0;
73 gate_uint64_t output_position = 0;
74 char const* ptr_msg_buffer = NULL;
75 gate_strbuilder_t msg_builder;
76 char msg_buffer[1024];
77
78 do
79 {
80 if (!input || !output || !config)
81 {
82 return GATE_RESULT_NULLPOINTER;
83 }
84
85 if (input)
86 {
87 gate_object_retain(input);
88 }
89 if (output)
90 {
91 gate_object_retain(output);
92 }
93
94 block_size_backup = config->block_size;
95
96 if (config->block_size == 0)
97 {
98 block_size = sizeof(buffer);
99 }
100 else
101 {
102 block_size = config->block_size;
103 }
104 if (block_size > sizeof(buffer))
105 {
106 ptr_buffer = gate_mem_alloc(block_size);
107 if (ptr_buffer == NULL)
108 {
109 ret = GATE_RESULT_OUTOFMEMORY;
110 break;
111 }
112 }
113
114 if (GATE_OBJECT_IMPLEMENTS(input, GATE_INTERFACE_NAME_CONTROLSTREAM))
115 {
116 input_res = (gate_controlstream_t*)input;
117 }
118
119 if (GATE_OBJECT_IMPLEMENTS(output, GATE_INTERFACE_NAME_CONTROLSTREAM))
120 {
121 output_res = (gate_controlstream_t*)output;
122 }
123
124
125 if (config->read_offset != 0)
126 {
127 if (!input_res)
128 {
129 ret = GATE_RESULT_NOTSUPPORTED;
130 break;
131 }
132 else
133 {
134 ret = gate_stream_seek(input_res, (gate_int64_t)config->read_offset, GATE_STREAM_SEEK_BEGIN, &new_position);
135 GATE_BREAK_IF_FAILED(ret);
136 }
137 }
138
139 if (input_res)
140 {
141 ret = gate_stream_get_available(input_res, &config->total_available);
142 if (GATE_FAILED(ret))
143 {
144 config->total_available = 0;
145 }
146 }
147 else
148 {
149 config->total_available = 0;
150 }
151
152 if (config->copy_limit != 0)
153 {
154 config->total_available = config->copy_limit;
155 }
156
157
158 if (config->write_offset != 0)
159 {
160 if (!output_res)
161 {
162 ret = GATE_RESULT_NOTSUPPORTED;
163 break;
164 }
165 else
166 {
167 ret = gate_stream_seek(output_res, (gate_int64_t)config->write_offset, GATE_STREAM_SEEK_BEGIN, &new_position);
168 GATE_BREAK_IF_FAILED(ret);
169 }
170 }
171 output_position = config->write_offset;
172 copy_limit = config->copy_limit;
173 next_block_size = block_size;
174
175 while (gate_atomic_int_set(&config->cancel, 0) == 0)
176 {
177 ret = GATE_RESULT_OK;
178 if (copy_limit > 0)
179 {
180 bytes_to_copy = copy_limit - bytes_copied;
181 if (bytes_to_copy == 0)
182 {
183 /* copy job completed, limit reached */
184 break;
185 }
186 if (bytes_to_copy < block_size)
187 {
188 next_block_size = (gate_size_t)(bytes_to_copy - block_size);
189 }
190 else
191 {
192 next_block_size = block_size;
193 }
194 }
195
196 config->block_size = next_block_size;
197
198 input_position = config->read_offset + bytes_copied;
199 gate_mem_clear(ptr_buffer, next_block_size);
200 ret = gate_stream_read_block(input, ptr_buffer, next_block_size, &bytes_retrieved);
201 if (GATE_FAILED(ret))
202 {
203 /* error during read process */
204 if (config->callback)
205 {
206 gate_strbuilder_create_static(&msg_builder, msg_buffer, sizeof(msg_buffer), 0);
207 gate_strbuilder_append_cstr(&msg_builder, "Failed to read from source stream at position ");
208 gate_strbuilder_append_int64(&msg_builder, input_position);
209 gate_strbuilder_ptr(&msg_builder, 0);
210 config->callback(GATE_STREAM_COPIER_STATUS_INPUTERROR, input_position, bytes_copied,
211 ret, gate_strbuilder_ptr(&msg_builder, 0), config);
212 gate_strbuilder_release(&msg_builder);
213 }
214
215 if (!config->continue_on_read_errors || (input_res == NULL))
216 {
217 /* error cancels further execution */
218 break;
219 }
220
221 /* try to skip the block that could not be read */
222 ret = gate_stream_seek(input_res, (gate_int64_t)(input_position + next_block_size), GATE_STREAM_SEEK_BEGIN, NULL);
223 if (GATE_FAILED(ret))
224 {
225 if (config->callback)
226 {
227 config->callback(GATE_STREAM_COPIER_STATUS_INPUTERROR, input_position, bytes_copied,
228 ret, "Failed to skip gap in source stream", config);
229 }
230 /* error cancels further execution */
231 break;
232 }
233 /* ignoring read-errors -> write an empty buffer to target stream */
234 gate_mem_clear(ptr_buffer, next_block_size);
235 bytes_retrieved = next_block_size;
236 }
237
238 if (bytes_retrieved == 0)
239 {
240 /* end of stream reached */
241 break;
242 }
243
244 ret = gate_stream_write_block(output, ptr_buffer, bytes_retrieved, &bytes_written);
245 if (GATE_FAILED(ret))
246 {
247 /* error during write operation */
248 if (config->callback)
249 {
250 config->callback(GATE_STREAM_COPIER_STATUS_OUTPUTERROR, output_position, bytes_copied,
251 ret, "Failed to write to target stream", config);
252 }
253 if (!config->continue_on_write_errors || (input_res == NULL))
254 {
255 break;
256 }
257 else
258 {
259 /* try to skip block that could not be written to */
260 ret = gate_stream_seek(input_res, (gate_int64_t)(output_position + bytes_retrieved),
261 GATE_STREAM_SEEK_BEGIN, NULL);
262 if (GATE_FAILED(ret))
263 {
264 if (config->callback)
265 {
266 config->callback(GATE_STREAM_COPIER_STATUS_OUTPUTERROR,
267 output_position + bytes_retrieved, bytes_copied,
268 ret, "Failed to skip gap in target stream", config);
269 }
270 break;
271 }
272 bytes_written = bytes_retrieved;
273 }
274 }
275 output_position += bytes_written;
276
277 bytes_copied += bytes_retrieved;
278
279 if (config->callback)
280 {
281 config->callback(GATE_STREAM_COPIER_STATUS_PROGRESS, input_position, bytes_copied,
282 GATE_RESULT_OK, NULL, config);
283 }
284 }
285 } while (0);
286
287 if (output)
288 {
289 gate_object_release(output);
290 }
291 if (input)
292 {
293 gate_object_release(input);
294 }
295
296 if ((ptr_buffer != &buffer[0]) && (ptr_buffer != NULL))
297 {
298 gate_mem_dealloc(ptr_buffer);
299 }
300
301 config->block_size = block_size_backup;
302
303 if (config->callback)
304 {
305 config->callback(GATE_STREAM_COPIER_STATUS_COMPLETED, input_position, bytes_copied, ret, NULL, config);
306 }
307
308 if (result)
309 {
310 result->succeeded = GATE_SUCCEEDED(ret);
311 result->bytes_copied = bytes_copied;
312 result->error_message[0] = 0;
313 ptr_msg_buffer = gate_result_text(ret);
314 gate_str_print_text(result->error_message, sizeof(result->error_message),
315 ptr_msg_buffer, gate_str_length(ptr_msg_buffer));
316 }
317
318 return ret;
319 }
320
321 gate_result_t gate_stream_copier_cancel(gate_stream_copier_config_t* config)
322 {
323 if (config)
324 {
325 gate_atomic_int_set(&config->cancel, 1);
326 return GATE_RESULT_OK;
327 }
328 else
329 {
330 return GATE_RESULT_NULLPOINTER;
331 }
332 }
333
334