1 /*
2 Copyright (C) 2015-2021, Dirk Krause
3 SPDX-License-Identifier: BSD-3-Clause
4 */
5
6 /*
7 WARNING: This file was generated by the dkct program (see
8 http://dktools.sourceforge.net/ for details).
9 Changes you make here will be lost if dkct is run again!
10 You should modify the original source and run dkct on it.
11 Original source: dk4strm.ctr
12 */
13
14 /** @file dk4strm.c The dk4strm module.
15 */
16
17
18
19
20 #include "dk4conf.h"
21 #include <libdk4c/dk4strm.h>
22 #include <libdk4base/dk4mem.h>
23 #include <libdk4c/dk4enc.h>
24 #include <libdk4base/dk4numco.h>
25
26 #if DK4_HAVE_ASSERT_H
27 #ifndef ASSERT_H_INCLUDED
28 #include <assert.h>
29 #define ASSERT_H_INCLUDED 1
30 #endif
31 #endif
32
33
34
35
36
37
38
39 static
40 void
dk4stream_api_init(dk4_stream_api_t * ptr)41 dk4stream_api_init(dk4_stream_api_t *ptr)
42 {
43
44 #if DK4_USE_ASSERT
45 assert(NULL != ptr);
46 #endif
47 DK4_MEMRES(ptr, sizeof(dk4_stream_api_t));
48 ptr->d = NULL;
49 ptr->b = NULL;
50 ptr->sz_in = 0;
51 ptr->sz_out = 0;
52 ptr->res = 0;
53 ptr->cmd = 0;
54
55 }
56
57
58
59 /** Release memory allocated by a stream.
60 @param strm Stream to release.
61 */
62 static
63 void
dk4stream_release_memory(dk4_stream_t * strm)64 dk4stream_release_memory(dk4_stream_t *strm)
65 {
66
67 #if DK4_USE_ASSERT
68 assert(NULL != strm);
69 #endif
70 if (NULL != strm) {
71 dk4mem_release(strm->bi);
72 dk4mem_release(strm->bo);
73 strm->d = NULL;
74 strm->fct = NULL;
75 strm->bwr = (dk4_um_t)0UL;
76 strm->szbi = 0;
77 strm->szbo = 0;
78 strm->usbi = 0;
79 strm->usbo = 0;
80 strm->rebi = 0;
81 strm->fl = 0;
82 strm->feoi = 0;
83 strm->bwo = 0;
84 dk4mem_free(strm);
85 }
86 }
87
88
89
90
91 /** Flush write buffer.
92 */
93 static
94 int
dk4stream_i_flush_write(dk4_stream_t * strm,int flfl,dk4_er_t * erp)95 dk4stream_i_flush_write(dk4_stream_t *strm, int flfl, dk4_er_t *erp)
96 {
97 dk4_stream_api_t api;
98 int back = 1;
99
100 /* Write buffer contents (if any) downwards.
101 */
102 #if DK4_USE_ASSERT
103 assert(NULL != strm);
104 #endif
105 if (0 != strm->usbo) {
106 dk4stream_api_init(&api);
107 api.cmd = DK4_STREAM_API_WRITE;
108 api.d = strm->d;
109 api.b = strm->bo;
110 api.sz_in = strm->usbo;
111 (*(strm->fct))(&api);
112 if (0 == api.res) {
113 back = 0;
114 dk4error_set_simple_error_code(erp, DK4_E_WRITE_FAILED);
115 }
116 }
117 /* Flush downwards.
118 */
119 if (0 < flfl) {
120 dk4stream_api_init(&api);
121 api.cmd = DK4_STREAM_API_FLUSH;
122 api.d = strm->d;
123 (*(strm->fct))(&api);
124 if (0 == api.res) {
125 back = 0;
126 dk4error_set_simple_error_code(erp, DK4_E_FLUSH_FAILED);
127 }
128 }
129 /* Indicate output buffer is empty.
130 */
131 strm->usbo = 0;
132
133 return back;
134 }
135
136
137
138 /** Internal function to write one character after checking stream.
139 @param strm Stream to write to.
140 @param c Character to write.
141 @param erp Error report, may be NULL.
142 @return 1 on success, 0 on error.
143 */
144 static
145 int
dk4stream_i_write_byte(dk4_stream_t * strm,char c,dk4_er_t * erp)146 dk4stream_i_write_byte(dk4_stream_t *strm, char c, dk4_er_t *erp)
147 {
148 int back = 0;
149
150 #if DK4_USE_ASSERT
151 assert(NULL != strm);
152 #endif
153 if (strm->usbo < strm->szbo) {
154 (strm->bo)[strm->usbo] = c;
155 strm->usbo += 1;
156 strm->bwr += (dk4_um_t)1UL;
157 if ((dk4_um_t)0UL == strm->bwr) { strm->bwo = 1; }
158 back = 1;
159 if (strm->usbo >= strm->szbo) {
160 back = dk4stream_i_flush_write(strm, 0, erp);
161 }
162 }
163 return back;
164 }
165
166
167
168
169 /** Internal function to read a single character.
170 @param dst Pointer to variable for result.
171 @param strm Stream to read from.
172 @return 1 on success, 0 on error.
173 */
174 static
175 int
dk4stream_i_c8_read_byte(char * dst,dk4_stream_t * strm)176 dk4stream_i_c8_read_byte(char *dst, dk4_stream_t *strm)
177 {
178 dk4_stream_api_t api;
179 int back = 0;
180 #if DK4_USE_ASSERT
181 assert(NULL != strm);
182 assert(NULL != dst);
183 #endif
184
185 if ((0 == strm->feoi) && ((strm->usbi == 0) || (strm->rebi >= strm->usbi))) {
186
187 dk4stream_api_init(&api);
188 api.cmd = DK4_STREAM_API_READ;
189 api.d = strm->d;
190 api.b = strm->bi;
191 api.sz_in = strm->szbi;
192 (*(strm->fct))(&api);
193 if (0 != api.res) {
194 strm->rebi = 0;
195 strm->usbi = api.sz_out;
196 if (api.sz_out < strm->szbi) {
197 if (0 == strm->zreof) {
198 dk4stream_api_init(&api);
199 api.cmd = DK4_STREAM_API_AT_END;
200 api.d = strm->d;
201 (*(strm->fct))(&api);
202 if (0 != api.res) {
203 strm->feoi = 1;
204 }
205 }
206 }
207 } else {
208 if (0 != strm->zreof) {
209 strm->feoi = 1;
210 } else {
211 dk4stream_api_init(&api);
212 api.cmd = DK4_STREAM_API_AT_END;
213 api.d = strm->d;
214 (*(strm->fct))(&api);
215 if (0 != api.res) {
216 strm->feoi = 1;
217 }
218 }
219 }
220 } else {
221 }
222 if ((0 < strm->usbi) && (strm->rebi < strm->usbi)) {
223
224 *dst = (strm->bi)[strm->rebi];
225 strm->rebi += 1;
226 back = 1;
227 } else {
228 }
229
230 return back;
231 }
232
233
234
235
236 dk4_stream_t *
dk4stream_open(void * obj,dk4_stream_api_fct_t * fct,int fl,size_t ibs,size_t obs,dk4_er_t * erp)237 dk4stream_open(
238 void *obj,
239 dk4_stream_api_fct_t *fct,
240 int fl,
241 size_t ibs,
242 size_t obs,
243 dk4_er_t *erp
244 )
245 {
246 dk4_stream_api_t api;
247 dk4_stream_t *back = NULL;
248
249 /* Check arguments
250 */
251 #if DK4_USE_ASSERT
252 assert(NULL != obj);
253 assert(NULL != fct);
254 #endif
255 if ((NULL == obj) || (NULL == fct)) {
256 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
257 goto finished;
258 }
259 /* Check flag, at least read or write must be set
260 */
261 if (0 == (fl & (DK4_STREAM_READ | DK4_STREAM_WRITE))) {
262 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
263 goto finished;
264 }
265 /* Allocate memory for stream itself
266 */
267 back = dk4mem_new(dk4_stream_t,1,erp);
268 if (NULL == back) {
269 goto finished;
270 }
271 /* Initialize members
272 */
273 back->d = obj; back->fct = fct;
274 back->bi = NULL; back->bo = NULL;
275 back->bwr = (dk4_um_t)0UL;
276 back->szbi = 0; back->szbo = 0;
277 back->usbi = 0; back->usbo = 0; back->rebi = 0;
278 back->fl = fl; back->feoi = 0;
279 back->bwo = 0;
280 #if DK4_ON_WINDOWS
281 back->oenc = DK4_FILE_ENCODING_WIN1252;
282 #else
283 back->oenc = DK4_FILE_ENCODING_PLAIN;
284 #endif
285 back->zreof = 0;
286 /* Allocate input buffer or destroy object
287 */
288 if (fl & DK4_STREAM_READ) {
289 back->szbi = ((0 < ibs) ? ibs : 4096);
290 back->bi = dk4mem_new(char,back->szbi,erp);
291 if (NULL == back->bi) {
292 dk4stream_release_memory(back);
293 back = NULL;
294 goto finished;
295 }
296 }
297 /* Allocate output buffer or destroy object
298 */
299 if (fl & DK4_STREAM_WRITE) {
300 back->szbo = ((0 < obs) ? obs : 4096);
301 back->bo = dk4mem_new(char,back->szbo,erp);
302 if (NULL == back->bo) {
303 dk4stream_release_memory(back);
304 back = NULL;
305 goto finished;
306 }
307 }
308 /* Check whether reading zero bytes indicates end of input
309 */
310 dk4stream_api_init(&api);
311 api.cmd = DK4_STREAM_API_ZERO_READ_IS_EOF;
312 api.d = obj;
313 (*(back->fct))(&api);
314 if (0 != api.res) { back->zreof = 1; }
315 finished:
316
317 return back;
318 }
319
320
321
322 int
dk4stream_close(dk4_stream_t * strm,dk4_er_t * erp)323 dk4stream_close(dk4_stream_t *strm, dk4_er_t *erp)
324 {
325 dk4_stream_api_t api;
326 int back = 0;
327
328 /* Check argument.
329 */
330 #if DK4_USE_ASSERT
331 assert(NULL != strm);
332 #endif
333 if (NULL == strm) {
334 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
335 goto finished;
336 }
337
338 /* Success so far, unless there are errors in the next sections.
339 */
340 back = 1;
341
342 /* Write bytes in output buffer downwards.
343 */
344 if ((0 != ((strm->fl) & DK4_STREAM_WRITE)) && (0 < strm->usbo)) {
345 dk4stream_api_init(&api);
346 api.cmd = DK4_STREAM_API_WRITE;
347 api.d = strm->d;
348 api.b = strm->bo;
349 api.sz_in = strm->usbo;
350 (*(strm->fct))(&api);
351 if (0 == api.res) {
352 back = 0;
353 dk4error_set_simple_error_code(erp, DK4_E_WRITE_FAILED);
354 }
355 }
356
357 /* Attempt to flush downwards.
358 */
359 if ((strm->fl) & DK4_STREAM_WRITE) {
360 dk4stream_api_init(&api);
361 api.cmd = DK4_STREAM_API_FLUSH;
362 api.d = strm->d;
363 (*(strm->fct))(&api);
364 if (0 == api.res) {
365 back = 0;
366 dk4error_set_simple_error_code(erp, DK4_E_FLUSH_FAILED);
367 }
368 }
369
370 /* Finalize downward data structures.
371 */
372 dk4stream_api_init(&api);
373 api.cmd = DK4_STREAM_API_CLOSE;
374 api.d = strm->d;
375 (*(strm->fct))(&api);
376 if (0 == api.res) {
377 back = 0;
378 dk4error_set_simple_error_code(erp, DK4_E_CLOSE_FAILED);
379 }
380
381 /* Release memory.
382 */
383 dk4stream_release_memory(strm);
384
385 finished:
386
387 return back;
388 }
389
390
391
392 int
dk4stream_write_byte(dk4_stream_t * strm,char c,dk4_er_t * erp)393 dk4stream_write_byte(dk4_stream_t *strm, char c, dk4_er_t *erp)
394 {
395 int back = 0;
396
397 #if DK4_USE_ASSERT
398 assert(NULL != strm);
399 #endif
400 if (NULL != strm) {
401 if ((strm->fl) & DK4_STREAM_WRITE) {
402 back = dk4stream_i_write_byte(strm, c, erp);
403 } else {
404 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
405 }
406 } else {
407 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
408 }
409 return back;
410 }
411
412
413
414 #if NOT_OPTIMIZED
415
416 int
dk4stream_write(dk4_stream_t * strm,const void * b,size_t sz,dk4_er_t * erp)417 dk4stream_write(dk4_stream_t *strm, const void *b, size_t sz, dk4_er_t *erp)
418 {
419 char *cptr; /* Traverse buffer */
420 int back = 0;
421
422 #if DK4_USE_ASSERT
423 assert(NULL != strm);
424 assert(NULL != b);
425 assert(0 < sz);
426 #endif
427 if ((NULL != strm) && (NULL != b) && (0 < sz)) {
428 if ((strm->fl) & DK4_STREAM_WRITE) {
429 back = 1;
430 cptr = (char *)b;
431 while(sz--) {
432 if (0 == dk4stream_i_write_byte(strm, *(cptr++), erp)) {
433 back = 0;
434 }
435 }
436 } else {
437 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
438 }
439 } else {
440 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
441 }
442 return back;
443 }
444
445 #else
446
447 int
dk4stream_write(dk4_stream_t * strm,const void * b,size_t sz,dk4_er_t * erp)448 dk4stream_write(dk4_stream_t *strm, const void *b, size_t sz, dk4_er_t *erp)
449 {
450 char *cptr; /* Traverse buffer */
451 size_t bc;
452 int back = 0;
453 int cc;
454
455
456 #if DK4_USE_ASSERT
457 assert(NULL != strm);
458 assert(NULL != b);
459 assert(0 < sz);
460 #endif
461 if ((NULL != strm) && (NULL != b) && (0 < sz)) {
462 if ((strm->fl) & DK4_STREAM_WRITE) {
463 back = 1;
464 cptr = (char *)b;
465 do {
466 cc = 0;
467 if (0 < sz) {
468 if (strm->usbo < strm->szbo) {
469 /* Attempt to copy as many bytes as still free in output buffer */
470 bc = strm->szbo - strm->usbo;
471 /* If not enough bytes available, correct number of bytes */
472 if (bc > sz) { bc = sz; }
473 DK4_MEMCPY(&((strm->bo)[strm->usbo]), cptr, bc);
474 strm->usbo += bc;
475 cptr = &(cptr[bc]);
476 sz -= bc;
477 if ((DK4_UM_MAX - (dk4_um_t)bc) < strm->bwr) {
478 strm->bwo = 1;
479 back = 0;
480 }
481 strm->bwr += (dk4_um_t)bc;
482 if (strm->usbo >= strm->szbo) {
483 if (0 == dk4stream_i_flush_write(strm, 0, erp)) {
484 back = 0;
485 }
486 }
487 if (0 < sz) { cc = 1; }
488 } else {
489 if (0 == dk4stream_i_flush_write(strm, 0, erp)) {
490 back = 0;
491 }
492 }
493 }
494 } while(0 != cc);
495 } else {
496 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
497 }
498 } else {
499 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
500 }
501 return back;
502 }
503
504 #endif
505
506
507
508 int
dk4stream_write_char_string(dk4_stream_t * strm,const char * str,dk4_er_t * erp)509 dk4stream_write_char_string(dk4_stream_t *strm, const char *str, dk4_er_t *erp)
510 {
511 size_t sl;
512 int back = 0;
513 #if DK4_USE_ASSERT
514 assert(NULL != strm);
515 assert(NULL != str);
516 #endif
517 if ((NULL != strm) && (NULL != str)) {
518 sl = strlen(str);
519 back = dk4stream_write(strm, str, sl, erp);
520 }
521 else {
522 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
523 }
524 return back;
525 }
526
527
528
529 int
dk4stream_flush_read(dk4_stream_t * strm,dk4_er_t * erp)530 dk4stream_flush_read(dk4_stream_t *strm, dk4_er_t *erp)
531 {
532 int back = 0;
533
534 #if DK4_USE_ASSERT
535 assert(NULL != strm);
536 #endif
537 if (NULL != strm) {
538 if ((strm->fl) & DK4_STREAM_READ) {
539 back = 1;
540 strm->usbi = 0;
541 strm->rebi = 0;
542 } else {
543 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
544 }
545 } else {
546 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
547 }
548 return back;
549 }
550
551
552
553 int
dk4stream_flush_write(dk4_stream_t * strm,int flfl,dk4_er_t * erp)554 dk4stream_flush_write(dk4_stream_t *strm, int flfl, dk4_er_t *erp)
555 {
556 int back = 0;
557
558 #if DK4_USE_ASSERT
559 assert(NULL != strm);
560 #endif
561 if (NULL != strm) {
562 if ((strm->fl) & DK4_STREAM_WRITE) {
563 back = dk4stream_i_flush_write(strm, flfl, erp);
564 } else {
565 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
566 }
567 } else {
568 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
569 }
570 return back;
571 }
572
573
574
575 int
dk4stream_flush(dk4_stream_t * strm,int flfl,dk4_er_t * erp)576 dk4stream_flush(dk4_stream_t *strm, int flfl, dk4_er_t *erp)
577 {
578 int back = 0;
579
580 #if DK4_USE_ASSERT
581 assert(NULL != strm);
582 #endif
583 if (NULL != strm) {
584 back = 1;
585 if ((strm->fl) & DK4_STREAM_WRITE) {
586 if (0 == dk4stream_flush_write(strm, flfl, erp)) {
587 back = 0;
588 }
589 }
590 if ((strm->fl) & DK4_STREAM_READ) {
591 if (0 == dk4stream_flush_read(strm, erp)) {
592 back = 0;
593 }
594 }
595 } else {
596 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
597 }
598 return back;
599 }
600
601
602
603 int
dk4stream_c8_read_byte(char * dst,dk4_stream_t * strm,dk4_er_t * erp)604 dk4stream_c8_read_byte(char *dst, dk4_stream_t *strm, dk4_er_t *erp)
605 {
606 int back = 0;
607
608 #if DK4_USE_ASSERT
609 assert(NULL != strm);
610 assert(NULL != dst);
611 #endif
612 if ((NULL != dst) && (NULL != strm)) {
613 if ((strm->fl) & DK4_STREAM_READ) {
614 back = dk4stream_i_c8_read_byte(dst, strm);
615 } else {
616 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
617 }
618 } else {
619 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
620 }
621 return back;
622 }
623
624
625
626 int
dk4stream_read(void * b,size_t * szptr,dk4_stream_t * strm,dk4_er_t * erp)627 dk4stream_read(void *b, size_t *szptr, dk4_stream_t *strm, dk4_er_t *erp)
628 {
629 char *cptr; /* Traverse the buffer */
630 size_t szin; /* Input: Available buffer size */
631 size_t szout; /* Output: Used buffer size */
632 int back = 0; /* Function result */
633 int cc = 1; /* Flag: Can continue */
634
635 #if DK4_USE_ASSERT
636 assert(NULL != strm);
637 assert(NULL != b);
638 assert(NULL != szptr);
639 assert(0 < *szptr);
640 #endif
641 if ((NULL != b) && (NULL != szptr) && (NULL != strm)) {
642 if (((strm->fl) & DK4_STREAM_READ) && (0 < *szptr)) {
643 szin = *szptr; szout = 0;
644 cptr = (char *)b;
645 do {
646 if (0 != dk4stream_i_c8_read_byte(cptr++, strm)) {
647 szout++;
648 if (szout >= szin) {
649 cc = 0;
650 back = 1;
651 }
652 } else {
653 cc = 0;
654 if (0 < szout) {
655 back = 1;
656 } else {
657 if (0 != dk4stream_found_eof(strm)) {
658 dk4error_set_simple_error_code(erp, DK4_E_NOT_FOUND);
659 } else {
660 dk4error_set_simple_error_code(erp, DK4_E_READ_FAILED);
661 }
662 }
663 }
664 } while (0 != cc);
665 *szptr = szout;
666 } else {
667 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
668 }
669 } else {
670 dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
671 }
672 return back;
673 }
674
675
676
677 dk4_um_t
dk4stream_bytes_written(const dk4_stream_t * strm)678 dk4stream_bytes_written(const dk4_stream_t *strm)
679 {
680 dk4_um_t back = (dk4_um_t)0UL;
681 #if DK4_USE_ASSERT
682 assert(NULL != strm);
683 #endif
684 if (NULL != strm) { back = strm->bwr; }
685 return back;
686 }
687
688
689
690 int
dk4stream_overflow_bytes_written(const dk4_stream_t * strm)691 dk4stream_overflow_bytes_written(const dk4_stream_t *strm)
692 {
693 int back = 0;
694 #if DK4_USE_ASSERT
695 assert(NULL != strm);
696 #endif
697 if (NULL != strm) { back = strm->bwo; }
698 return back;
699 }
700
701
702
703 int
dk4stream_found_eof(const dk4_stream_t * strm)704 dk4stream_found_eof(const dk4_stream_t *strm)
705 {
706 int back = 0;
707 #if DK4_USE_ASSERT
708 assert(NULL != strm);
709 #endif
710 if (NULL != strm) {
711 back = strm->feoi;
712 }
713 return back;
714 }
715
716