1 /***************************************************************************
2     begin       : Tue Apr 27 2010
3     copyright   : (C) 2010 by Martin Preuss
4     email       : martin@libchipcard.de
5 
6  ***************************************************************************
7  *          Please see toplevel file COPYING for license details           *
8  ***************************************************************************/
9 
10 
11 #ifndef GWEN_FASTBUFFER_H
12 #define GWEN_FASTBUFFER_H
13 
14 
15 #include <gwenhywfar/syncio.h>
16 #include <gwenhywfar/buffer.h>
17 
18 
19 #define GWEN_FAST_BUFFER_FLAGS_DOSMODE 0x00000001
20 
21 
22 /**
23  * Do not use the fields of this struct directly!! Only use it via the functions and macros
24  * in this module, because otherwise future versions of you application might not work.
25  * Do not allocate such an object yourself, always use @ref GWEN_FastBuffer_new() otherwise
26  * future versions of you application might not work!
27  * This struct is not part of the API.
28  */
29 typedef struct {
30   GWEN_SYNCIO *io;
31   uint32_t bufferSize;
32   uint32_t bufferReadPos;
33   uint32_t bufferWritePos;
34   uint32_t flags;
35   uint32_t bytesWritten;
36   uint32_t bytesRead;
37   uint8_t buffer[1];
38 } GWEN_FAST_BUFFER;
39 
40 
41 
42 #ifdef __cplusplus
43 extern "C" {
44 #endif
45 
46 
47 GWENHYWFAR_API GWEN_FAST_BUFFER *GWEN_FastBuffer_new(uint32_t bsize, GWEN_SYNCIO *io);
48 
49 GWENHYWFAR_API void GWEN_FastBuffer_free(GWEN_FAST_BUFFER *fb);
50 
51 
52 GWENHYWFAR_API uint32_t GWEN_FastBuffer_GetFlags(const GWEN_FAST_BUFFER *fb);
53 GWENHYWFAR_API void GWEN_FastBuffer_SetFlags(GWEN_FAST_BUFFER *fb, uint32_t fl);
54 GWENHYWFAR_API void GWEN_FastBuffer_AddFlags(GWEN_FAST_BUFFER *fb, uint32_t fl);
55 GWENHYWFAR_API void GWEN_FastBuffer_SubFlags(GWEN_FAST_BUFFER *fb, uint32_t fl);
56 
57 GWENHYWFAR_API uint32_t GWEN_FastBuffer_GetBytesWritten(const GWEN_FAST_BUFFER *fb);
58 GWENHYWFAR_API uint32_t GWEN_FastBuffer_GetBytesRead(const GWEN_FAST_BUFFER *fb);
59 
60 GWENHYWFAR_API int GWEN_FastBuffer_ReadLine(GWEN_FAST_BUFFER *fb, uint8_t *p, int len);
61 GWENHYWFAR_API int GWEN_FastBuffer_ReadLineToBuffer(GWEN_FAST_BUFFER *fb, GWEN_BUFFER *buf);
62 
63 
64 #ifdef __cplusplus
65 }
66 #endif
67 
68 
69 /**
70  * This macro peeks at the read buffer and returns the next available byte (if any).
71  * Consecutive peeks will always return the same byte. Also, the next @ref GWEN_FASTBUFFER_READBYTE
72  * will return the same byte as well.
73  */
74 #define GWEN_FASTBUFFER_PEEKBYTE(fb, var) {\
75     if (fb->bufferReadPos>=fb->bufferWritePos) { \
76       int fb_peekbyte_rv; \
77       \
78       fb_peekbyte_rv=GWEN_SyncIo_Read(fb->io, fb->buffer, fb->bufferSize); \
79       if (fb_peekbyte_rv<0) { \
80         DBG_DEBUG(GWEN_LOGDOMAIN, "here (%d)", fb_peekbyte_rv); \
81   var=fb_peekbyte_rv; \
82       } \
83       else if (fb_peekbyte_rv==0) { \
84         DBG_DEBUG(GWEN_LOGDOMAIN, "EOF met"); \
85   var=GWEN_ERROR_EOF; \
86       } \
87       else { \
88   fb->bufferWritePos=fb_peekbyte_rv; \
89   fb->bufferReadPos=0; \
90   var=((int)((fb->buffer[fb->bufferReadPos])) & 0xff); \
91       } \
92     } \
93     else { \
94       var=((int)((fb->buffer[fb->bufferReadPos])) & 0xff); \
95     } \
96   }
97 
98 
99 /**
100  * Returns the next byte from the buffer (if any). That byte will be placed into "var". In case of an error
101  * var will contain an error code instead.
102  */
103 #define GWEN_FASTBUFFER_READBYTE(fb, var) {\
104     if (fb->bufferReadPos>=fb->bufferWritePos) { \
105       int fb_readbyte_rv; \
106       \
107       fb_readbyte_rv=GWEN_SyncIo_Read(fb->io, fb->buffer, fb->bufferSize); \
108       if (fb_readbyte_rv<0) { \
109         DBG_DEBUG(GWEN_LOGDOMAIN, "here (%d)", fb_readbyte_rv); \
110   var=fb_readbyte_rv; \
111       } \
112       else if (fb_readbyte_rv==0) { \
113         DBG_DEBUG(GWEN_LOGDOMAIN, "EOF met"); \
114   var=GWEN_ERROR_EOF; \
115       } \
116       else { \
117   fb->bufferWritePos=fb_readbyte_rv; \
118   fb->bufferReadPos=0; \
119   var=((int)((fb->buffer[fb->bufferReadPos++])) & 0xff); \
120         fb->bytesRead++; \
121       } \
122     } \
123     else { \
124       var=((int)((fb->buffer[fb->bufferReadPos++])) & 0xff); \
125       fb->bytesRead++; \
126     } \
127   }
128 
129 
130 /**
131  * Writes a byte into the buffer (flushing it if necessary) and returns the result of this operation
132  * in "var".
133  */
134 #define GWEN_FASTBUFFER_WRITEBYTE(fb, var, chr) {\
135     if (fb->bufferWritePos>=fb->bufferSize) { \
136       int fb_writeByte_rv; \
137       \
138       fb_writeByte_rv=GWEN_SyncIo_WriteForced(fb->io, fb->buffer, fb->bufferWritePos); \
139       if (fb_writeByte_rv<(int)(fb->bufferWritePos)) { \
140         DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", fb_writeByte_rv); \
141   var=fb_writeByte_rv; \
142       } \
143       else { \
144         var=0; \
145   fb->bufferWritePos=0; \
146   fb->buffer[fb->bufferWritePos++]=chr; \
147         fb->bytesWritten++; \
148       } \
149     } \
150     else { \
151       var=0; \
152       fb->buffer[fb->bufferWritePos++]=chr; \
153       fb->bytesWritten++; \
154     } \
155   }
156 
157 
158 /**
159  * Flushes the write buffer (i.e. write all remaining bytes from the buffer to the io layer with
160  * the flag @ref GWEN_IO_REQUEST_FLAGS_FLUSH set).
161  */
162 #define GWEN_FASTBUFFER_FLUSH(fb, var) {\
163     int fb_flush_rv; \
164     \
165     fb_flush_rv=GWEN_SyncIo_WriteForced(fb->io, fb->buffer, fb->bufferWritePos); \
166     if (fb_flush_rv<(int)(fb->bufferWritePos)) { \
167       DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", fb_flush_rv); \
168       var=fb_flush_rv; \
169     } \
170     else { \
171       var=0; \
172       fb->bufferWritePos=0; \
173     } \
174   }
175 
176 
177 /**
178  * Reads a number of bytes from the buffer and stores it at the given memory location.
179  * @param fb fast buffer
180  * @param var variable to receive the result (<0: error code, number of bytes read otherwise)
181  * @param p pointer to the location to read the bytes to
182  * @param len number of bytes to read
183  */
184 #define GWEN_FASTBUFFER_READBYTES(fb, var, p, len) { \
185   int fb_readbyte_bytes;\
186   \
187   var=0; \
188   if (fb->bufferReadPos>=fb->bufferWritePos) { \
189     int fb_readbyte_rv; \
190     \
191     fb_readbyte_rv=GWEN_SyncIo_Read(fb->io, fb->buffer, fb->bufferSize); \
192     if (fb_readbyte_rv<0) { \
193       DBG_DEBUG(GWEN_LOGDOMAIN, "here (%d)", fb_readbyte_rv); \
194       var=fb_readbyte_rv; \
195     } \
196     else {\
197       fb->bufferWritePos=fb_readbyte_rv; \
198       fb->bufferReadPos=0; \
199     }\
200   }\
201   if (var==0) {\
202     fb_readbyte_bytes=fb->bufferWritePos-fb->bufferReadPos;\
203     if (fb_readbyte_bytes>len)\
204       fb_readbyte_bytes=len;\
205     if (fb_readbyte_bytes) {\
206       memmove(p, fb->buffer+fb->bufferReadPos, fb_readbyte_bytes);\
207       fb->bufferReadPos+=fb_readbyte_bytes;\
208       fb->bytesRead+=fb_readbyte_bytes; \
209     }\
210     var=fb_readbyte_bytes;\
211   }\
212 }
213 
214 
215 
216 #define GWEN_FASTBUFFER_READLINE(fb, var, p, len) {\
217   int fb_readline_bytes;\
218   \
219   var=0;\
220   if (fb->bufferReadPos>=fb->bufferWritePos) {\
221     int fb_readline_rv;\
222     \
223     fb_readline_rv=GWEN_SyncIo_Read(fb->io, fb->buffer, fb->bufferSize);\
224     if (fb_readline_rv<0) {\
225       DBG_DEBUG(GWEN_LOGDOMAIN, "here (%d)", fb_readline_rv);\
226       var=fb_readline_rv;\
227     }\
228     else {\
229       fb->bufferWritePos=fb_rv; \
230       fb->bufferReadPos=0; \
231     }\
232   }\
233   if (var==0) {\
234     fb_readline_bytes=fb->bufferWritePos-fb->bufferReadPos;\
235     if (fb_readline_bytes>len)\
236       fb_readline_bytes=len;\
237     if (fb_readline_bytes) {\
238       uint8_t *fb_readline_p;\
239       \
240       fb_readline_p=(uint8_t*)p;\
241       \
242       while(fb_readline_bytes) {\
243   uint8_t c;\
244         \
245   c=fb->buffer[fb->bufferReadPos++];\
246         fb->bytesRead++; \
247   fb_readline_bytes--;\
248         if (c==10) {\
249     *(fb_readline_p++)=c;\
250     var++;\
251     break;\
252         }\
253   else if (c!=13) {\
254     *(fb_readline_p++)=c;\
255     var++;\
256   }\
257       }\
258     }\
259   }\
260 }
261 
262 
263 
264 #define GWEN_FASTBUFFER_READLINEFORCED(fb, var, p, len) {\
265   int fb_readlineforced_len;\
266   uint8_t *fb_readlineforced_p;\
267   \
268   fb_readlineforced_len=len;\
269   fb_readlineforced_p=(uint8_t*)p;\
270   var=0;\
271   while(fb_readlineforced_len && var==0) {\
272     int fb_readlineforced_rv;\
273     \
274     GWEN_FASTBUFFER_READLINE(fb, fb_readlineforced_rv, fb_readlineforced_p, fb_readlineforced_len);\
275     if (fb_readlineforced_rv<0) {\
276       var=fb_readlineforced_rv;\
277       break;\
278     }\
279     else if (fb_readlineforced_rv==0) {\
280       var=GWEN_ERROR_EOF;\
281       break;\
282     }\
283     else {\
284       if (fb_readlineforced_p[fb_readlineforced_rv-1]==10) {\
285         fb_readlineforced_p[fb_readlineforced_rv-1]=0;\
286         var=fb_readlineforced_rv;\
287         break;\
288       }\
289       fb_readlineforced_len-=fb_readlineforced_rv;\
290       fb_readlineforced_p+=fb_readlineforced_rv;\
291     }\
292   }\
293   if (var==0) {\
294     DBG_INFO(GWEN_LOGDOMAIN, "No line within %d bytes", len);\
295     var=GWEN_ERROR_BAD_SIZE;\
296   }\
297 }
298 
299 
300 
301 #define GWEN_FASTBUFFER_READFORCED(fb, var, p, len) {\
302   int fb_readforced_len;\
303   uint8_t *fb_readforced_p;\
304   \
305   fb_readforced_len=len;\
306   fb_readforced_p=(uint8_t*)p;\
307   var=0;\
308   while(fb_readforced_len && var==0) {\
309     int fb_readforced_rv;\
310     \
311     GWEN_FASTBUFFER_READBYTES(fb, fb_readforced_rv, fb_readforced_p, fb_readforced_len);\
312     if (fb_readforced_rv<0) {\
313       var=fb_readforced_rv;\
314       break;\
315     }\
316     else if (fb_readforced_rv==0) {\
317       var=GWEN_ERROR_EOF;\
318       break;\
319     }\
320     else {\
321       fb_readforced_len-=fb_readforced_rv;\
322       fb_readforced_p+=fb_readforced_rv;\
323     }\
324   }\
325 }
326 
327 
328 
329 /**
330  * Write a number of bytes to the buffer and stores it at the given memory location.
331  * @param fb fast buffer
332  * @param var variable to receive the result (<0: error code, number of bytes read otherwise)
333  * @param p pointer to the location to write the bytes from
334  * @param len number of bytes to write
335  */
336 #define GWEN_FASTBUFFER_WRITEBYTES(fb, var, p, len) {\
337   int fb_writebytes_bytes;\
338   int fb_writebytes_len;\
339   \
340   fb_writebytes_len=len;\
341   if (fb_writebytes_len==-1)\
342     fb_writebytes_len=strlen((const char*)p);\
343   var=0; \
344   if (fb->bufferWritePos>=fb->bufferSize) { \
345     int fb_writebytes_rv; \
346     \
347     fb_writebytes_rv=GWEN_SyncIo_WriteForced(fb->io, fb->buffer, fb->bufferWritePos); \
348     if (fb_writebytes_rv<(int)(fb->bufferWritePos)) { \
349       DBG_DEBUG(GWEN_LOGDOMAIN, "here (%d)", fb_writebytes_rv); \
350       var=fb_writebytes_rv; \
351     } \
352     else {\
353       fb->bufferWritePos=0; \
354     }\
355   }\
356   if (var==0) {\
357     fb_writebytes_bytes=fb->bufferSize-fb->bufferWritePos;\
358     if (fb_writebytes_bytes>fb_writebytes_len)\
359       fb_writebytes_bytes=fb_writebytes_len;\
360     if (fb_writebytes_bytes) {\
361       memmove(fb->buffer+fb->bufferWritePos, p, fb_writebytes_bytes);\
362       fb->bufferWritePos+=fb_writebytes_bytes;\
363       fb->bytesWritten+=fb_writebytes_bytes; \
364     }\
365     var=fb_writebytes_bytes;\
366   }\
367 }
368 
369 
370 /**
371  * Write a number of bytes to the buffer and make sure that @b all bytes are written.
372  * @param fb fast buffer
373  * @param var variable to receive the result (<0: error code, 0 on success)
374  * @param p pointer to the location to write the bytes from
375  * @param len number of bytes to write
376  */
377 #define GWEN_FASTBUFFER_WRITEFORCED(fb, var, p, len) {\
378   int fb_writeforced_len;\
379   const uint8_t *fb_writeforced_p;\
380   \
381   fb_writeforced_len=len;\
382   if (fb_writeforced_len==-1) \
383     fb_writeforced_len=strlen((const char*)p);\
384   fb_writeforced_p=(const uint8_t*)p;\
385   var=0;\
386   while(fb_writeforced_len && var==0) {\
387     int fb_writeforced_rv;\
388     \
389     GWEN_FASTBUFFER_WRITEBYTES(fb, fb_writeforced_rv, fb_writeforced_p, fb_writeforced_len);\
390     if (fb_writeforced_rv<0) {\
391       var=fb_writeforced_rv;\
392       break;\
393     }\
394     else if (fb_writeforced_rv==0) {\
395       var=GWEN_ERROR_EOF;\
396       break;\
397     }\
398     else {\
399       fb_writeforced_len-=fb_writeforced_rv;\
400       fb_writeforced_p+=fb_writeforced_rv;\
401     }\
402   }\
403 }
404 
405 
406 
407 #define GWEN_FASTBUFFER_WRITELINE(fb, var, p) {\
408   int fb_writeline_rv;\
409   int fb_writeline_len=strlen((const char*)p);\
410   \
411   GWEN_FASTBUFFER_WRITEFORCED(fb, fb_writeline_rv, p, fb_writeline_len);\
412   if (fb_writeline_rv<0)\
413     var=fb_writeline_rv;\
414   else {\
415     if (fb->flags & GWEN_FAST_BUFFER_FLAGS_DOSMODE) {\
416        GWEN_FASTBUFFER_WRITEFORCED(fb, fb_writeline_rv, "\r\n", 2);\
417     }\
418     else {\
419        GWEN_FASTBUFFER_WRITEFORCED(fb, fb_writeline_rv, "\n", 1);\
420     }\
421     if (fb_writeline_rv<0)\
422       var=fb_writeline_rv;\
423     else\
424       var=0;\
425   }\
426 }
427 
428 
429 
430 /**
431  * Copy a number of bytes from one buffer to another one.
432  * @param fb1 source fast buffer
433  * @param fb2 destination fast buffer
434  * @param var variable to receive the result (<0: error code, number of bytes read otherwise)
435  * @param len number of bytes to copy
436  */
437 #define GWEN_FASTBUFFER_COPYBYTES(fb1, fb2, var, len) { \
438   int fb_copybytes_bytes;\
439   \
440   var=0; \
441   if (fb1->bufferReadPos>=fb1->bufferWritePos) { \
442     int fb_copybytes_rv; \
443     \
444     fb_copybytes_rv=GWEN_SyncIo_Read(fb1->io, fb1->buffer, fb1->bufferSize); \
445     if (fb_copybytes_rv<0) { \
446       DBG_DEBUG(GWEN_LOGDOMAIN, "here (%d)", fb_copybytes_rv); \
447       var=fb_copybytes_rv; \
448     } \
449     else {\
450       fb1->bufferWritePos=fb_copybytes_rv; \
451       fb1->bufferReadPos=0; \
452     }\
453   }\
454   if (var==0) {\
455     fb_bytes=fb1->bufferWritePos-fb1->bufferReadPos;\
456     if (fb_copybytes_bytes>len)\
457       fb_copybytes_bytes=len;\
458     if (fb_copybytes_bytes) {\
459       int fb_copybytes_rv;\
460       \
461       GWEN_FASTBUFFER_WRITEBYTES(fb2, fb_copybytes_rv, (fb1->buffer+fb1->bufferReadPos), fb_bytes);\
462       var=fb_copybytes_rv;\
463       if (fb_copybytes_rv>0) {\
464   fb1->bufferReadPos+=fb_copybytes_rv;\
465         fb1->bytesRead+=fb_copybytes_rv; \
466       }\
467     }\
468   }\
469 }
470 
471 
472 
473 /**
474  * Copy a number of bytes to the buffer and make sure that @b all bytes are copied.
475  * @param fb1 source fast buffer
476  * @param fb2 destination fast buffer
477  * @param var variable to receive the result (<0: error code, 0 on success)
478  * @param p pointer to the location to write the bytes from
479  * @param len number of bytes to copy
480  */
481 #define GWEN_FASTBUFFER_COPYFORCED(fb1, fb2, var, p, len) {\
482   int fb_copyforced_len;\
483   uint8_t *fb_copyforced_p;\
484   \
485   fb_copyforced_len=len;\
486   fb_copyforced_p=(uint8_t*)p;\
487   var=0;\
488   while(fb_copyforced_len && var==0) {\
489     int fb_copyforced_rv;\
490     \
491     GWEN_FASTBUFFER_COPYBYTES(fb1, fb2, fb_copyforced_rv, fb_copyforced_p, fb_copyforced_len);\
492     if (fb_copyforced_rv<0) {\
493       var=fb_copyforced_rv;\
494       break;\
495     }\
496     else if (fb_copyforced_rv==0)\
497       var=GWEN_ERROR_EOF;\
498     else {\
499       fb_len-=fb_copyforced_rv;\
500       fb_p+=fb_copyforced_rv;\
501     }\
502   }\
503 }
504 
505 
506 
507 
508 #endif
509 
510 
511 
512