/* Copyright (C) 2015-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: dk4tsp16.ctr */ /** @file dk4tsp16.c The dk4tsp16 module. */ #line 246 "dk4tsp16.ctr" #include "dk4conf.h" #include "dk4tsp16.h" #include "dk4enc.h" #include "dk4mem.h" #include "dk4ansi.h" #include "dk4utf8.h" #include "dk4utf16.h" #include "dk4c32.h" #if DK4_HAVE_ASSERT_H #ifndef ASSERT_H_INCLUDED #include #define ASSERT_H_INCLUDED 1 #endif #endif #line 265 "dk4tsp16.ctr" /** Initialize text stream processing structure. @param tsp Text stream processor. @param eie Expected input encoding. */ static void dk4tsp16_init(dk4_tsp16_t *tsp, int eie) { #if DK4_USE_ASSERT assert(NULL != tsp); #endif DK4_MEMRES(tsp, sizeof(dk4_tsp16_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->pst = 0; (tsp->pos).bytes = (dk4_um_t)0UL; (tsp->pos).chars = (dk4_um_t)1UL; (tsp->pos).lineno = (dk4_um_t)1UL; (tsp->pos).charil = (dk4_um_t)1UL; } /** Initialize decoder for found input encoding. @param tsp Text stream processor. */ static void dk4tsp16_initialize_decoder(dk4_tsp16_t *tsp) { #if DK4_USE_ASSERT assert(NULL != tsp); #endif 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; } } #if 0 static int dk4tsp16_process_character( dk4_tsp16_t *tsp, dk4_c16_t chr ) { int back = DK4_TSP_RES_FATAL; #line 339 "dk4tsp16.ctr" /* Increase position */ (tsp->pos).chars += (dk4_um_t)1UL; (tsp->pos).charil += (dk4_um_t)1UL; /* Check for line buffering or direct processing */ if ((NULL != tsp->inbuf) && (0 < tsp->in_sz) && (NULL != (tsp->fct).lh)) { #line 345 "dk4tsp16.ctr" if (tsp->in_us < tsp->in_sz) { (tsp->inbuf)[tsp->in_us] = chr; tsp->in_us += 1; back = DK4_TSP_RES_OK; if ((dk4_c16_t)'\n' == chr) { back = DK4_TSP_RES_FATAL; if (tsp->in_us < tsp->in_sz) { (tsp->inbuf)[tsp->in_us] = (dk4_c16_t)'\0'; back = (*((tsp->fct).lh))( tsp->obj,tsp->inbuf,(tsp->pos).lineno,&(tsp->er_pr) ); } else { 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 { 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 { #line 374 "dk4tsp16.ctr" if (NULL != (tsp->fct).ch) { back = (*((tsp->fct).ch))(tsp->obj, chr, &(tsp->pos), &(tsp->er_pr)); } } /* Increase line number for newline characters */ if ((dk4_c16_t)('\n') == chr) { (tsp->pos).lineno += (dk4_um_t)1UL; (tsp->pos).charil = (dk4_um_t)1UL; } #line 383 "dk4tsp16.ctr" return back; } #endif /** Process a group of 16 bit characters, the group represents one 32 bit character. @param tsp Text stream processor. @param buf Buffer of 16 bit characters. @param sz Number of 16 bit characters. @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 dk4tsp16_process_group(dk4_tsp16_t *tsp, dk4_c16_t *buf, size_t sz) { size_t i = 0; int back = DK4_TSP_RES_FATAL; int res = DK4_TSP_RES_FATAL; #line 409 "dk4tsp16.ctr" #if DK4_USE_ASSERT assert(NULL != tsp); assert(NULL != buf); assert(0 < sz); #endif /* Increase position */ (tsp->pos).chars += (dk4_um_t)1UL; (tsp->pos).charil += (dk4_um_t)1UL; /* Check for line buffering or direct processing */ if ((NULL != tsp->inbuf) && (0 < tsp->in_sz) && (NULL != (tsp->fct).lh)) { #line 420 "dk4tsp16.ctr" if (sz < tsp->in_sz) { if (tsp->in_us < (tsp->in_sz - sz)) { /* Append group to line and increase used size */ DK4_MEMCPY(&((tsp->inbuf)[tsp->in_us]),buf,(sizeof(dk4_c16_t)*sz)); tsp->in_us += sz; back = DK4_TSP_RES_OK; /* On newline, process the line buffer */ if ((1 == sz) && ((dk4_c16_t)'\n' == buf[0])) { back = DK4_TSP_RES_FATAL; if (tsp->in_us < tsp->in_sz) { (tsp->inbuf)[tsp->in_us] = (dk4_c16_t)'\0'; back = (*((tsp->fct).lh))( tsp->obj,tsp->inbuf,(tsp->pos).lineno,&(tsp->er_pr) ); } else { /* ERROR: Buffer too small */ 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: Buffer too small */ back = DK4_TSP_RES_FATAL; 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: Buffer too small */ back = DK4_TSP_RES_FATAL; 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 { #line 464 "dk4tsp16.ctr" 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 ); } } /* If we have a newline, increase line number and reset char in line */ if (1 == sz) { if ((dk4_c16_t)('\n') == buf[0]) { (tsp->pos).lineno += (dk4_um_t)1UL; (tsp->pos).charil = (dk4_um_t)1UL; } } #line 493 "dk4tsp16.ctr" return back; } /** Normal processing for one byte. Retrieve a 32 bit character first, either by decoding directly or by adding to a decoder. In the next step encode the 32 bit character in one or two 16 bit characters and process these. @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 dk4tsp16_process_byte(dk4_tsp16_t *tsp, unsigned char inbyte) { dk4_c16_t buf[8]; dk4_c32_t c32 = dkC32(0); size_t sz; int back = DK4_TSP_RES_FATAL; int cuc32 = 0; int res = 0; /* Add byte to decoder, attempt to retrieve a 32 bit character */ #if DK4_USE_ASSERT assert(NULL != tsp); #endif switch (tsp->ief) { case DK4_FILE_ENCODING_PLAIN: { c32 = (dk4_c32_t)inbyte; cuc32 = 1; } break; case DK4_FILE_ENCODING_WIN1252: { if (0 != dk4ansi_decode(&c32, inbyte)) { cuc32 = 1; } else { 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: { res = dk4utf8_add(&((tsp->dec).u08), inbyte); switch (res) { case DK4_EDSTM_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: { res = dk4utf16_byte_add(&((tsp->dec).u16), inbyte); switch (res) { case DK4_EDSTM_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: { res = dk4utf16_byte_add(&((tsp->dec).u16), inbyte); switch (res) { case DK4_EDSTM_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: { res = dk4c32_decoder_add(&((tsp->dec).c32), inbyte); switch (res) { case DK4_EDSTM_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: { res = dk4c32_decoder_add(&((tsp->dec).c32), inbyte); switch (res) { case DK4_EDSTM_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; } /* Process 32 bit character if we have a 32 bit char to process */ if (0 != cuc32) { sz = DK4_SIZEOF(buf,dk4_c16_t); if (0 != dk4utf16_encode(buf, &sz, c32, NULL)) { #if 0 back = DK4_TSP_RES_OK; for (i = 0; ((i < sz) && (DK4_TSP_RES_FATAL != back)); i++) { switch (dk4tsp16_process_character(tsp, buf[i])) { 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 back = dk4tsp16_process_group(tsp, buf, sz); #endif } else { dk4error_set_with_position( &(tsp->er_en), DK4_E_ENCODING_FAILED, (tsp->pos).bytes, (tsp->pos).lineno, (tsp->pos).chars, (tsp->pos).charil ); } } if (DK4_TSP_RES_FATAL == back) { tsp->pst = 2; } 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 dk4tsp16_i_add_one_byte( dk4_tsp16_t *tsp, unsigned char inbyte ) { size_t nrej; size_t i; int back = DK4_TSP_RES_FATAL; int res; unsigned char uc; #line 693 "dk4tsp16.ctr" #if DK4_USE_ASSERT assert(NULL != tsp); #endif (tsp->pos).bytes += (dk4_um_t)1UL; switch (tsp->pst) { case 0: { #line 699 "dk4tsp16.ctr" 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: { /* Result is acceptable */ back = DK4_TSP_RES_OK; /* Retrieve found encoding */ tsp->ief = dk4bom_detect_get_encoding(&(tsp->bomd)); /* If necessary, initialize decoder */ dk4tsp16_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) { for (i = 0; ((i < nrej) && (DK4_TSP_RES_FATAL != back)); i++) { uc = dk4bom_detect_unused_byte(&(tsp->bomd), i); switch (dk4tsp16_process_byte(tsp, uc)) { 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; } } } } } break; } } break; case 1: { #line 736 "dk4tsp16.ctr" back = dk4tsp16_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. */ } #line 746 "dk4tsp16.ctr" return back; } int dk4tsp16_setup_char( dk4_tsp16_t *tsp, void *obj, dk4_c16_handler_t *fct, int eie, dk4_er_t *erp ) { int back = 0; #if DK4_USE_ASSERT assert(NULL != tsp); #endif if (NULL != tsp) { dk4tsp16_init(tsp, eie); if (NULL != fct) { tsp->obj = obj; (tsp->fct).ch = fct; tsp->iee = eie; tsp->ief = eie; tsp->pst = 0; back = 1; } else { dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); tsp->pst = 2; } } else { dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); } return back; } int dk4tsp16_setup_line( dk4_tsp16_t *tsp, void *obj, dk4_c16_line_handler_t *fct, dk4_c16_t *inbuf, size_t szin, int eie, dk4_er_t *erp ) { int back = 0; #if DK4_USE_ASSERT assert(NULL != tsp); assert(NULL != inbuf); assert(0 < szin); #endif if (NULL != tsp) { dk4tsp16_init(tsp, eie); if ((NULL != fct) && (NULL != inbuf) && (0 < szin)) { tsp->obj = obj; (tsp->fct).lh = fct; tsp->inbuf = inbuf; tsp->in_sz = szin; tsp->in_us = 0; tsp->iee = eie; tsp->ief = eie; tsp->pst = 0; back = 1; } else { dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); tsp->pst = 2; } } else { dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); } return back; } int dk4tsp16_add_one_byte( dk4_tsp16_t *tsp, unsigned char inbyte ) { int back = DK4_TSP_RES_FATAL; #if DK4_USE_ASSERT assert(NULL != tsp); #endif if (NULL != tsp) { if (2 > tsp->pst) { back = dk4tsp16_i_add_one_byte(tsp, inbyte); } } return back; } int dk4tsp16_add_bytes( dk4_tsp16_t *tsp, const unsigned char *buffer, size_t sz ) { int back = DK4_TSP_RES_FATAL; /* Function result */ int res; /* Processing result */ #if DK4_USE_ASSERT assert(NULL != tsp); assert(NULL != buffer); assert(0 < sz); #endif if ((NULL != tsp) && (NULL != buffer) && (0 < sz)) { if (2 > tsp->pst) { back = DK4_TSP_RES_OK; while ((sz--) && (2 > tsp->pst)) { res = dk4tsp16_i_add_one_byte(tsp, *(buffer++)); 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; } } } } return back; } int dk4tsp16_finish(dk4_tsp16_t *tsp) { size_t nrej = 0; /* Number of unused bytes */ size_t i = 0; /* Current unused byte index */ int back = DK4_TSP_RES_FATAL; /* Function result */ int res; /* Operation result */ unsigned char uc; /* Current unused byte */ #if DK4_USE_ASSERT assert(NULL != tsp); #endif if (NULL != tsp) { /* Flush all unprocessed output 1. If there are unprocessed bytes in the BOM detector as BOM detection was not completed, process these bytes. 2. If there are characters in the line buffer, finalize the line buffer text and process it. */ back = DK4_TSP_RES_OK; /* Retrieve an process bytes stored in BOM detector */ if (0 == tsp->pst) { tsp->pst = 1; nrej = dk4bom_detect_num_unused_bytes(&(tsp->bomd)); if (0 < nrej) { dk4tsp16_initialize_decoder(tsp); for (i = 0; ((i < nrej) && (2 > tsp->pst)); i++) { uc = dk4bom_detect_unused_byte(&(tsp->bomd), i); switch (dk4tsp16_process_byte(tsp, uc)) { case DK4_TSP_RES_FATAL: { back = DK4_TSP_RES_FATAL; tsp->pst = 2; } break; case DK4_TSP_RES_ERROR: { if (DK4_TSP_RES_OK == back) { back = DK4_TSP_RES_ERROR; } } break; } } } } /* Process final line */ if ((NULL != tsp->inbuf) && (0 < tsp->in_sz) && (NULL != (tsp->fct).lh)) { if (0 < tsp->in_us) { if (2 > tsp->pst) { if (tsp->in_us < tsp->in_sz) { (tsp->inbuf)[tsp->in_us] = (dk4_c16_t)'\0'; res = (*((tsp->fct).lh))( tsp->obj,tsp->inbuf,(tsp->pos).lineno,&(tsp->er_pr) ); switch (res) { case DK4_TSP_RES_FATAL: { back = DK4_TSP_RES_FATAL; tsp->pst = 2; } break; case DK4_TSP_RES_ERROR: { if (DK4_TSP_RES_OK == back) { back = DK4_TSP_RES_ERROR; } } break; } } else { back = DK4_TSP_RES_FATAL; tsp->pst = 2; dk4error_set_with_position( &(tsp->er_en), DK4_E_BUFFER_TOO_SMALL, (tsp->pos).bytes, (tsp->pos).lineno, (tsp->pos).chars, (tsp->pos).charil ); } } } } } return back; } void dk4tsp16_get_errors(dk4_er_t *er_en, dk4_er_t *er_pr, dk4_tsp16_t const *tsp) { #if DK4_USE_ASSERT assert(NULL != tsp); #endif 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)); } } }