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