%% 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);
}
}