1
0
mirror of https://git.code.sf.net/p/zint/code synced 2025-12-18 10:27:09 +00:00

RAW_TEXT: change source to be unconverted, i.e. UTF-8 (unless

`DATA_MODE`); allows ZXing-C++ to be built in writer-only mode
  without needing "libzueci"
library: in GS1 mode check that ECI if any is ASCII compatible
general: some code fiddling, `mode` -> `modes`
This commit is contained in:
gitlost
2025-09-05 17:23:18 +01:00
parent 44e2099a65
commit 9b4d097516
39 changed files with 798 additions and 630 deletions

View File

@@ -84,7 +84,7 @@ static void set_symbol_defaults(struct zint_symbol *symbol) {
struct zint_symbol *ZBarcode_Create(void) {
struct zint_symbol *symbol;
symbol = (struct zint_symbol *) calloc(1, sizeof(*symbol));
symbol = (struct zint_symbol *) calloc(1, sizeof(*symbol)); /* Zeroizes */
if (!symbol) return NULL;
set_symbol_defaults(symbol);
@@ -100,6 +100,7 @@ void ZBarcode_Clear(struct zint_symbol *symbol) {
if (!symbol) return;
/* Zeroize output fields */
for (i = 0; i < symbol->rows; i++) {
memset(symbol->encoded_data[i], 0, sizeof(symbol->encoded_data[0]));
}
@@ -285,142 +286,6 @@ INTERNAL int zint_test_error_tag(int error_number, struct zint_symbol *symbol, c
}
#endif
/* Output a hexadecimal representation of the rendered symbol (TXT files - includes frontend "--dump" option) */
static int txt_hex_plot(struct zint_symbol *symbol) {
static const char hex[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
struct filemem fm;
struct filemem *const fmp = &fm;
int r;
if (!zint_fm_open(fmp, symbol, "w")) {
return ZEXT z_errtxtf(ZINT_ERROR_FILE_ACCESS, symbol, 201, "Could not open TXT output file (%1$d: %2$s)",
fmp->err, strerror(fmp->err));
}
for (r = 0; r < symbol->rows; r++) {
int space = 0, byt = 0;
int i;
for (i = 0; i < symbol->width; i++) {
byt <<= 1;
if (symbol->symbology == BARCODE_ULTRA) {
if (z_module_colour_is_set(symbol, r, i)) {
byt++;
}
} else {
if (z_module_is_set(symbol, r, i)) {
byt++;
}
}
if (((i + 1) & 0x3) == 0) {
zint_fm_putc(hex[byt], fmp);
space++;
byt = 0;
}
if (space == 2 && i + 1 < symbol->width) {
zint_fm_putc(' ', fmp);
space = 0;
}
}
if (symbol->width & 0x03) {
byt <<= 4 - (symbol->width & 0x03);
zint_fm_putc(hex[byt], fmp);
}
zint_fm_putc('\n', fmp);
}
if (zint_fm_error(fmp)) {
ZEXT z_errtxtf(0, symbol, 795, "Incomplete write of TXT output (%1$d: %2$s)", fmp->err, strerror(fmp->err));
(void) zint_fm_close(fmp, symbol);
return ZINT_ERROR_FILE_WRITE;
}
if (!zint_fm_close(fmp, symbol)) {
return ZEXT z_errtxtf(ZINT_ERROR_FILE_WRITE, symbol, 792, "Failure on closing TXT output file (%1$d: %2$s)",
fmp->err, strerror(fmp->err));
}
return 0;
}
/* Permitted HIBC characters */
static const char TECHNETIUM[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%"; /* Same as SILVER (CODE39) */
/* Process health industry bar code data */
static int hibc(struct zint_symbol *symbol, struct zint_seg segs[], const int seg_count) {
unsigned char *source = segs[0].source;
int length = segs[0].length;
int i;
int counter, error_number = 0;
char to_process[110 + 2 + 1];
int posns[110];
/* without "+" and check: max 110 characters in HIBC 2.6 */
if (length > 110) {
return z_errtxtf(ZINT_ERROR_TOO_LONG, symbol, 202, "Input length %d too long for HIBC LIC (maximum 110)",
length);
}
z_to_upper(source, length);
if ((i = z_not_sane_lookup(TECHNETIUM, sizeof(TECHNETIUM) - 1, source, length, posns))) {
return z_errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 203,
"Invalid character at position %d in input (alphanumerics, space and \"-.$/+%%\" only)", i);
}
counter = 41;
for (i = 0; i < length; i++) {
counter += posns[i];
}
counter = counter % 43;
to_process[0] = '+';
memcpy(to_process + 1, source, length);
to_process[++length] = TECHNETIUM[counter];
to_process[++length] = '\0';
segs[0].source = (unsigned char *) to_process;
segs[0].length = length;
if (symbol->debug & ZINT_DEBUG_PRINT) printf("HIBC processed source: %s\n", to_process);
/* HIBC uses same `raw_text` as base symbologies */
switch (symbol->symbology) {
case BARCODE_HIBC_128:
error_number = zint_code128(symbol, segs[0].source, segs[0].length);
z_hrt_cpy_chr(symbol, '*');
z_hrt_cat_nochk(symbol, segs[0].source, segs[0].length);
z_hrt_cat_chr_nochk(symbol, '*');
break;
case BARCODE_HIBC_39:
symbol->option_2 = 0;
error_number = zint_code39(symbol, segs[0].source, segs[0].length);
z_hrt_cpy_chr(symbol, '*');
z_hrt_cat_nochk(symbol, segs[0].source, segs[0].length);
z_hrt_cat_chr_nochk(symbol, '*');
break;
case BARCODE_HIBC_DM:
error_number = zint_datamatrix(symbol, segs, seg_count);
break;
case BARCODE_HIBC_QR:
error_number = zint_qrcode(symbol, segs, seg_count);
break;
case BARCODE_HIBC_PDF:
error_number = zint_pdf417(symbol, segs, seg_count);
break;
case BARCODE_HIBC_MICPDF:
error_number = zint_micropdf417(symbol, segs, seg_count);
break;
case BARCODE_HIBC_AZTEC:
error_number = zint_aztec(symbol, segs, seg_count);
break;
case BARCODE_HIBC_BLOCKF:
error_number = zint_codablockf(symbol, segs[0].source, segs[0].length);
break;
}
return error_number;
}
/* Returns 1 if symbology MUST have GS1 data */
static int check_force_gs1(const int symbology) {
@@ -484,6 +349,23 @@ static int supports_eci(const int symbology) {
return 0;
}
/* Returns 1 if symbology can encode other than ISO/IEC 8869-1 (Latin-1) */
static int supports_non_iso8859_1(const int symbology) {
if (supports_eci(symbology)) {
return 1;
}
switch (symbology) {
case BARCODE_MICROQR:
case BARCODE_UPNQR:
return 1;
break;
}
return 0;
}
/* Returns 1 if symbology supports HRT */
static int has_hrt(const int symbology) {
@@ -533,6 +415,94 @@ static int has_hrt(const int symbology) {
return 1;
}
/* Process health industry bar code data */
static int hibc(struct zint_symbol *symbol, struct zint_seg segs[], const int seg_count) {
/* Permitted HIBC characters */
static const char TECHNETIUM[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%"; /* Same as SILVER (CODE39) */
unsigned char *source = segs[0].source;
int length = segs[0].length;
int i;
int counter, error_number = 0;
char to_process[110 + 2 + 1];
int posns[110];
const int raw_text = symbol->output_options & BARCODE_RAW_TEXT;
/* Without "+" and check: max 110 characters in HIBC 2.6 */
if (length > 110) {
return z_errtxtf(ZINT_ERROR_TOO_LONG, symbol, 202, "Input length %d too long for HIBC LIC (maximum 110)",
length);
}
z_to_upper(source, length);
if ((i = z_not_sane_lookup(TECHNETIUM, sizeof(TECHNETIUM) - 1, source, length, posns))) {
return z_errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 203,
"Invalid character at position %d in input (alphanumerics, space and \"-.$/+%%\" only)", i);
}
counter = 41;
for (i = 0; i < length; i++) {
counter += posns[i];
}
counter = counter % 43;
to_process[0] = '+';
memcpy(to_process + 1, source, length);
to_process[++length] = TECHNETIUM[counter];
to_process[++length] = '\0';
segs[0].source = (unsigned char *) to_process;
segs[0].length = length;
assert(seg_count == 1);
if (symbol->debug & ZINT_DEBUG_PRINT) printf("HIBC processed source: %s\n", to_process);
/* Code 128, Code 39 & Codablock-F set `raw_text` themselves, but the others don't, so do it now */
assert(!symbol->raw_segs); /* HIBC symbologies don't satisfy `supports_non_iso8859_1()` */
if (raw_text && symbol->symbology != BARCODE_HIBC_128 && symbol->symbology != BARCODE_HIBC_39
&& symbol->symbology != BARCODE_HIBC_BLOCKF) {
if (z_rt_cpy_segs(symbol, segs, seg_count)) {
return error_tag(ZINT_ERROR_MEMORY, symbol, -1, NULL); /* `z_rt_cpy_segs()` only fails with OOM */
}
}
switch (symbol->symbology) {
case BARCODE_HIBC_128:
error_number = zint_code128(symbol, segs[0].source, segs[0].length);
z_hrt_cpy_chr(symbol, '*');
z_hrt_cat_nochk(symbol, segs[0].source, segs[0].length);
z_hrt_cat_chr_nochk(symbol, '*');
break;
case BARCODE_HIBC_39:
symbol->option_2 = 0;
error_number = zint_code39(symbol, segs[0].source, segs[0].length);
z_hrt_cpy_chr(symbol, '*');
z_hrt_cat_nochk(symbol, segs[0].source, segs[0].length);
z_hrt_cat_chr_nochk(symbol, '*');
break;
case BARCODE_HIBC_DM:
error_number = zint_datamatrix(symbol, segs, seg_count);
break;
case BARCODE_HIBC_QR:
error_number = zint_qrcode(symbol, segs, seg_count);
break;
case BARCODE_HIBC_PDF:
error_number = zint_pdf417(symbol, segs, seg_count);
break;
case BARCODE_HIBC_MICPDF:
error_number = zint_micropdf417(symbol, segs, seg_count);
break;
case BARCODE_HIBC_AZTEC:
error_number = zint_aztec(symbol, segs, seg_count);
break;
case BARCODE_HIBC_BLOCKF:
error_number = zint_codablockf(symbol, segs[0].source, segs[0].length);
break;
}
return error_number;
}
typedef int (*barcode_src_func_t)(struct zint_symbol *, unsigned char[], int);
typedef int (*barcode_seg_func_t)(struct zint_symbol *, struct zint_seg[], const int);
@@ -988,7 +958,7 @@ int ZBarcode_Encode_Segs(struct zint_symbol *symbol, const struct zint_seg segs[
int error_number, warn_number = 0;
int total_len = 0;
int have_zero_eci = 0;
int escape_mode;
int escape_mode, raw_text;
int i;
unsigned char *local_source;
struct zint_seg *local_segs;
@@ -1022,6 +992,7 @@ int ZBarcode_Encode_Segs(struct zint_symbol *symbol, const struct zint_seg segs[
escape_mode = (symbol->input_mode & ESCAPE_MODE)
|| ((symbol->input_mode & EXTRA_ESCAPE_MODE) && symbol->symbology == BARCODE_CODE128);
raw_text = symbol->output_options & BARCODE_RAW_TEXT;
local_segs = (struct zint_seg *) z_alloca(sizeof(struct zint_seg) * (seg_count > 0 ? seg_count : 1));
@@ -1164,6 +1135,10 @@ int ZBarcode_Encode_Segs(struct zint_symbol *symbol, const struct zint_seg segs[
if (symbol->rows < 0) { /* Silently defend against out-of-bounds access */
symbol->rows = 0;
}
if (raw_text && symbol->rows) { /* Would only give info on last stacked */
return error_tag(ZINT_ERROR_INVALID_OPTION, symbol, 857,
"Cannot use BARCODE_RAW_TEXT output option if stacking symbols");
}
if ((symbol->input_mode & 0x07) == GS1_MODE && !gs1_compliant(symbol->symbology)) {
return error_tag(ZINT_ERROR_INVALID_OPTION, symbol, 220, "Selected symbology does not support GS1 mode");
@@ -1218,8 +1193,18 @@ int ZBarcode_Encode_Segs(struct zint_symbol *symbol, const struct zint_seg segs[
/* Reduce input for composite and non-forced symbologies, others (GS1_128 and DBAR_EXP based) will
handle it themselves */
const int have_composite = z_is_composite(symbol->symbology);
/* Deal with any ECI first */
if (symbol->eci) {
/* Check that ECI is at least CSET82 (an ASCII Invariant subset) compatible */
if (symbol->eci == 25 || (symbol->eci >= 33 && symbol->eci <= 35)) { /* UTF-16/32 BE/LE */
return error_tag(ZINT_ERROR_INVALID_OPTION, symbol, 856, "In GS1 mode ECI must be ASCII compatible");
}
/* Note not warning here that ECI is not supported in GS1 mode, leaving it up to individual
symbologies, as standards are inconsistent in mentioning it */
}
if (have_composite || !check_force_gs1(symbol->symbology)) {
const int raw_text = symbol->output_options & BARCODE_RAW_TEXT;
unsigned char *reduced = (unsigned char *) z_alloca(local_segs[0].length + 1);
int source_len = local_segs[0].length;
error_number = zint_gs1_verify(symbol, local_segs[0].source, &source_len, reduced,
@@ -1243,6 +1228,11 @@ int ZBarcode_Encode_Segs(struct zint_symbol *symbol, const struct zint_seg segs[
} else {
return error_tag(ZINT_ERROR_INVALID_OPTION, symbol, 210, "Selected symbology does not support GS1 mode");
}
} else if (raw_text && supports_non_iso8859_1(symbol->symbology)) {
/* Copy these as-is. The raw seg `eci` will need to be updated individually */
if (z_rt_cpy_segs(symbol, local_segs, seg_count)) {
return error_tag(ZINT_ERROR_MEMORY, symbol, -1, NULL); /* `z_rt_cpy_segs()` only fails with OOM */
}
}
error_number = extended_or_reduced_charset(symbol, local_segs, seg_count);
@@ -1272,7 +1262,10 @@ int ZBarcode_Encode_Segs(struct zint_symbol *symbol, const struct zint_seg segs[
if (symbol->height < 0.5f) { /* Absolute minimum */
(void) z_set_height(symbol, 0.0f, 50.0f, 0.0f, 1 /*no_errtxt*/);
}
assert(!(symbol->output_options & BARCODE_RAW_TEXT) || (symbol->raw_segs && symbol->raw_seg_count));
assert(!(symbol->output_options & BARCODE_RAW_TEXT)
|| (symbol->raw_segs && symbol->raw_seg_count && symbol->raw_segs[0].source
&& ((symbol->input_mode & 0x07) == DATA_MODE
|| z_is_valid_utf8(symbol->raw_segs[0].source, symbol->raw_segs[0].length))));
}
return error_number;
@@ -1327,6 +1320,64 @@ static int filetype_idx(const char *extension) {
return i == ARRAY_SIZE(filetypes) ? -1 : i;
}
/* Output a hexadecimal representation of the rendered symbol (TXT files - includes frontend "--dump" option) */
static int txt_hex_plot(struct zint_symbol *symbol) {
static const char hex[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
struct filemem fm;
struct filemem *const fmp = &fm;
int r;
if (!zint_fm_open(fmp, symbol, "w")) {
return ZEXT z_errtxtf(ZINT_ERROR_FILE_ACCESS, symbol, 201, "Could not open TXT output file (%1$d: %2$s)",
fmp->err, strerror(fmp->err));
}
for (r = 0; r < symbol->rows; r++) {
int space = 0, byt = 0;
int i;
for (i = 0; i < symbol->width; i++) {
byt <<= 1;
if (symbol->symbology == BARCODE_ULTRA) {
if (z_module_colour_is_set(symbol, r, i)) {
byt++;
}
} else {
if (z_module_is_set(symbol, r, i)) {
byt++;
}
}
if (((i + 1) & 0x3) == 0) {
zint_fm_putc(hex[byt], fmp);
space++;
byt = 0;
}
if (space == 2 && i + 1 < symbol->width) {
zint_fm_putc(' ', fmp);
space = 0;
}
}
if (symbol->width & 0x03) {
byt <<= 4 - (symbol->width & 0x03);
zint_fm_putc(hex[byt], fmp);
}
zint_fm_putc('\n', fmp);
}
if (zint_fm_error(fmp)) {
ZEXT z_errtxtf(0, symbol, 795, "Incomplete write of TXT output (%1$d: %2$s)", fmp->err, strerror(fmp->err));
(void) zint_fm_close(fmp, symbol);
return ZINT_ERROR_FILE_WRITE;
}
if (!zint_fm_close(fmp, symbol)) {
return ZEXT z_errtxtf(ZINT_ERROR_FILE_WRITE, symbol, 792, "Failure on closing TXT output file (%1$d: %2$s)",
fmp->err, strerror(fmp->err));
}
return 0;
}
/* Output a previously encoded symbol to file `symbol->outfile` */
int ZBarcode_Print(struct zint_symbol *symbol, int rotate_angle) {
int error_number;