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