%% options copyright owner = Dirk Krause copyright year = 2011-2014 license = bsd %% header #include "dk3conf.h" #include "dk3types.h" #ifdef __cplusplus extern "C" { #endif /** Create output filter for a stream. @param os Output stream. @param app Application structure for diagnostics. @return Pointer to new filter on success, NULL on error. */ dk3_of_t * dk3of_open_app(dk3_stream_t *os, dk3_app_t *app); /** Create output filter for a stream. @param os Output stream. @return Pointer to new filter on success, NULL on error. */ dk3_of_t * dk3of_open(dk3_stream_t *os); /** Close output filter, release memory. @param of Filter to delete. */ void dk3of_close(dk3_of_t *of); /** Add filter cell. @param of Output filter. @param ct Cell type (DK3_OF_CELL_TYPE_xxx). @return 1 on success, 0 on error. */ int dk3of_add_cell(dk3_of_t *of, int ct); /** Start data chunk. @param of Output filter. @return 1 on success, 0 on error. */ int dk3of_start_chunk(dk3_of_t *of); /** End data chunk, flush buffers. @param of Output filter. @return 1 on success, 0 on error. */ int dk3of_end_chunk(dk3_of_t *of); /** Write bytes to filter cell. @param cp Filter cell. @param bu Buffer containing the bytes. @param sz Number of bytes. @return 1 on success, 0 on error. */ int dk3of_bytes_to_cell(dk3_of_cell_t *cp, unsigned char const *bu, size_t sz); /** Write bytes from filter cell, either to the next filter cell downwards or to the destination stream. @param cp Filter cell. @param bu Buffer containing the bytes. @param sz Number of bytes. @return 1 on success, 0 on error. */ int dk3of_bytes_from_cell(dk3_of_cell_t *cp, unsigned char const *bu, size_t sz); /** Write bytes to output filter. @param of Output filter. @param bu Buffer containing the bytes. @param sz Number of bytes. @return 1 on success, 0 on error. */ int dk3of_write_bytes(dk3_of_t *of, unsigned char const *bu, size_t sz); /** Write string to output filter. @param of Output filter. @param st String to write. @return 1 on success, 0 on error. */ int dk3of_write_c8_string(dk3_of_t *of, char const *st); /** Write bits to output filter. @param of Output filter. @param bv Bit values. @param sz Number of bits. @return 1 on success, 0 on error. */ int dk3of_write_bits(dk3_of_t *of, unsigned short bv, size_t sz); /** Flush bit buffer. @param of Output filter. @return 1 on success, 0 on error. */ int dk3of_flush_bits(dk3_of_t *of); /** Configure use of cr/nl sequences. @param of Output filter. @param fl 0 for disable, any other value to enable. */ void dk3of_set_crnl(dk3_of_t *of, int fl); /** Configure use of finalizers. @param of Output filter. @param fl 0 for disable, any other value to enable. */ void dk3of_set_finalize(dk3_of_t *of, int fl); /** Write double number to output, avoid exponential notation. @param of Output filter. @param x Value to write. @return 1 on success, 0 on error. */ int dk3of_double_to_c8_no_sci(dk3_of_t *of, double x); /** Write double number to output. @param of Output filter to write to. @param buffer String buffer containing number as string. @return 1 on success, 0 on error. */ int dk3of_double_str_no_sci(dk3_of_t *of, char *buffer); #ifdef __cplusplus } #endif %% module #include "dk3all.h" $!trace-include /** Keywords used by this module. */ static char const * dk3of_kw[] = { /* 0 */ "\n", /* 1 */ "\r\n", /* 2 */ ">", /* ASCII/Hex finalizer. */ /* 3 */ "~>", /* ASCII85 finalizer. */ }; /** Characters used for ASCII-Hex conversion. */ static char const dk3of_hex_chars[] = { "0123456789ABCDEF" }; /** Masks for single bits in an unsigned char. */ static unsigned char const dk3of_bits_in_char[] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }; /** Masks for single bits in an unsigned short. */ static unsigned short const dk3of_bits_in_short[] = { 0x0001U, 0x0002U, 0x0004U, 0x0008U, 0x0010U, 0x0020U, 0x0040U, 0x0080U, 0x0100U, 0x0200U, 0x0400U, 0x0800U, 0x1000U, 0x2000U, 0x4000U, 0x8000U }; /** Constant factors used in ASCII85 encoding. */ static unsigned long const dk3of_a85_factors[] = { (85UL * 85UL * 85UL * 85UL), (85UL * 85UL * 85UL), (85UL * 85UL), 85UL }; /** Destroy filter cell, release memory. @param cp Filter cell to delete. */ static void dk3of_cell_close(dk3_of_cell_t *cp) { $? "+ dk3of_cell_close %s", TR_PTR(cp) if(cp) { switch(cp->type) { case DK3_OF_CELL_TYPE_HEX: { /* Nothing to do here, only static data structures. */ } break; case DK3_OF_CELL_TYPE_A85: { /* Nothing to do here, only static data structures. */ } break; case DK3_OF_CELL_TYPE_RUN_LENGTH: { dk3_delete((cp->data).psrl.bu); } break; case DK3_OF_CELL_TYPE_FLATE: { #if DK3_HAVE_ZLIB_H dk3_release((cp->data).flate.zs); dk3_release((cp->data).flate.ibu); dk3_release((cp->data).flate.obu); (cp->data).flate.iused = 0UL; (cp->data).flate.ok = 0; #else back = 0; #endif } break; default: { $? "! unknown type" /* Nothing to do here as type is unknown. */ } break; } dk3_delete(cp); } $? "- dk3of_cell_close" } /** Create new filter cell for a filter. @param of Output filter. @param ct Cell type. @return Pointer to the new filter cell on success, NULL on error. */ static dk3_of_cell_t * dk3of_cell_open(dk3_of_t *of, int ct) { dk3_of_cell_t *back = NULL; $? "+ dk3of_cell_open %s %d", TR_PTR(of), ct if(of) { back = dk3_new_app(dk3_of_cell_t,1,(of->app)); if(back) { back->down = NULL; back->up = NULL; back->of = of; back->type = ct; switch(ct) { case DK3_OF_CELL_TYPE_HEX: { (back->data).ah.nl = 0; } break; case DK3_OF_CELL_TYPE_A85: { (back->data).a85.val = 0UL; (back->data).a85.nc = 0; (back->data).a85.nl = 0; } break; case DK3_OF_CELL_TYPE_RUN_LENGTH: { (back->data).psrl.bu = NULL; (back->data).psrl.used = 0; (back->data).psrl.same = 0; (back->data).psrl.pc = 0x00; (back->data).psrl.hc = 0x00; (back->data).psrl.run = 0x00; (back->data).psrl.bu = dk3_new_app(unsigned char,128,of->app); if(!((back->data).psrl.bu)) { dk3of_cell_close(back); back = NULL; } } break; case DK3_OF_CELL_TYPE_FLATE: { #if DK3_HAVE_ZLIB_H int ok = 0; (back->data).flate.zs = NULL; (back->data).flate.ibu = NULL; (back->data).flate.obu = NULL; (back->data).flate.iused = 0UL; (back->data).flate.ok = 0; (back->data).flate.zs = dk3_new_app(z_stream,1,of->app); if((back->data).flate.zs) { (back->data).flate.ibu = dk3_new_app(unsigned char,DK3_OF_FLATE_IN_BUFFER_SIZE,of->app); if((back->data).flate.ibu) { /* (back->data).flate.ilgt = DK3_OF_FLATE_IN_BUFFER_SIZE; */ (back->data).flate.obu = dk3_new_app(unsigned char,DK3_OF_FLATE_OUT_BUFFER_SIZE,of->app); if((back->data).flate.obu) { (back->data).flate.ok = 1; ok = 1; } } } if(!(ok)) { dk3of_cell_close(back); back = NULL; } #else back = 0; /* ERROR: Not supported. */ if(of->app) { dk3app_log_i1(of->app, DK3_LL_ERROR, 262); } #endif } break; default: { $? "! unknown type" dk3_delete(back); back = NULL; if(of->app) { /* ERROR: Unknown type! */ dk3app_log_i1(of->app, DK3_LL_ERROR, 262); } } break; } } } $? "- dk3of_cell_open %s", TR_PTR(back) return back; } dk3_of_t * dk3of_open_app(dk3_stream_t *os, dk3_app_t *app) { dk3_of_t *back = NULL; $? "+ dk3of_open_app %s %s", TR_PTR(os), TR_PTR(app) if(os) { back = dk3_new_app(dk3_of_t,1,app); if(back) { back->app = app; back->os = os; back->bottom = NULL; back->top = NULL; back->nCells = 0; back->nBits = 0; back->bits = 0x00; back->flags = DK3_OF_FLAG_FINALIZE; } } $? "- dk3of_open_app %s", TR_PTR(back) return back; } dk3_of_t * dk3of_open(dk3_stream_t *os) { dk3_of_t *back = NULL; $? "+ dk3of_open %s", TR_PTR(os) if(os) { back = dk3of_open_app(os, NULL); } $? "- dk3of_open %s", TR_PTR(back) return back; } void dk3of_close(dk3_of_t *of) { dk3_of_cell_t *cc; dk3_of_cell_t *nc; $? "+ dk3of_close %s", TR_PTR(of) if(of) { cc = of->top; while(cc) { nc = cc->down; dk3of_cell_close(cc); cc = nc; } } $? "- dk3of_close" } int dk3of_add_cell(dk3_of_t *of, int ct) { dk3_of_cell_t *nc; /* New cell. */ dk3_of_cell_t *ot; /* Old top. */ int back = 0; $? "+ dk3of_add_cell %s %d", TR_PTR(of), ct if(of) { switch(ct) { case DK3_OF_CELL_TYPE_HEX: case DK3_OF_CELL_TYPE_A85: case DK3_OF_CELL_TYPE_RUN_LENGTH: case DK3_OF_CELL_TYPE_FLATE: { nc = dk3of_cell_open(of, ct); if(nc) { back = 1; nc->of = (void *)of; ot = of->top; if(ot) { $? ". already have cells in stream" ot->up = nc; nc->down = ot; } else { $? ". first cell for stream" of->bottom = nc; nc->down = NULL; } nc->up = NULL; of->top = nc; of->nCells += 1; } } break; default: { /* ERROR: Illegal cell type! */ if(of->app) { dk3app_log_i1(of->app, DK3_LL_ERROR, 263); } } break; } } $? "- dk3of_add_cell %d", back return back; } int dk3of_start_chunk(dk3_of_t *of) { dk3_of_cell_t *cellptr; int back = 0; $? "+ dk3of_start_chunk %s", TR_PTR(of) if(of) { if(of->top) { back = 1; cellptr = of->top; while(cellptr) { switch(cellptr->type) { case DK3_OF_CELL_TYPE_HEX: { (cellptr->data).ah.nl = 0; } break; case DK3_OF_CELL_TYPE_A85: { (cellptr->data).a85.val = 0UL; (cellptr->data).a85.nc = 0; (cellptr->data).a85.nl = 0; } break; case DK3_OF_CELL_TYPE_RUN_LENGTH: { if((cellptr->data).psrl.bu) { dk3mem_res((void *)((cellptr->data).psrl.bu), 128); (cellptr->data).psrl.used = 0; (cellptr->data).psrl.same = 0; (cellptr->data).psrl.pc = 0x00; (cellptr->data).psrl.hc = 0x00; (cellptr->data).psrl.run = 0x00; } else { back = 0; } } break; case DK3_OF_CELL_TYPE_FLATE: { #if DK3_HAVE_ZLIB_H (cellptr->data).flate.iused = 0UL; ((cellptr->data).flate.zs)->zfree = (free_func)0; ((cellptr->data).flate.zs)->zalloc = (alloc_func)0; ((cellptr->data).flate.zs)->opaque = (voidpf)0; if(deflateInit((cellptr->data).flate.zs, 9) == Z_OK) { (cellptr->data).flate.ok = 1; } else { (cellptr->data).flate.ok = 0; back = 0; } #else back = 0; #endif } break; default: { back = 0; /* ERROR: Illegal cell type! */ if(of->app) { dk3app_log_i1(of->app, DK3_LL_ERROR, 263); } } break; } cellptr = cellptr->down; } } } $? "- dk3of_start_chunk %d", back return back; } /** Write Newline downwards. @param of Output filter. @param cellptr Current filter cell producing the newline. @return 1 on success, 0 on error. */ static int dk3of_nl_from_cell(dk3_of_t *of, dk3_of_cell_t *cellptr) { int back = 0; $? "+ dk3of_nl_from_cell" if((of->flags) & DK3_OF_FLAG_CRNL) { back = dk3of_bytes_from_cell( cellptr, (unsigned char const *)(dk3of_kw[1]), strlen(dk3of_kw[1]) ); } else { back = dk3of_bytes_from_cell( cellptr, (unsigned char const *)(dk3of_kw[0]), strlen(dk3of_kw[0]) ); } $? "- dk3of_nl_from_cell %d", back return back; } /** Write data from ASCII85 encoding cell downwards. @param of Output filter. @param cp Pointer to cell. @return 1 on success, 0 on error. */ static int dk3of_write_a85_cell(dk3_of_t *of, dk3_of_cell_t *cp) { int back = 0; unsigned long v; unsigned char bu[5]; $? "+ dk3of_write_a85_cell" if((cp->data).a85.nc > 0) { v = (cp->data).a85.val; bu[0] = (unsigned char)(33UL + v / dk3of_a85_factors[0]); v = v % dk3of_a85_factors[0]; bu[1] = (unsigned char)(33UL + v / dk3of_a85_factors[1]); v = v % dk3of_a85_factors[1]; bu[2] = (unsigned char)(33UL + v / dk3of_a85_factors[2]); v = v % dk3of_a85_factors[2]; bu[3] = (unsigned char)(33UL + v / dk3of_a85_factors[3]); v = v % dk3of_a85_factors[3]; bu[4] = (unsigned char)(33UL + v); $? ". %u bytes", (unsigned)(1 + (cp->data).a85.nc) back = dk3of_bytes_from_cell(cp, bu, (1 + (cp->data).a85.nc)); } else { back = 1; } $? "- dk3of_write_a85_cell %d", back return back; } /** Save a run. @param of Output filter. @param cp Filter cell. @return 1 on success, 0 on error. */ static int dk3of_psrl_save_run(dk3_of_t *of, dk3_of_cell_t *cp) { int back = 0; size_t sz; unsigned char bu[2]; sz = 257 - (cp->data).psrl.used; bu[0] = (unsigned char)sz; bu[1] = (cp->data).psrl.pc; back = dk3of_bytes_from_cell(cp, bu, 2); (cp->data).psrl.used = 0; (cp->data).psrl.same = 0; (cp->data).psrl.pc = 0x00; (cp->data).psrl.hc = 0x00; (cp->data).psrl.run = 0x00; return back; } /** Save data. @param of Output filter. @param cp Filter cell. @param final Flag: Final action for chunk. @return 1 on success, 0 on error. */ static int dk3of_psrl_save_data(dk3_of_t *of, dk3_of_cell_t *cp, int final) { size_t i; int back = 0; unsigned char c; size_t lgt; $? "+ dk3of_psrl_save_data" if(final) { /* Save data as is. */ c = (unsigned char)((cp->data).psrl.used - 1); if(dk3of_bytes_from_cell(cp, &c, 1)) { if(dk3of_bytes_from_cell(cp, (cp->data).psrl.bu, (cp->data).psrl.used)) { back = 1; } } (cp->data).psrl.used = 0; (cp->data).psrl.same = 0; (cp->data).psrl.pc = 0x00; (cp->data).psrl.hc = 0x00; (cp->data).psrl.run = 0x00; } else { /* Save data and attempt to switch into a run. */ if((cp->data).psrl.same >= 1) { if(((cp->data).psrl.same) < ((cp->data).psrl.used)) { lgt = (cp->data).psrl.used - (cp->data).psrl.same - 1; $? ". lgt = %u", (unsigned)lgt if(lgt > 0) { c = (unsigned char)(lgt - 1); if(dk3of_bytes_from_cell(cp, &c, 1)) { if(dk3of_bytes_from_cell(cp, (cp->data).psrl.bu, lgt)) { back = 1; } } for(i = 0; i < (cp->data).psrl.same + 1; i++) { ((cp->data).psrl.bu)[i] = ((cp->data).psrl.bu)[lgt + i]; } (cp->data).psrl.used = (cp->data).psrl.same + 1; if((cp->data).psrl.same >= 1) { (cp->data).psrl.run = 0x01; $? ". now in a run" } } else { back = 1; /* Nothing to do here. */ if((cp->data).psrl.same > 1) { (cp->data).psrl.run = 0x01; $? ". now in a run" } } } else { $? "! BUG" } } else { back = dk3of_psrl_save_data(of, cp, 1); } } $? "- dk3of_psrl_save_data %d", back return back; } int dk3of_end_chunk(dk3_of_t *of) { dk3_of_cell_t *cellptr; size_t sz; int back = 0; int res; $? "+ dk3of_end_chunk %s", TR_PTR(of) if(of) { if(of->top) { back = dk3of_flush_bits(of); cellptr = of->top; while(cellptr) { switch(cellptr->type) { case DK3_OF_CELL_TYPE_HEX: { if((of->flags) & DK3_OF_FLAG_FINALIZE) { res = dk3of_bytes_from_cell( cellptr, (unsigned char const *)(dk3of_kw[2]), strlen(dk3of_kw[2]) ); if(!(res)) { back = 0; } if(!dk3of_nl_from_cell(of, cellptr)) { back = 0; } } } break; case DK3_OF_CELL_TYPE_A85: { if(!dk3of_write_a85_cell(of, cellptr)) { back = 0; } if((of->flags) & DK3_OF_FLAG_FINALIZE) { res = dk3of_bytes_from_cell( cellptr, (unsigned char const *)(dk3of_kw[3]), strlen(dk3of_kw[3]) ); if(!(res)) { back = 0; } if(!dk3of_nl_from_cell(of, cellptr)) { back = 0; } } } break; case DK3_OF_CELL_TYPE_RUN_LENGTH: { if((cellptr->data).psrl.bu) { if((cellptr->data).psrl.run) { if(!dk3of_psrl_save_run(of, cellptr)) { back = 0; } } else { if(!dk3of_psrl_save_data(of, cellptr, 1)) { back = 0; } } } else { back = 0; } } break; case DK3_OF_CELL_TYPE_FLATE: { #if DK3_HAVE_ZLIB_H int cc = 1; ((cellptr->data).flate.zs)->next_in = (cellptr->data).flate.ibu; ((cellptr->data).flate.zs)->avail_in = (cellptr->data).flate.iused; while(cc) { cc = 0; ((cellptr->data).flate.zs)->next_out = (cellptr->data).flate.obu; ((cellptr->data).flate.zs)->avail_out = DK3_OF_FLATE_OUT_BUFFER_SIZE; res = deflate((cellptr->data).flate.zs, Z_FINISH); switch(res) { case Z_STREAM_END: { sz = (size_t)( DK3_OF_FLATE_OUT_BUFFER_SIZE - ((cellptr->data).flate.zs)->avail_out ); if(sz) { if(!dk3of_bytes_from_cell( cellptr, (unsigned char const *)((cellptr->data).flate.obu), sz ) ) { back = 0; } } } break; case Z_OK: { cc = 1; sz = (size_t)( DK3_OF_FLATE_OUT_BUFFER_SIZE - ((cellptr->data).flate.zs)->avail_out ); if(sz) { if(!dk3of_bytes_from_cell( cellptr, (unsigned char const *)((cellptr->data).flate.obu), sz ) ) { back = 0; } } } break; default: { back = 0; } break; } } if(deflateEnd((cellptr->data).flate.zs) != Z_OK) { back = 0; } (cellptr->data).flate.iused = 0UL; (cellptr->data).flate.ok = 0; #else back = 0; #endif } break; default: { back = 0; /* ERROR: Illegal cell type! */ if(of->app) { dk3app_log_i1(of->app, DK3_LL_ERROR, 263); } } break; } cellptr = cellptr->down; } } } $? "- dk3of_end_chunk %d", back return back; } int dk3of_bytes_from_cell(dk3_of_cell_t *cp, unsigned char const *bu, size_t sz) { dk3_app_t *app; dk3_of_t *of; int back = 0; size_t bw; $? "+ dk3of_bytes_from_cell %s %s %u", TR_PTR(cp), TR_PTR(bu), (unsigned)sz if((cp) && (bu) && (sz)) { of = NULL; app = NULL; if(cp->of) { of = (dk3_of_t *)(cp->of); if(of->app) { app = of->app; } if(cp->down) { $? ". bytes to next cell downwards" back = dk3of_bytes_to_cell(cp->down, bu, sz); } else { $? ". bytes to output stream" if(of->os) { bw = dk3stream_write_bytes(of->os, (char const *)bu, sz); if(bw == sz) { back = 1; } } else { $? "! BUG: Output filter has no destination stream!" /* BUG: Output filter has no destination stream! */ } } } else { $? "! BUG: Missing output filter pointer!" /* BUG: Missing output filter pointer! */ } } $? "- dk3of_bytes_from_cell %d", back return back; } /** Process one byte in a filter cell. @param cp Filter cell. @param uc Byte to process. @return 1 on success, 0 on error. */ static int dk3of_one_byte_to_cell(dk3_of_cell_t *cp, unsigned char uc) { dk3_of_t *of = NULL; unsigned long ul; size_t u1; size_t u2; size_t sz; int cc; int back = 0; int err; unsigned char b[5]; $? "+ dk3of_one_byte_to_cell %x", (int)uc of = (dk3_of_t *)(cp->of); switch(cp->type) { case DK3_OF_CELL_TYPE_HEX: { $? ". hex" u1 = (size_t)uc; u2 = (size_t)uc; u1 = (u1 >> 4) & 0x000FU; u2 = u2 & 0x000FU; b[0] = (unsigned char)(dk3of_hex_chars[u1]); b[1] = (unsigned char)(dk3of_hex_chars[u2]); back = dk3of_bytes_from_cell(cp, b, 2); (cp->data).ah.nl += 1; if((cp->data).ah.nl >= 35) { (cp->data).ah.nl = 0; if(cp->of) { of = (dk3_of_t *)(cp->of); if(!dk3of_nl_from_cell(of, cp)) { back = 0; } } else { back = 0; /* BUG: Stream not configured for cell! */ } } } break; case DK3_OF_CELL_TYPE_A85: { $? ". a85" ul = (unsigned long)uc; switch((cp->data).a85.nc) { case 0: { ul = ((ul << 24) & 0xFF000000UL); } break; case 1: { ul = ((ul << 16) & 0x00FF0000UL); } break; case 2: { ul = ((ul << 8) & 0x0000FF00UL); } break; default: { ul = (ul & 0x000000FFUL); } break; } (cp->data).a85.val |= ul; (cp->data).a85.nc += 1; back = 1; if((cp->data).a85.nc >= 4) { back = dk3of_write_a85_cell(of, cp); (cp->data).a85.nc = 0; (cp->data).a85.val = 0UL; (cp->data).a85.nl += 1; if((cp->data).a85.nl >= 14) { (cp->data).a85.nl = 0; if(!dk3of_nl_from_cell(of, cp)) { back = 0; } } } } break; case DK3_OF_CELL_TYPE_RUN_LENGTH: { $? ". rl start" back = 1; if((cp->data).psrl.run) { $? ". have existing run" if(uc == (cp->data).psrl.pc) { $? ". append to run" ((cp->data).psrl.bu)[(cp->data).psrl.used] = uc; (cp->data).psrl.used += 1; (cp->data).psrl.same += 1; if((cp->data).psrl.used >= 127) { if(!dk3of_psrl_save_run(of, cp)) { back = 0; } } } else { $? ". finished run" if(!dk3of_psrl_save_run(of, cp)) { back = 0; } ((cp->data).psrl.bu)[0] = uc; (cp->data).psrl.used = 1; (cp->data).psrl.pc = uc; (cp->data).psrl.hc = 0x01; } } else { $? ". no existing run" ((cp->data).psrl.bu)[(cp->data).psrl.used] = uc; (cp->data).psrl.used += 1; if((cp->data).psrl.hc) { $? ". already contents in buffer" if(uc == (cp->data).psrl.pc) { $? ". same char" (cp->data).psrl.same += 1; $? ". same %u/%u", (unsigned)((cp->data).psrl.same), (unsigned)((cp->data).psrl.used) } else { $? ". not the same char" (cp->data).psrl.same = 0; } } else { $? ". no contents in buffer yet" (cp->data).psrl.same = 0; } (cp->data).psrl.hc = 0x01; (cp->data).psrl.pc = uc; if(((cp->data).psrl.used >= 127) || ((cp->data).psrl.same >= 2)) { if(!dk3of_psrl_save_data(of, cp, 0)) { back = 0; } } } $? ". rl end" } break; case DK3_OF_CELL_TYPE_FLATE: { $? ". flate" #if DK3_HAVE_ZLIB_H if((cp->data).flate.ok) { back = 1; ((cp->data).flate.ibu)[(cp->data).flate.iused] = uc; (cp->data).flate.iused += 1; if((cp->data).flate.iused >= DK3_OF_FLATE_IN_BUFFER_SIZE) { cc = 1; ((cp->data).flate.zs)->next_in = (cp->data).flate.ibu; ((cp->data).flate.zs)->avail_in = (cp->data).flate.iused; while(cc) { cc = 0; ((cp->data).flate.zs)->next_out = (cp->data).flate.obu; ((cp->data).flate.zs)->avail_out = DK3_OF_FLATE_OUT_BUFFER_SIZE; err = deflate((cp->data).flate.zs, 0); switch(err) { case Z_OK: { if(((cp->data).flate.zs)->avail_in) { cc= 1; } sz = (size_t)( DK3_OF_FLATE_OUT_BUFFER_SIZE - ((cp->data).flate.zs)->avail_out ); if(!dk3of_bytes_from_cell(cp, (cp->data).flate.obu, sz)) { back = 0; } } break; default: { (cp->data).flate.ok = 0; } break; } } (cp->data).flate.iused = 0; } } else { /* ERROR: Previous operations failed! */ if(of->app) { dk3app_log_i1(of->app, DK3_LL_ERROR, 264); } } #else /* ERROR: Compression not supported! */ if(of->app) { dk3app_log_i1(of->app, DK3_LL_ERROR, 262); } #endif } break; } $? "- dk3of_one_byte_to_cell %d", back return back; } int dk3of_bytes_to_cell(dk3_of_cell_t *cp, unsigned char const *bu, size_t sz) { int back = 0; size_t i; unsigned char const *ptr; $? "+ dk3of_bytes_to_cell %s %s %u", TR_PTR(cp), TR_PTR(bu), (unsigned)sz if((cp) && (bu) && (sz)) { back = 1; ptr = bu; for(i = 0; i < sz; i++) { if(!dk3of_one_byte_to_cell(cp, *(ptr++))) { back = 0; } } } $? "- dk3of_bytes_to_cell %d", back return back; } int dk3of_write_bits(dk3_of_t *of, unsigned short bv, size_t sz) { size_t i; int back = 0; int bit; $? "+ dk3of_write_bits %u %u", (unsigned)bv, (unsigned)sz if((of) && (sz)) { if(sz <= 16) { back = 1; for(i = 0; i < sz; i++) { bit = 0; if(bv & dk3of_bits_in_short[sz - i - 1]) { bit = 1; } if(bit) { $? ". set bit %u", (unsigned)(of->nBits) of->bits = (of->bits) | (dk3of_bits_in_char[of->nBits]); } else { $? ". reset bit %u", (unsigned)(of->nBits) of->bits = (of->bits) & (~(dk3of_bits_in_char[of->nBits])); } of->nBits += 1; $? ". nBits now %u", (unsigned)(of->nBits) if(of->nBits >= 8) { $? ". time to flush" if(!dk3of_flush_bits(of)) { $? "! error in bit flush" back = 0; } } } } } $? "- dk3of_write_bits %d", back return back; } int dk3of_write_bytes(dk3_of_t *of, unsigned char const *bu, size_t sz) { int back = 0; unsigned char const *ptr; unsigned char uc; unsigned short us; size_t i; $? "+ dk3of_write_bytes %s %u", TR_PTR(bu), (unsigned)sz if((of) && (bu) && (sz)) { if(of->nBits) { $? ". write bit by bit" back = 1; ptr = bu; for(i = 0; i < sz; i++) { uc = *(ptr++); us = (unsigned short)uc; us &= 0x00FFU; if(!dk3of_write_bits(of, us, 8)) { back = 0; } } } else { $? ". write bytes" if(of->top) { back = dk3of_bytes_to_cell(of->top, bu, sz); } } } $? "- dk3of_write_bytes %d", back return back; } int dk3of_write_c8_string(dk3_of_t *of, char const *st) { int back = 0; size_t sl; if((of) && (st)) { sl = strlen(st); back = dk3of_write_bytes(of, (unsigned char const *)st, sl); } return back; } int dk3of_flush_bits(dk3_of_t *of) { int back = 0; $? "+ dk3of_flush_bits" if(of) { if(of->nBits) { $? ". have bits to flush %u %x", (unsigned)(of->nBits), (int)(of->bits) back = dk3of_bytes_to_cell(of->top, &(of->bits), 1); of->bits = 0x00; of->nBits = 0; } else { $? ". no bits to flush" back = 1; } } $? "- dk3of_flush_bits %d", back return back; } void dk3of_set_crnl(dk3_of_t *of, int fl) { $? "+ dk3of_set_crnl %d", fl if(of) { if(fl) { of->flags |= DK3_OF_FLAG_CRNL; } else { of->flags &= (~(DK3_OF_FLAG_CRNL)); } } $? "- dk3of_set_crnl" } void dk3of_set_finalize(dk3_of_t *of, int fl) { $? "+ dk3of_set_finalize %d", fl if(of) { if(fl) { of->flags |= DK3_OF_FLAG_FINALIZE; } else { of->flags &= (~(DK3_OF_FLAG_FINALIZE)); } } $? "- dk3of_set_finalize" } int dk3of_double_str_no_sci(dk3_of_t *of, char *buffer) { char *start; /* Start of string. */ char *eptr; /* Start of exponent substring. */ char *ptr; /* Traverse string. */ size_t lgt; /* String length. */ int dp; /* Decimal dot position. */ int exponent; /* Exponent. */ int i; /* Traverse the string. */ char chr[2]; int back = 0; chr[1] = '\0'; if ((NULL != of) && (NULL != buffer)) { eptr = NULL; start = buffer; /* Print sign. */ switch(*start) { case '-': { chr[0] = '-'; if (0 == dk3of_write_c8_string(of, chr)) { back = 0; } start++; } break; case '+': { start++; } break; } /* Find exponent substring and exponent. */ eptr = NULL; ptr = start; while(*ptr) { switch(*ptr) { case 'e': case 'E': { eptr = ptr; } break; } ptr++; } if(eptr) { *(eptr++) = '\0'; if(sscanf(eptr, "%d", &exponent) != 1) { exponent = 0; } } else { exponent = 0; } /* Find decimal dot. */ eptr = strchr(start, '.'); if(eptr) { /* Keep dot position in dp, squeeze string. */ *eptr = '\0'; dp = (int)strlen(start); *eptr = '.'; while(*eptr) { eptr[0] = eptr[1]; eptr++; } } else { /* Dot position is after the string. */ dp = (int)strlen(start); } /* Correct dot position. */ dp = dp + exponent; /* Remove leading zeroes (if any). */ while('0' == *start) { start++; dp--; } /* Remove trailing zeroes (if any). */ eptr = NULL; ptr = start; while(*ptr) { if('0' == *ptr) { if(!(eptr)) { eptr = ptr; } } else { eptr = NULL; } ptr++; } if(eptr) { *eptr = '\0'; } lgt = strlen(start); if(0 < lgt) { if(dp >= (int)lgt) { /* Decimal dot is at end or after string. */ if (0 == dk3of_write_c8_string(of, start)) { back = 0; } /* Decimal dot is after the string. */ for(i = 0; i < (dp - (int)lgt); i++) { chr[0] = '0'; if (0 == dk3of_write_c8_string(of, chr)) { back = 0; } } } else { if(dp <= 0) { /* Decimal dot is before the string. */ chr[0] = '0'; if (0 == dk3of_write_c8_string(of, chr)) { back = 0; } chr[0] = '.'; if (0 == dk3of_write_c8_string(of, chr)) { back = 0; } while(dp++ < 0) { chr[0] = '0'; if (0 == dk3of_write_c8_string(of, chr)) { back = 0; } } if (0 == dk3of_write_c8_string(of, start)) { back = 0; } } else { /* Decimal dot is in the string. */ for(i = 0; i < (int)lgt; i++) { if(dp == i) { chr[0] = '.'; if (0 == dk3of_write_c8_string(of, chr)) { back = 0; } } chr[0] = start[i]; if (0 == dk3of_write_c8_string(of, chr)) { back = 0; } } } } } else { /* No non-zero digits in string. */ chr[0] = '0'; if (0 == dk3of_write_c8_string(of, chr)) { back = 0; } } back = 1; } return back; } int dk3of_double_to_c8_no_sci(dk3_of_t *of, double x) { char buffer[64]; char *ptr; int back = 0; if (NULL != of) { sprintf(buffer, "%lg", x); ptr = buffer; while ('\0' != *ptr) { if(',' == *ptr) { *ptr = '.'; } ptr++;} back = dk3of_double_str_no_sci(of, buffer); } return back; } /* vim: set ai sw=2 : */