%% options copyright owner = Dirk Krause copyright year = 2015-xxxx license = bsd %% header /** @file dk4tsp08.h Text stream processing for 8 bit characters. CRT on Windows: Optional. */ #ifndef DK4CONF_H_INCLUDED #include "dk4conf.h" #endif #ifndef DK4TYPES_H_INCLUDED #include "dk4types.h" #endif #ifndef DK4ERROR_H_INCLUDED #include "dk4error.h" #endif #ifndef DK4BOM_H_INCLUDED #include "dk4bom.h" #endif #ifndef DK4TSP_H_INCLUDED #include "dk4tsp.h" #endif #ifndef DK4UTF8_H_INCLUDED #include "dk4utf8.h" #endif #ifndef DK4UTF16_H_INCLUDED #include "dk4utf16.h" #endif #ifndef DK4C32_H_INCLUDED #include "dk4c32.h" #endif /** Handler function for single characters. @param obj Object to modify while processing the character. @param c Character to process. @param pos Current position in file or data stream. @param erp Error report, may be NULL. @return DK4_TSP_RES_OK if the character was processed successfully, DK4_TSP_RES_ERROR if there was an error but we can continue, DK4_TSP_RES_FATAL if there was a fatal error so we should abort processing. */ typedef int dk4_c8_handler_t( void *obj, char c, dk4_text_stream_position_t *pos, dk4_er_t *erp ); /** Handler function for text lines. @param obj Object to modify while processing the character. @param line Text line to process. @param lineno Current line number. @param erp Error report, may be NULL. @return DK4_TSP_RES_OK if the character was processed successfully, DK4_TSP_RES_ERROR if there was an error but we can continue, DK4_TSP_RES_FATAL if there was a fatal error so we should abort processing. */ typedef int dk4_c8_line_handler_t( void *obj, char *line, dk4_um_t lineno, dk4_er_t *erp ); /** Structure for 8 bit character processing. */ typedef struct { union { dk4_utf8_decoder_t u08; /**< UTF-8 decoder. */ dk4_utf16_byte_decoder_t u16; /**< UTF-16 decoder. */ dk4_c32_byte_decoder_t c32; /**< 32 bit char decoder. */ } dec; /**< Input decoder. */ dk4_bom_detector_t bomd; /**< BOM detector. */ dk4_text_stream_position_t pos; /**< Current position. */ dk4_er_t er_en; /**< Errors in input decoding. */ dk4_er_t er_pr; /**< Errors in processing. */ union { dk4_c8_line_handler_t *lh; /**< Handler function for lines. */ dk4_c8_handler_t *ch; /**< Handler function for char. */ } fct; /**< Handler function. */ char *inbuf; /**< Buffer for input line. */ void *obj; /**< Object to modify in processing. */ size_t in_sz; /**< Size of input line buffer. */ size_t in_us; /**< Used bytes in input line buffer. */ int upt; /**< Flag: Enable UTF-8 pass through. */ int ief; /**< Input encoding found. */ int iee; /**< Input encoding expected. */ int pen; /**< Encoding for processing. */ int pst; /**< Processing stage. */ int pth; /**< Flag: Pass through. */ } dk4_tsp08_t; #ifdef __cplusplus extern "C" { #endif /** Set up processor for byte by byte processing. @param tsp Processor to set up. @param obj Object to modify when processing input, may be NULL. @param fct Handler function to call for each character. @param pre Encoding required for processing. @param eie Expected input encoding. @param erp Error report, may be NULL. @return 1 on success, 0 on error. Error codes: - DK4_E_INVALID_ARGUMENTS
if tsp or fct is NULL or pre is not an encoding for 8-bit characters. */ int dk4tsp08_setup_char( dk4_tsp08_t *tsp, void *obj, dk4_c8_handler_t *fct, int pre, int eie, dk4_er_t *erp ); /** Set up processor for line processing. @param tsp Processor to set up. @param obj Object to modify when processing input, may be NULL. @param fct Handler function to invoke for each line. @param inbuf Input line buffer. @param szin Size of input line buffer. @param pre Encoding required for processing. @param eie Expected input encoding. @param erp Error report, may be NULL. @return 1 on success, 0 on error. Error codes: - DK4_E_INVALID_ARGUMENTS
if tsp, fct or inbuf is NULL, szin is 0 or pre is not a valid encoding for 8-bit characters. */ int dk4tsp08_setup_line( dk4_tsp08_t *tsp, void *obj, dk4_c8_line_handler_t *fct, char *inbuf, size_t szin, int pre, int eie, dk4_er_t *erp ); /** Enable or disable pass-through of UTF-8 encoded data. Use this function after dk4tsp08_setup_line() or dk4tsp08_setup_char() but before adding the first byte. @param tsp Text stream processor to configure. @param fl Flag: Enabled. */ void dk4tsp08_enable_utf8_pass_through(dk4_tsp08_t *tsp, int fl); /** Add one single byte. @param tsp Text stream processor. @param inbyte Byte to process. @return DK4_TSP_RES_OK if the character was processed successfully, DK4_TSP_RES_ERROR if there was an error but we can continue, DK4_TSP_RES_FATAL if there was a fatal error so we should abort processing. */ int dk4tsp08_add_one_byte( dk4_tsp08_t *tsp, unsigned char inbyte ); /** Add multiple bytes. @param tsp Text stream processor. @param buffer Buffer start address. @param sz Number of bytes in buffer. @return DK4_TSP_RES_OK if the character was processed successfully, DK4_TSP_RES_ERROR if there was an error but we can continue, DK4_TSP_RES_FATAL if there was a fatal error so we should abort processing. */ int dk4tsp08_add_bytes( dk4_tsp08_t *tsp, const unsigned char *buffer, size_t sz ); /** Finish processing. @param tsp Text stream processor. @return DK4_TSP_RES_OK if processing was finished successfully, DK4_TSP_RES_ERROR if there was an error, DK4_TSP_RES_FATAL if there was a fatal error. */ int dk4tsp08_finish(dk4_tsp08_t *tsp); /** Retrieve error reports for encoding/decoding and processing. @param er_en Destination error report buffer for encoding/decoding. @param er_pr Destination error report buffer for processing. @param tsp Text stream processor to retrieve errors from. Error codes er_en: - DK4_E_BUFFER_TOO_SMALL
if the input buffer provided in dk4tsp08_setup_line() is too small, - DK4_E_INVALID_ARGUMENTS
if no character processing function was provided, - DK4_E_DECODING_FAILED
if there were decoding errors, - DK4_E_ENCODING_FAILED
if there were encoding errors. Error codes er_pr: - The error codes returned in er_pr depend on the processing function. */ void dk4tsp08_get_errors(dk4_er_t *er_en, dk4_er_t *er_pr, dk4_tsp08_t *tsp); #ifdef __cplusplus } #endif %% module #include "dk4tsp.h" #include "dk4tsp08.h" #include "dk4mem.h" #include "dk4enc.h" #include "dk4ansi.h" #include "dk4utf8.h" #include "dk4utf16.h" #include "dk4c32.h" #include "dk4bom.h" $!trace-include /** Initialize text stream processor structure. @param tsp Text stream processor to set up. @param eie Expected input encoding. */ static void dk4tsp08_init(dk4_tsp08_t *tsp, int eie) { $? "+ dk4tsp08_init" DK4_MEMRES(tsp, sizeof(dk4_tsp08_t)); dk4bom_detect_init(&(tsp->bomd), eie); dk4error_init(&(tsp->er_en)); dk4error_init(&(tsp->er_pr)); tsp->inbuf = NULL; tsp->obj = NULL; tsp->in_sz = 0; tsp->in_us = 0; tsp->ief = eie; tsp->iee = eie; tsp->upt = 0; tsp->pen = 0; $? ". pen = 0" tsp->pst = 0; tsp->pth = 0; (tsp->pos).bytes = (dk4_um_t)0UL; (tsp->pos).chars = (dk4_um_t)1UL; $? ". chars = 1" (tsp->pos).lineno = (dk4_um_t)1UL; (tsp->pos).charil = (dk4_um_t)1UL; $? "- dk4tsp08_init" } /** Initialize decoder for found input encoding. @param tsp Text stream processor. */ static void dk4tsp08_initialize_decoder(dk4_tsp08_t *tsp) { $? "+ dk4tsp08_initialize_decoder" if (0 == tsp->pth) { switch (tsp->ief) { case DK4_FILE_ENCODING_UTF8: { dk4utf8_init(&((tsp->dec).u08)); } break; case DK4_FILE_ENCODING_UTF16_LE: { dk4utf16_byte_init(&((tsp->dec).u16), 0); } break; case DK4_FILE_ENCODING_UTF16_BE: { dk4utf16_byte_init(&((tsp->dec).u16), 1); } break; case DK4_FILE_ENCODING_32_LE: { dk4c32_decoder_init(&((tsp->dec).c32), 0); } break; case DK4_FILE_ENCODING_32_BE: { dk4c32_decoder_init(&((tsp->dec).c32), 1); } break; } } $? "- dk4tsp08_initialize_decoder" } /** Process group of characters (one UTF-8 encoded 32 bit character). @param tsp Text stream processor. @param buf Buffer containing characters to process. @param sz Number of characters in buffer. @return DK4_TSP_RES_OK if the characters were processed successfully, DK4_TSP_RES_ERROR if there was an error but we can continue, DK4_TSP_RES_FATAL if there was a fatal error so we should abort processing. */ static int dk4tsp08_process_group(dk4_tsp08_t *tsp, char *buf, size_t sz) { size_t i; int back = DK4_TSP_RES_FATAL; int res; $? "+ dk4tsp08_process_group %u", (unsigned)sz /* Increase character numbers */ (tsp->pos).chars += (dk4_um_t)1UL; $? ". increase chars %u", (unsigned)((tsp->pos).chars) (tsp->pos).charil += (dk4_um_t)1UL; /* Decide between line by line or char by char processing */ if ((NULL != tsp->inbuf) && (0 < tsp->in_sz) && (NULL != (tsp->fct).lh)) { /* Line processing */ if (sz < tsp->in_sz) { if ((tsp->in_sz - sz) > tsp->in_us) { back = DK4_TSP_RES_OK; DK4_MEMCPY( &((tsp->inbuf)[tsp->in_us]), buf, sz ); tsp->in_us += sz; if ((1 == sz) && ('\n' == buf[0])) { back = DK4_TSP_RES_FATAL; if (tsp->in_us < tsp->in_sz) { (tsp->inbuf)[tsp->in_us] = '\0'; back = (*((tsp->fct).lh))( tsp->obj,tsp->inbuf,(tsp->pos).lineno,&(tsp->er_pr) ); } else { /* ERROR: Line too long! */ dk4error_set_with_position( &(tsp->er_en), DK4_E_BUFFER_TOO_SMALL, (tsp->pos).bytes, (tsp->pos).lineno, (tsp->pos).chars, (tsp->pos).charil ); } tsp->in_us = 0; } } else { /* ERROR: Line too long! */ dk4error_set_with_position( &(tsp->er_en), DK4_E_BUFFER_TOO_SMALL, (tsp->pos).bytes, (tsp->pos).lineno, (tsp->pos).chars, (tsp->pos).charil ); } } else { /* ERROR: Line too long! */ dk4error_set_with_position( &(tsp->er_en), DK4_E_BUFFER_TOO_SMALL, (tsp->pos).bytes, (tsp->pos).lineno, (tsp->pos).chars, (tsp->pos).charil ); } } else { /* Direct char processing */ if (NULL != (tsp->fct).ch) { back = DK4_TSP_RES_OK; for (i = 0; i < sz; i++) { res = (*((tsp->fct).ch))(tsp->obj, buf[i], &(tsp->pos), &(tsp->er_pr)); switch (res) { case DK4_TSP_RES_FATAL: { back = DK4_TSP_RES_FATAL; } break; case DK4_TSP_RES_ERROR: { if (DK4_TSP_RES_OK == back) { back = DK4_TSP_RES_ERROR; } } break; } } } else { dk4error_set_with_position( &(tsp->er_en), DK4_E_INVALID_ARGUMENTS, (tsp->pos).bytes, (tsp->pos).lineno, (tsp->pos).chars, (tsp->pos).charil ); } } /* After newline correct line number and position in line */ if (1 == sz) { if ('\n' == buf[0]) { (tsp->pos).lineno += (dk4_um_t)1UL; (tsp->pos).charil = (dk4_um_t)1UL; } } $? "- dk4tsp08_process_group %d", back return back; } /** Normal processing for one byte. @param tsp Text stream processor. @param inbyte Byte to process. @return Operation result, one from DK4_TSP_RES_OK, DK4_TSP_RES_ERROR or DK4_TSP_RES_FATAL. */ static int dk4tsp08_process_byte( dk4_tsp08_t *tsp, unsigned char inbyte ) { unsigned char buf[8]; dk4_c32_t c32; size_t sz; int back = DK4_TSP_RES_FATAL; int cuc32 = 0; int res = 0; unsigned char uc = '\0'; char c08; $? "+ dk4tsp08_process_byte %02x", (int)inbyte if (0 != tsp->pth) { $? ". pass through" back = dk4tsp08_process_group(tsp, (char *)(&inbyte), 1); } else { $? ". decode and encode" /* Decode and process */ switch (tsp->ief) { case DK4_FILE_ENCODING_ASCII: { $? ". ASCII found" c32 = (dk4_c32_t)inbyte; cuc32 = 1; } break; case DK4_FILE_ENCODING_ANSI: { $? ". ANSI found" if (0 != dk4ansi_decode(&c32, inbyte)) { cuc32 = 1; } else { $? "! ANSI decoding failed" dk4error_set_with_position( &(tsp->er_en), DK4_E_DECODING_FAILED, (tsp->pos).bytes, (tsp->pos).lineno, (tsp->pos).chars, (tsp->pos).charil ); } } break; case DK4_FILE_ENCODING_UTF8: { $? ". UTF-8 found" res = dk4utf8_add(&((tsp->dec).u08), inbyte); switch (res) { case DK4_EDSTM_ERROR: { $? "! UTF-8 decoding failed" /* Decoding error */ dk4error_set_with_position( &(tsp->er_en), DK4_E_DECODING_FAILED, (tsp->pos).bytes, (tsp->pos).lineno, (tsp->pos).chars, (tsp->pos).charil ); } break; case DK4_EDSTM_FINISHED: { c32 = dk4utf8_get(&((tsp->dec).u08)); cuc32 = 1; dk4utf8_init(&((tsp->dec).u08)); } break; case DK4_EDSTM_ACCEPT: { back = DK4_TSP_RES_OK; } break; } } break; case DK4_FILE_ENCODING_UTF16_LE: { $? ". UTF-16.LSB found" res = dk4utf16_byte_add(&((tsp->dec).u16), inbyte); switch (res) { case DK4_EDSTM_ERROR: { $? "! UTF-16.LSB failed" /* Decoding error */ dk4error_set_with_position( &(tsp->er_en), DK4_E_DECODING_FAILED, (tsp->pos).bytes, (tsp->pos).lineno, (tsp->pos).chars, (tsp->pos).charil ); } break; case DK4_EDSTM_FINISHED: { c32 = dk4utf16_byte_get(&((tsp->dec).u16)); cuc32 = 1; dk4utf16_byte_init(&((tsp->dec).u16), 0); } break; case DK4_EDSTM_ACCEPT: { back = DK4_TSP_RES_OK; } break; } } break; case DK4_FILE_ENCODING_UTF16_BE: { $? ". UTF-16.MSB found" res = dk4utf16_byte_add(&((tsp->dec).u16), inbyte); switch (res) { case DK4_EDSTM_ERROR: { $? "! UTF-16.MSB failed" /* Decoding error */ dk4error_set_with_position( &(tsp->er_en), DK4_E_DECODING_FAILED, (tsp->pos).bytes, (tsp->pos).lineno, (tsp->pos).chars, (tsp->pos).charil ); } break; case DK4_EDSTM_FINISHED: { c32 = dk4utf16_byte_get(&((tsp->dec).u16)); cuc32 = 1; dk4utf16_byte_init(&((tsp->dec).u16), 1); } break; case DK4_EDSTM_ACCEPT: { back = DK4_TSP_RES_OK; } break; } } break; case DK4_FILE_ENCODING_32_LE: { $? ". C32.LSB found" res = dk4c32_decoder_add(&((tsp->dec).c32), inbyte); switch (res) { case DK4_EDSTM_ERROR: { $? "! C32.LSB failed" /* Decoding error */ dk4error_set_with_position( &(tsp->er_en), DK4_E_DECODING_FAILED, (tsp->pos).bytes, (tsp->pos).lineno, (tsp->pos).chars, (tsp->pos).charil ); } break; case DK4_EDSTM_FINISHED: { c32 = dk4c32_decoder_get(&((tsp->dec).c32)); cuc32 = 1; dk4c32_decoder_init(&((tsp->dec).c32), 0); } break; case DK4_EDSTM_ACCEPT: { back = DK4_TSP_RES_OK; } break; } } break; case DK4_FILE_ENCODING_32_BE: { $? ". C32.MSB found" res = dk4c32_decoder_add(&((tsp->dec).c32), inbyte); switch (res) { case DK4_EDSTM_ERROR: { $? "! C32.MSB failed" /* Decoding error */ dk4error_set_with_position( &(tsp->er_en), DK4_E_DECODING_FAILED, (tsp->pos).bytes, (tsp->pos).lineno, (tsp->pos).chars, (tsp->pos).charil ); } break; case DK4_EDSTM_FINISHED: { c32 = dk4c32_decoder_get(&((tsp->dec).c32)); cuc32 = 1; dk4c32_decoder_init(&((tsp->dec).c32), 1); } break; case DK4_EDSTM_ACCEPT: { back = DK4_TSP_RES_OK; } break; } } break; } if (0 != cuc32) { switch (tsp->pen) { case DK4_ENCODING_ASCII: { $? ". ASCII required" if (dkC32(0x00000100) > c32) { c08 = (char)c32; back = dk4tsp08_process_group(tsp, &c08, 1); } else { $? "! ASCII encoding failed for %lu",(unsigned long)c32 /* Encoding error */ dk4error_set_with_position( &(tsp->er_en), DK4_E_ENCODING_FAILED, (tsp->pos).bytes, (tsp->pos).lineno, (tsp->pos).chars, (tsp->pos).charil ); } } break; case DK4_ENCODING_ANSI: { $? ". ANSI required" if (0 != dk4ansi_encode(&uc, c32)) { c08 = (char)uc; back = dk4tsp08_process_group(tsp, &c08, 1); } else { $? "! ANSI encoding failed for %lu", (unsigned long)c32 /* Encoding error */ dk4error_set_with_position( &(tsp->er_en), DK4_E_ENCODING_FAILED, (tsp->pos).bytes, (tsp->pos).lineno, (tsp->pos).chars, (tsp->pos).charil ); } } break; case DK4_ENCODING_UTF8: { $? ". UTF-8 required" sz = sizeof(buf); if (0 != dk4utf8_encode(buf, &sz, c32, NULL)) { back = dk4tsp08_process_group(tsp, (char *)buf, sz); } else { $? "! UTF-8 encoding failed for %lu", (unsigned long)c32 /* Encoding error */ dk4error_set_with_position( &(tsp->er_en), DK4_E_ENCODING_FAILED, (tsp->pos).bytes, (tsp->pos).lineno, (tsp->pos).chars, (tsp->pos).charil ); } } break; } } } if (DK4_TSP_RES_FATAL == back) { tsp->pst = 2; } $? "- dk4tsp08_process_byte %d", back return back; } /** Add one byte to internal data structures (BOM detection and/or normal processing). @param tsp Text stream processor. @param inbyte Byte to add. @return Operation result, one from DK4_TSP_RES_OK, DK4_TSP_RES_ERROR or DK4_TSP_RES_FATAL. */ static int dk4tsp08_i_add_one_byte( dk4_tsp08_t *tsp, unsigned char inbyte ) { size_t nrej = 0; size_t i = 0; int back = DK4_TSP_RES_FATAL; int res; unsigned char uc; $? "+ dk4tsp08_i_add_one_byte %02x", (int)inbyte (tsp->pos).bytes += (dk4_um_t)1UL; switch (tsp->pst) { case 0: { /* BOM detection */ $? ". in BOM detection" res = dk4bom_detect_add(&(tsp->bomd), inbyte); switch (res) { case DK4_EDSTM_ACCEPT: { back = DK4_TSP_RES_OK; } break; case DK4_EDSTM_FINISHED: case DK4_EDSTM_FINISHED_WITH_UNUSED: { $? ". end of BOM detection" /* This result is ok. */ back = DK4_TSP_RES_OK; /* Retrieve found encoding */ tsp->ief = dk4bom_detect_get_encoding(&(tsp->bomd)); /* Check whether we can pass through data unchanged */ if (tsp->ief == tsp->pen) { switch (tsp->ief) { #if VERSION_BEFORE_20150321 /* 2015-30-21 We do not hard-code the decision whether or not to enable pass-through for UTF-8 encoded bytes, better use a run-time decision. */ case DK4_ENCODING_ASCII: case DK4_ENCODING_ANSI: #if 0 /* 2014-12-01 We must make sure to process the complete UTF-8 representation of a glyph completely. */ case DK4_ENCODING_UTF8: #endif { tsp->pth = 1; $? ". pass through" } break; #endif case DK4_ENCODING_ASCII : case DK4_ENCODING_ANSI : { tsp->pth = 1; } break; case DK4_ENCODING_UTF8 : { if (0 != tsp->upt) { tsp->pth = 1; } } break; } } /* If necessary, initialize decoder */ dk4tsp08_initialize_decoder(tsp); /* Switch to normal processing */ tsp->pst = 1; /* Process bytes stored in BOM detector */ if (DK4_EDSTM_FINISHED_WITH_UNUSED == res) { nrej = dk4bom_detect_num_unused_bytes(&(tsp->bomd)); if (0 < nrej) { $? ". processing bytes rejected by BOM detector" for (i = 0; ((i < nrej) && (DK4_TSP_RES_FATAL != back)); i++) { uc = dk4bom_detect_unused_byte(&(tsp->bomd), i); $? ". process byte %u/%u = %02x", (unsigned)i,(unsigned)nrej,(int)uc switch (dk4tsp08_process_byte(tsp, uc)) { case DK4_TSP_RES_FATAL: { $? "! fatal" back = DK4_TSP_RES_FATAL; } break; case DK4_TSP_RES_ERROR: { if (DK4_TSP_RES_OK == back) { $? "! error" back = DK4_TSP_RES_ERROR; } } break; } } } } } break; case DK4_EDSTM_ERROR: { $? "! error in BOM detection" } break; } } break; case 1: { /* Normal processing */ $? ". in normal processing" back = dk4tsp08_process_byte(tsp, inbyte); } break; /* Processing stage 2 indicates there was a serious error before, we must skip further processing. This situation is covered by the initialization value DK4_TSP_RES_FATAL, so we do not need a case branch here. */ } $? "- dk4tsp08_i_add_one_byte %d", back return back; } int dk4tsp08_setup_char( dk4_tsp08_t *tsp, void *obj, dk4_c8_handler_t *fct, int pre, int eie, dk4_er_t *erp ) { int back = 0; $? "+ dk4tsp08_setup_char" if (NULL != tsp) { $? ". tsp ok" dk4tsp08_init(tsp, eie); if (NULL != fct) { $? ". args ok" switch (pre) { case DK4_ENCODING_ASCII: case DK4_ENCODING_ANSI: case DK4_ENCODING_UTF8: { tsp->obj = obj; (tsp->fct).ch = fct; tsp->pen = pre; tsp->iee = eie; $? ". expected encoding = %d", eie tsp->ief = eie; back = 1; } break; default: { $? "! invalid char encoding" dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); tsp->pst = 2; } break; } } else { $? "! invalid arguments" dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); tsp->pst = 2; } } else { $? "! invalid arguments" dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); } $? "- dk4tsp08_setup_char %d", back return back; } int dk4tsp08_setup_line( dk4_tsp08_t *tsp, void *obj, dk4_c8_line_handler_t *fct, char *inbuf, size_t szin, int pre, int eie, dk4_er_t *erp ) { int back = 0; $? "+ dk4tsp08_setup_line" if (NULL != tsp) { $? ". tsp ok" dk4tsp08_init(tsp, eie); if ((NULL != fct) && (NULL != inbuf) && (0 < szin)) { $? ". args ok" switch (pre) { case DK4_ENCODING_ASCII: case DK4_ENCODING_ANSI: case DK4_ENCODING_UTF8: { tsp->obj = obj; (tsp->fct).lh = fct; tsp->inbuf = inbuf; tsp->in_sz = szin; tsp->in_us = 0; tsp->pen = pre; tsp->iee = eie; tsp->ief = eie; back = 1; } break; default: { $? "! invalid char encoding" dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); tsp->pst = 2; } break; } } else { $? "! invalid arguments" dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); tsp->pst = 2; } } else { $? "! invalid arguments" dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); } $? "- dk4tsp08_setup_line %d", back return back; } int dk4tsp08_add_one_byte( dk4_tsp08_t *tsp, unsigned char inbyte ) { int back = DK4_TSP_RES_FATAL; $? "+ dk4tsp08_add_one_byte" if (NULL != tsp) { if (2 > tsp->pst) { back = dk4tsp08_i_add_one_byte(tsp, inbyte); } } $? "- dk4tsp08_add_one_byte %d", back return back; } int dk4tsp08_add_bytes( dk4_tsp08_t *tsp, const unsigned char *buffer, size_t sz ) { int back = DK4_TSP_RES_FATAL; int res; $? "+ dk4tsp08_add_bytes" if ((NULL != tsp) && (NULL != buffer) && (0 < sz)) { if (2 > tsp->pst) { back = DK4_TSP_RES_OK; while((sz--) && (2 > tsp->pst)) { res = dk4tsp08_i_add_one_byte(tsp, *(buffer++)); switch (res) { case DK4_TSP_RES_FATAL: { $? "! fatal" back = DK4_TSP_RES_FATAL; } break; case DK4_TSP_RES_ERROR: { if (DK4_TSP_RES_OK == back) { $? "! error" back = DK4_TSP_RES_ERROR; } } break; } } } } $? "- dk4tsp08_add_bytes %d", back return back; } int dk4tsp08_finish(dk4_tsp08_t *tsp) { size_t nrej = 0; size_t i = 0; int back = DK4_TSP_RES_FATAL; int res; unsigned char uc; $? "+ dk4tsp08_finish" if (NULL != tsp) { /* Retrieve rejected bytes from BOM detector */ back = DK4_TSP_RES_OK; if (0 == tsp->pst) { $? ". still in BOM detection" tsp->pst = 1; nrej = dk4bom_detect_num_unused_bytes(&(tsp->bomd)); if (0 < nrej) { dk4tsp08_initialize_decoder(tsp); for (i = 0; ((i < nrej) && (2 > tsp->pst)); i++) { uc = dk4bom_detect_unused_byte(&(tsp->bomd), i); $? ". process byte %u/%u = %02x", (unsigned)i,(unsigned)nrej,(int)uc switch (dk4tsp08_process_byte(tsp, uc)) { case DK4_TSP_RES_FATAL: { $? "! fatal" back = DK4_TSP_RES_FATAL; tsp->pst = 2; } break; case DK4_TSP_RES_ERROR: { $? "! error" if (DK4_TSP_RES_OK == back) { back = DK4_TSP_RES_ERROR; } } break; } } } } else { $? ". BOM detection was finished" } /* Process final line */ if ((NULL != tsp->inbuf) && (0 < tsp->in_sz) && (NULL != (tsp->fct).lh)) { if (0 < tsp->in_us) { $? ". processing final line" if (2 > tsp->pst) { if (tsp->in_us < tsp->in_sz) { $? ". can add final 0x00" (tsp->inbuf)[tsp->in_us] = '\0'; $? ". run processing function" res = (*((tsp->fct).lh))( tsp->obj,tsp->inbuf,(tsp->pos).lineno,&(tsp->er_pr) ); switch (res) { case DK4_TSP_RES_FATAL: { $? "! fatal" back = DK4_TSP_RES_FATAL; tsp->pst = 2; } break; case DK4_TSP_RES_ERROR: { $? "! error" if (DK4_TSP_RES_OK == back) { back = DK4_TSP_RES_ERROR; } } break; } } else { $? "! line too long to add final 0x00" back = DK4_TSP_RES_FATAL; tsp->pst = 2; /* ERROR: Line too long! */ dk4error_set_with_position( &(tsp->er_en), DK4_E_BUFFER_TOO_SMALL, (tsp->pos).bytes, (tsp->pos).lineno, (tsp->pos).chars, (tsp->pos).charil ); } } else { $? "! previous errors" } } } } $? "- dk4tsp08_finish %d", back return back; } void dk4tsp08_get_errors(dk4_er_t *er_en, dk4_er_t *er_pr, dk4_tsp08_t *tsp) { if (NULL != tsp) { if (NULL != er_en) { DK4_MEMCPY(er_en, &(tsp->er_en), sizeof(dk4_er_t)); } if (NULL != er_pr) { DK4_MEMCPY(er_pr, &(tsp->er_pr), sizeof(dk4_er_t)); } } } void dk4tsp08_enable_utf8_pass_through(dk4_tsp08_t *tsp, int fl) { if (NULL != tsp) { tsp->upt = ((0 != fl) ? 1 : 0); } }