/* Copyright (C) 2016-2020, Dirk Krause SPDX-License-Identifier: BSD-3-Clause */ /* WARNING: This file was generated by the dkct program (see http://dktools.sourceforge.net/ for details). Changes you make here will be lost if dkct is run again! You should modify the original source and run dkct on it. Original source: dk4strmco.ctr */ /** @file dk4strmco.c The dk4strmco module. */ #line 137 "dk4strmco.ctr" #include "dk4conf.h" #if DK4_HAVE_ZLIB_H #ifndef ZLIB_H_INCLUDED #include #define ZLIB_H_INCLUDED 1 #endif #endif #if DK4_HAVE_LIMITS_H #ifndef LIMITS_H_INCLUDED #include #define LIMITS_H_INCLUDED 1 #endif #endif #include "dk4rle.h" #include "dk4a85e.h" #include "dk4strmco.h" #include "dk4mem.h" #include "dk4memrs.h" #include "dk4lzwe.h" #if DK4_HAVE_ASSERT_H #ifndef ASSERT_H_INCLUDED #include #define ASSERT_H_INCLUDED 1 #endif #endif #line 169 "dk4strmco.ctr" #ifndef DK4_STRMCO_ZBUF_SIZE #define DK4_STRMCO_ZBUF_SIZE 4096 #endif /** Compressor data structure. */ typedef struct { char zbuf[DK4_STRMCO_ZBUF_SIZE]; /**< Output buffer. */ union { #if DK4_HAVE_ZLIB_H z_stream zs; /**< Flate compression structure. */ #endif dk4_lzwe_t lzw; /**< LZW compression structure. */ } u_co; /**< Compression structures. */ union { dk4_rl_enc_t rle; /**< Run-length encoder. */ } u_pp; /**< Preprocessing structures. */ union { dk4_a85_enc_t a85; /**< ASCII-85 encoder. */ } u_oe; /**< Output encoding structures. */ dk4_stream_t *dststrm; /**< Destination stream. */ size_t ll; /**< Line length. */ int pp; /**< Preprocessing. */ int co; /**< Compression. */ int oe; /**< Output encoding. */ int fl; /**< Flags. */ } compressor_t; /** Newline. */ static char nl[] = { '\n', '\0' }; /** Carriage return and newline. */ static char crnl[] = { '\r', '\n', '\0' }; /** Finalizer for ASCII-Hex encoding. */ static char ahfin[] = { '>', '\0' }; /** Finalizer for ASCII-85 encoding. */ static char a85fin[] = { '~', '>', '\0' }; /** Hexadecimal digits using lower case characters. */ static char lower[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', '\0' }; /** Hexadecimal digits using upper case characters. */ static char upper[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', '\0' }; /** Write newline to destination stream. @param co Compressor structure. @return 1 on success, 0 on error. */ static int dk4strmco_nl(compressor_t *co) { int back = 0; #line 264 "dk4strmco.ctr" #if DK4_USE_ASSERT assert(NULL != co); #endif if (0 != (DK4_STRMCO_FL_CR_NL & (co->fl))) { back = dk4stream_write(co->dststrm, crnl, 2, NULL); } else { back = dk4stream_write(co->dststrm, nl, 1, NULL); } #line 274 "dk4strmco.ctr" return back; } /** Write bytes to compressor at output encoding level. @param co Compressor to write to. @param b Buffer start address. @param sz Number of bytes to write. @param szo Address of variable for number of bytes written, may be NULL. @return 1 on success, 0 on error. */ static int dk4strmco_co_oe( compressor_t *co, const char *b, size_t sz, size_t *szo ) { char buf[8]; /* Buffer for hexadecimal digits. */ const char *dptr; /* Pointer to A85 encoding result. */ size_t osz = 0; /* Number of bytes processed. */ size_t szd = 0; /* A85 encoding result length. */ size_t i = 0; /* Index of current byte to process. */ size_t j = 0; /* Index of cur out char. */ int back = 0; /* Function result. */ int res; /* Result from various operations. */ unsigned us; /* Index in hex digits array. */ unsigned char uc; /* UC version of current character */ #line 307 "dk4strmco.ctr" #if DK4_USE_ASSERT assert(NULL != co); assert(NULL != b); assert(0 < sz); #endif switch (co->oe) { case DK4_STRMCO_OE_ASCII85 : { #line 315 "dk4strmco.ctr" back = 1; for (i = 0; ((i < sz) && (1 == back)); i++) { switch (dk4a85_enc_add(&(co->u_oe.a85), b[i], NULL)) { case DK4_EDSTM_ACCEPT : { osz++; } break; case DK4_EDSTM_FINISHED : { dptr = NULL; szd = 0; res = dk4a85_enc_output( &dptr, &szd, &(co->u_oe.a85), NULL ); if (0 < res) { if (0 < szd) { #if VERSION_BEFORE_20161019 res = dk4stream_write( co->dststrm, dptr, szd, NULL ); if (0 < res) { osz++; co->ll += szd; if (0 != (DK4_STRMCO_FL_NL_OE & (co->fl))) { if (74 <= co->ll) { res = dk4strmco_nl(co); if (0 < res) { co->ll = 0; } else { back = 0; } } } } else { back = 0; } #else back = 1; for (j = 0; ((j < szd) && (1 == back)); j++) { res = dk4stream_write_byte( co->dststrm, dptr[j], NULL ); if (0 < res) { osz++; co->ll += 1; if (75 <= co->ll) { res = dk4strmco_nl(co); if (0 < res) { co->ll = 0; } else { back = 0; } } } else { back = 0; } } #endif } else { osz++; } } else { back = 0; } } break; default : { back = 0; } break; } } } break; case DK4_STRMCO_OE_HEX : { #line 392 "dk4strmco.ctr" back = 1; buf[2] = '\0'; for (i = 0; ((i < sz) && (1 == back)); i++) { uc = (unsigned char)(b[i]); us = 0x000FU & ((unsigned char)uc); if (0 != (DK4_STRMCO_FL_UPPER_OE & (co->fl))) { buf[1] = upper[us]; } else { buf[1] = lower[us]; } us = 0x000FU & (((unsigned char)uc) >> 4); if (0 != (DK4_STRMCO_FL_UPPER_OE & (co->fl))) { buf[0] = upper[us]; } else { buf[0] = lower[us]; } res = dk4stream_write(co->dststrm, buf, 2, NULL); co->ll += 2; if (0 < res) { osz++; if (0 != (DK4_STRMCO_FL_NL_OE & (co->fl))) { if (78 <= co->ll) { res = dk4strmco_nl(co); if (0 < res) { co->ll = 0; } else { back = 0; } } } } else { back = 0; } } } break; default : { #line 433 "dk4strmco.ctr" back = dk4stream_write(co->dststrm, b, sz, NULL); if (0 != back) { osz = sz; } } break; } if (NULL != szo) { *szo = osz; } #line 441 "dk4strmco.ctr" return back; } /** Write bytes to compressor at compression level. @param co Compressor to write to. @param b Buffer start address. @param sz Number of bytes to write. @param szo Address of variable for number of bytes written, may be NULL. @return 1 on success, 0 on error. */ static int dk4strmco_co_co( compressor_t *co, const char *b, size_t sz, size_t *szo ) { const unsigned char *cptr; size_t osz = 0; /* Number of bytes processed successfully. */ size_t used = 0; /* Used bytes in output buffer. */ size_t i = 0; /* Index of current LZW byte to process. */ size_t lzwsz = 0; /* Bytes from LZW compression. */ int back = 0; /* Function result. */ int res = 0; /* Result from various operations. */ #line 470 "dk4strmco.ctr" #if DK4_USE_ASSERT assert(NULL != co); assert(NULL != b); assert(0 < sz); #endif switch (co->co) { case DK4_STRMCO_CO_FLATE : { #line 478 "dk4strmco.ctr" if (((dk4_um_t)(UINT_MAX)) >= ((dk4_um_t)sz)) { back = 1; co->u_co.zs.next_in = (unsigned char *)b; co->u_co.zs.avail_in = (unsigned int)sz; do { co->u_co.zs.next_out = (unsigned char *)(&(co->zbuf[0])); co->u_co.zs.avail_out = DK4_STRMCO_ZBUF_SIZE; res = deflate(&(co->u_co.zs), Z_NO_FLUSH); switch (res) { case Z_OK : { used = DK4_STRMCO_ZBUF_SIZE - co->u_co.zs.avail_out; if (0 < used) { res = dk4strmco_co_oe( co, &(co->zbuf[0]), used, NULL ); if (0 < res) { osz = sz - co->u_co.zs.avail_in; } else { back = 0; } } else { osz = sz - co->u_co.zs.avail_in; } } break; default : { back = 0; } break; } } while ((0 < co->u_co.zs.avail_in) && (1 == back)); if (NULL != szo) { *szo = osz; } } else { } } break; case DK4_STRMCO_CO_LZW : { back = 1; for (i = 0; ((1 == back) && (i < sz)); i++) { res = dk4lzwe_add(&(co->u_co.lzw), (unsigned char)(b[i]), NULL); switch (res) { case DK4_EDSTM_ACCEPT : { osz++; } break; case DK4_EDSTM_FINISHED : { cptr = NULL; lzwsz = 0; res = dk4lzwe_output( &cptr, &lzwsz, &(co->u_co.lzw), NULL ); if ((0 != res) && (NULL != cptr) && (0 < lzwsz)) { back = dk4strmco_co_oe( co, (const char *)cptr, lzwsz, NULL ); if (0 != back) { osz++; } } else { back = 0; } } break; case DK4_EDSTM_ERROR : { back = 0; } break; } } if (NULL != szo) { *szo = osz; } } break; default : { #line 548 "dk4strmco.ctr" back = dk4strmco_co_oe(co, b, sz, szo); } break; } #line 552 "dk4strmco.ctr" return back; } /** Write bytes to compressor at preprocessor level. @param co Compressor to write to. @param b Buffer start address. @param sz Number of bytes to write. @param szo Address of variable for number of bytes written, may be NULL. @return 1 on success, 0 on error. */ static int dk4strmco_co_write( compressor_t *co, const char *b, size_t sz, size_t *szo ) { const unsigned char *rleptr; /* RL encoding result */ size_t osz = 0; /* Bytes processed successfully */ size_t i; /* Running index of current byte */ size_t rlesz; /* Size of RL encoding result */ int back = 0; /* Function result */ int res; /* Result from various operations */ #line 580 "dk4strmco.ctr" #if DK4_USE_ASSERT assert(NULL != co); #endif switch (co->pp) { case DK4_STRMCO_PP_RUNLENGTH : { #line 586 "dk4strmco.ctr" back = 1; for (i = 0; ((i < sz) && (0 != back)); i++) { switch (dk4rle_add(&(co->u_pp.rle),(unsigned char)(b[i]),NULL)) { case DK4_EDSTM_FINISHED : { rleptr = NULL; rlesz = 0; res = dk4rle_output( &rleptr, &rlesz, &(co->u_pp.rle), NULL ); if (0 != res) { res = dk4strmco_co_co( co, (const char *)rleptr, rlesz, NULL ); if (0 != res) { osz++; } else { back = 0; } } else { back = 0; } } break; case DK4_EDSTM_ERROR : { back = 0; } break; default : { osz++; } break; } } if (NULL != szo) { *szo = osz; } } break; default : { #line 623 "dk4strmco.ctr" back = dk4strmco_co_co(co, b, sz, szo); } break; } #line 627 "dk4strmco.ctr" return back; } /** Flush data in output encoders if used. @param co Compressor structure. @return 1 on success, 0 on error. */ static int dk4strmco_co_oe_close(compressor_t *co) { const char *dptr = NULL; size_t sz = 0; size_t j = 0; int back = 1; int res = 0; #line 646 "dk4strmco.ctr" #if DK4_USE_ASSERT assert(NULL != co); #endif switch (co->oe) { case DK4_STRMCO_OE_ASCII85 : { #line 652 "dk4strmco.ctr" switch (dk4a85_enc_finish(&(co->u_oe.a85), NULL)) { case DK4_EDSTM_FINISHED : { if (0 < dk4a85_enc_output(&dptr,&sz,&(co->u_oe.a85),NULL)) { if (0 < sz) { #if VERSION_BEFORE_20161019 back = dk4stream_write(co->dststrm, dptr, sz, NULL); #else back = 1; for (j = 0; ((j < sz) && (1 == back)); j++) { res = dk4stream_write_byte( co->dststrm, dptr[j], NULL ); if (0 < res) { co->ll += 1; if (75 <= co->ll) { res = dk4strmco_nl(co); if (0 < res) { co->ll = 0; } else { back = 0; } } } else { back = 0; } } #endif } } else { back = 0; } } break; } if (0 != (DK4_STRMCO_FL_EOD_OE & (co->fl))) { #line 690 "dk4strmco.ctr" res = dk4stream_write(co->dststrm, a85fin, 2, NULL); if (0 == res) { back = 0; } } if (0 != (DK4_STRMCO_FL_NL_OE & (co->fl))) { #line 697 "dk4strmco.ctr" if (0 == dk4strmco_nl(co)) { back = 0; } } } break; case DK4_STRMCO_OE_HEX : { if (0 != (DK4_STRMCO_FL_EOD_OE & (co->fl))) { #line 705 "dk4strmco.ctr" back = dk4stream_write(co->dststrm, ahfin, 1, NULL); } if (0 != (DK4_STRMCO_FL_NL_OE & (co->fl))) { #line 709 "dk4strmco.ctr" if (0 == dk4strmco_nl(co)) { back = 0; } } } break; } #line 716 "dk4strmco.ctr" return back; } /** Flush data from flate compressor if used. @param co Compressor structure. @return 1 on success, 0 on error. */ static int dk4strmco_co_co_close(compressor_t *co) { const unsigned char *cptr; size_t used = 0; int back = 1; int zres = Z_OK; int res = 0; #line 735 "dk4strmco.ctr" #if DK4_USE_ASSERT assert(NULL != co); #endif switch (co->co) { case DK4_STRMCO_CO_FLATE : { #line 741 "dk4strmco.ctr" co->u_co.zs.next_in = (unsigned char *)nl; co->u_co.zs.avail_in = 0; do { co->u_co.zs.next_out = (unsigned char *)(&(co->zbuf[0])); co->u_co.zs.avail_out = DK4_STRMCO_ZBUF_SIZE; zres = deflate(&(co->u_co.zs), Z_FINISH); #line 748 "dk4strmco.ctr" switch (zres) { case Z_OK : case Z_STREAM_END : { used = DK4_STRMCO_ZBUF_SIZE - co->u_co.zs.avail_out; #line 752 "dk4strmco.ctr" if (0 < used) { res = dk4strmco_co_oe(co,&(co->zbuf[0]),used,NULL); if (0 == res) { back = 0; } } } break; default : { back = 0; } break; } } while ((Z_OK == zres) && (1 == back)); #line 765 "dk4strmco.ctr" if (Z_OK != deflateEnd(&(co->u_co.zs))) { back = 0; } } break; case DK4_STRMCO_CO_LZW : { res = dk4lzwe_finish(&(co->u_co.lzw), NULL); switch (res) { case DK4_EDSTM_FINISHED : { cptr = NULL; used = 0; res = dk4lzwe_output( &cptr, &used, &(co->u_co.lzw), NULL ); if ((0 != res) && (NULL != cptr) && (0 < used)) { back = dk4strmco_co_oe( co, (const char *)cptr, used, NULL ); } else { back = 0; } } break; case DK4_EDSTM_ERROR : { back = 0; } break; } } break; } #line 794 "dk4strmco.ctr" return back; } /** Flush data from run-length encoder if used. @param co Compressor structure. @return 1 on success, 0 on error. */ static int dk4strmco_co_pp_close(compressor_t *co) { const unsigned char *dptr = NULL; size_t szd = 0; int back = 1; int res; #line 812 "dk4strmco.ctr" #if DK4_USE_ASSERT assert(NULL != co); #endif switch (co->pp) { case DK4_STRMCO_PP_RUNLENGTH : { #line 818 "dk4strmco.ctr" switch (dk4rle_finish(&(co->u_pp.rle), NULL)) { case DK4_EDSTM_ACCEPT : { } break; case DK4_EDSTM_FINISHED : { #line 823 "dk4strmco.ctr" if (0 < dk4rle_output(&dptr, &szd, &(co->u_pp.rle), NULL)) { res = dk4strmco_co_write( co, (const char *)dptr, szd, NULL ); if (0 == res) { #line 828 "dk4strmco.ctr" back = 0; } } else { #line 832 "dk4strmco.ctr" back = 0; } } break; default : { } break; } } break; } #line 841 "dk4strmco.ctr" return back; } /** Finish output (flush data stored in the encoders). @param co Compressor structure. @return 1 on success, 0 on error. */ static int dk4strmco_co_close(compressor_t *co) { int back = 1; #line 856 "dk4strmco.ctr" #if DK4_USE_ASSERT assert(NULL != co); #endif /* Flush preprocessor (run-length encoder). */ if (0 == dk4strmco_co_pp_close(co)) { back = 0; } /* Flush compressor (flate stream). */ if (0 == dk4strmco_co_co_close(co)) { back = 0; } /* Flush output encoder (ASCII-Hex or ASCII-85 encoder). */ if (0 == dk4strmco_co_oe_close(co)) { back = 0; } /* Release memory. */ #line 877 "dk4strmco.ctr" if (0 == dk4mem_reset_secure(co, sizeof(compressor_t), NULL)) { back = 0; } #line 881 "dk4strmco.ctr" dk4mem_free(co); #line 883 "dk4strmco.ctr" return back; } static void dk4strmco_handler(dk4_stream_api_t *api) { compressor_t *co = NULL; #line 894 "dk4strmco.ctr" #if DK4_USE_ASSERT assert(NULL != api); #endif if (NULL != api) { api->res = 0; api->sz_out = 0; co = (compressor_t *)(api->d); switch (api->cmd) { case DK4_STREAM_API_WRITE : { #line 903 "dk4strmco.ctr" if (0 < api->sz_in) { api->res = dk4strmco_co_write( co, api->b, api->sz_in, &(api->sz_out) ); } else { api->res = 1; } } break; case DK4_STREAM_API_FLUSH : { #line 913 "dk4strmco.ctr" /* Do nothing but indicate success. Otherwise closing a stream will return an error. */ api->res = 1; } break; case DK4_STREAM_API_CLOSE : { #line 920 "dk4strmco.ctr" api->res = dk4strmco_co_close(co); } break; case DK4_STREAM_API_ZERO_READ_IS_EOF : { #line 923 "dk4strmco.ctr" api->res = 0; } break; default : { #line 926 "dk4strmco.ctr" /* Error: Functions not available */ } break; } } #line 931 "dk4strmco.ctr" } dk4_stream_t * dk4strmco_open( dk4_stream_t *strm, enum dk4_strmco_pp pp, enum dk4_strmco_co co, enum dk4_strmco_oe oe, int fl, dk4_er_t *erp ) { dk4_stream_t *back = NULL; compressor_t *cc = NULL; #line 948 "dk4strmco.ctr" #if DK4_USE_ASSERT assert(NULL != strm); #endif if (NULL != strm) { /* Allocate compressor and set up. */ #line 955 "dk4strmco.ctr" cc = dk4mem_new(compressor_t,1,erp); if (NULL != cc) { cc->dststrm = strm; cc->pp = pp; cc->co = co; cc->oe = oe; cc->fl = fl; cc->ll = 0; switch (pp) { case DK4_STRMCO_PP_RUNLENGTH : { #line 966 "dk4strmco.ctr" dk4rle_init( &(cc->u_pp.rle), ((0 != (DK4_STRMCO_FL_EOD_PP & fl)) ? 1 : 0), NULL ); } break; default : { } break; } switch (co) { case DK4_STRMCO_CO_FLATE : { #line 978 "dk4strmco.ctr" cc->u_co.zs.zalloc = Z_NULL; cc->u_co.zs.zfree = Z_NULL; cc->u_co.zs.opaque = Z_NULL; #line 982 "dk4strmco.ctr" if (Z_OK != deflateInit(&(cc->u_co.zs), 9)) { #line 984 "dk4strmco.ctr" dk4mem_free(cc); cc = NULL; #line 987 "dk4strmco.ctr" } } break; case DK4_STRMCO_CO_LZW : { #line 991 "dk4strmco.ctr" if (0 == dk4lzwe_init(&(cc->u_co.lzw), NULL)) { #line 993 "dk4strmco.ctr" dk4mem_free(cc); cc = NULL; #line 996 "dk4strmco.ctr" } } break; default : { } break; } switch (oe) { case DK4_STRMCO_OE_ASCII85 : { #line 1004 "dk4strmco.ctr" dk4a85_enc_init(&(cc->u_oe.a85), 1, NULL); } break; default : { } break; } } #if TRACE_DEBUG else { #line 1012 "dk4strmco.ctr" } #endif /* If the compressor was set up successfully, create stream. */ if (NULL != cc) { #line 1018 "dk4strmco.ctr" back = dk4stream_open( cc, dk4strmco_handler, DK4_STREAM_WRITE, 0, 4096, erp ); /* When failed to create stream, we must release the compressor. */ if (NULL == back) { /* Release dynamic resources assigned to components. */ #line 1029 "dk4strmco.ctr" switch (co) { case DK4_STRMCO_CO_FLATE : { #line 1032 "dk4strmco.ctr" (void)deflateEnd(&(cc->u_co.zs)); } break; case DK4_STRMCO_CO_LZW : { #line 1036 "dk4strmco.ctr" (void)dk4lzwe_finish(&(cc->u_co.lzw), NULL); } break; default : { } break; } #line 1042 "dk4strmco.ctr" dk4mem_free(cc); } #if TRACE_DEBUG else { #line 1046 "dk4strmco.ctr" } #endif } } else { dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); } #line 1054 "dk4strmco.ctr" return back; } /* vim: set ai sw=4 ts=4 : */