1
0
mirror of https://git.code.sf.net/p/zint/code synced 2026-06-09 23:23:36 +00:00

Add convenience API funcs ZBarcode_UTF8_To_ECI() and

`ZBarcode_Dest_Len_ECI()`, primarily for ZXingC++ but also useful
  in general
This commit is contained in:
gitlost
2025-03-02 20:50:55 +00:00
parent 99f94b1027
commit d0465375bb
12 changed files with 647 additions and 167 deletions
+39 -3
View File
@@ -1,7 +1,7 @@
/* eci.c - Extended Channel Interpretations */
/*
libzint - the open source barcode library
Copyright (C) 2009-2024 Robin Stuart <rstuart114@gmail.com>
Copyright (C) 2009-2025 Robin Stuart <rstuart114@gmail.com>
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
@@ -43,6 +43,30 @@
/* Single-byte stuff */
/* ECI 2 (bottom half ASCII, top half CP437), included for libzueci compatibility - assumes valid Unicode */
static int u_cp437(const unsigned int u, unsigned char *dest) {
int s, e;
if (u < 0x80) {
*dest = (unsigned char) u;
return 1;
}
s = 0;
e = ARRAY_SIZE(cp437_u) - 1;
while (s <= e) {
const int m = (s + e) >> 1;
if (cp437_u[m] < u) {
s = m + 1;
} else if (cp437_u[m] > u) {
e = m - 1;
} else {
*dest = cp437_sb[m];
return 1;
}
}
return 0;
}
/* Base ISO/IEC 8859 routine to convert Unicode codepoint `u` */
static int u_iso8859(const unsigned int u, const unsigned short *tab_s, const unsigned short *tab_u,
const unsigned char *tab_sb, int e, unsigned char *dest) {
@@ -181,6 +205,15 @@ static int u_utf32le(const unsigned int u, unsigned char *dest) {
return 4;
}
/* ECI 899 Binary, included for libzueci compatibility - assumes valid Unicode */
static int u_binary(const unsigned int u, unsigned char *dest) {
if (u <= 0xFF) {
*dest = (unsigned char) u;
return 1;
}
return 0;
}
/* Multibyte stuff */
/* Acknowledgements to Bruno Haible <bruno@clisp.org> for a no. of techniques used here */
@@ -701,7 +734,7 @@ typedef int (*eci_func_t)(const unsigned int u, unsigned char *dest);
INTERNAL int utf8_to_eci(const int eci, const unsigned char source[], unsigned char dest[], int *p_length) {
static const eci_func_t eci_funcs[36] = {
NULL, NULL, NULL, NULL, u_iso8859_2, /*0-4*/
NULL, NULL, u_cp437, NULL, u_iso8859_2, /*0-4*/
u_iso8859_3, u_iso8859_4, u_iso8859_5, u_iso8859_6, u_iso8859_7, /*5-9*/
u_iso8859_8, u_iso8859_9, u_iso8859_10, u_iso8859_11, NULL, /*10-14*/
u_iso8859_13, u_iso8859_14, u_iso8859_15, u_iso8859_16, NULL, /*15-19*/
@@ -717,7 +750,8 @@ INTERNAL int utf8_to_eci(const int eci, const unsigned char source[], unsigned c
int length = *p_length;
/* Special case ISO/IEC 8859-1 */
if (eci == 0 || eci == 3) { /* Default ECI 0 to ISO/IEC 8859-1 */
/* Default ECI 0 to ISO/IEC 8859-1 (and ECI 1 for libzueci compatibility) */
if (eci == 0 || eci == 3 || eci == 1) {
while (in_posn < length) {
do {
decode_utf8(&state, &codepoint, source[in_posn++]);
@@ -737,6 +771,8 @@ INTERNAL int utf8_to_eci(const int eci, const unsigned char source[], unsigned c
if (eci == 170) { /* ASCII Invariant (archaic subset) */
eci_func = u_ascii_inv;
} else if (eci == 899) { /* Binary, for libzueci compatibility */
eci_func = u_binary;
} else {
eci_func = eci_funcs[eci];
if (eci_func == NULL) {
+43 -4
View File
@@ -1,9 +1,10 @@
/* eci_sb.h - Extended Channel Interpretations single-byte, generated by "backend/tools/gen_eci_sb_h.php"
from "https://unicode.org/Public/MAPPINGS/ISO8859/8859-*.TXT"
and "https://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP125*.TXT" */
/* eci_sb.h - Extended Channel Interpretations single-byte, generated by "backend/tools/gen_eci_sb_h.php" from
"https://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/PC/CP437.TXT" (for libzueci compatibility) and
"https://unicode.org/Public/MAPPINGS/ISO8859/8859-*.TXT" and
"https://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP125*.TXT" */
/*
libzint - the open source barcode library
Copyright (C) 2021-2022 Robin Stuart <rstuart114@gmail.com>
Copyright (C) 2021-2025 Robin Stuart <rstuart114@gmail.com>
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
@@ -35,6 +36,44 @@
#ifndef Z_ECI_SB_H
#define Z_ECI_SB_H
/* Tables for ECI 2 CP437 (for libzueci compatibility) */
static const unsigned short cp437_u[128] = { /* Unicode codepoints sorted */
0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A5, 0x00AA, 0x00AB, 0x00AC,
0x00B0, 0x00B1, 0x00B2, 0x00B5, 0x00B7, 0x00BA, 0x00BB, 0x00BC,
0x00BD, 0x00BF, 0x00C4, 0x00C5, 0x00C6, 0x00C7, 0x00C9, 0x00D1,
0x00D6, 0x00DC, 0x00DF, 0x00E0, 0x00E1, 0x00E2, 0x00E4, 0x00E5,
0x00E6, 0x00E7, 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED,
0x00EE, 0x00EF, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F6, 0x00F7,
0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FF, 0x0192, 0x0393, 0x0398,
0x03A3, 0x03A6, 0x03A9, 0x03B1, 0x03B4, 0x03B5, 0x03C0, 0x03C3,
0x03C4, 0x03C6, 0x207F, 0x20A7, 0x2219, 0x221A, 0x221E, 0x2229,
0x2248, 0x2261, 0x2264, 0x2265, 0x2310, 0x2320, 0x2321, 0x2500,
0x2502, 0x250C, 0x2510, 0x2514, 0x2518, 0x251C, 0x2524, 0x252C,
0x2534, 0x253C, 0x2550, 0x2551, 0x2552, 0x2553, 0x2554, 0x2555,
0x2556, 0x2557, 0x2558, 0x2559, 0x255A, 0x255B, 0x255C, 0x255D,
0x255E, 0x255F, 0x2560, 0x2561, 0x2562, 0x2563, 0x2564, 0x2565,
0x2566, 0x2567, 0x2568, 0x2569, 0x256A, 0x256B, 0x256C, 0x2580,
0x2584, 0x2588, 0x258C, 0x2590, 0x2591, 0x2592, 0x2593, 0x25A0,
};
static const unsigned char cp437_sb[128] = { /* Single-byte in Unicode order */
0xFF, 0xAD, 0x9B, 0x9C, 0x9D, 0xA6, 0xAE, 0xAA,
0xF8, 0xF1, 0xFD, 0xE6, 0xFA, 0xA7, 0xAF, 0xAC,
0xAB, 0xA8, 0x8E, 0x8F, 0x92, 0x80, 0x90, 0xA5,
0x99, 0x9A, 0xE1, 0x85, 0xA0, 0x83, 0x84, 0x86,
0x91, 0x87, 0x8A, 0x82, 0x88, 0x89, 0x8D, 0xA1,
0x8C, 0x8B, 0xA4, 0x95, 0xA2, 0x93, 0x94, 0xF6,
0x97, 0xA3, 0x96, 0x81, 0x98, 0x9F, 0xE2, 0xE9,
0xE4, 0xE8, 0xEA, 0xE0, 0xEB, 0xEE, 0xE3, 0xE5,
0xE7, 0xED, 0xFC, 0x9E, 0xF9, 0xFB, 0xEC, 0xEF,
0xF7, 0xF0, 0xF3, 0xF2, 0xA9, 0xF4, 0xF5, 0xC4,
0xB3, 0xDA, 0xBF, 0xC0, 0xD9, 0xC3, 0xB4, 0xC2,
0xC1, 0xC5, 0xCD, 0xBA, 0xD5, 0xD6, 0xC9, 0xB8,
0xB7, 0xBB, 0xD4, 0xD3, 0xC8, 0xBE, 0xBD, 0xBC,
0xC6, 0xC7, 0xCC, 0xB5, 0xB6, 0xB9, 0xD1, 0xD2,
0xCB, 0xCF, 0xD0, 0xCA, 0xD8, 0xD7, 0xCE, 0xDF,
0xDC, 0xDB, 0xDD, 0xDE, 0xB0, 0xB1, 0xB2, 0xFE,
};
/* Forward reference to base ISO/IEC 8859 routine - see "eci.c" */
static int u_iso8859(const unsigned int u, const unsigned short *tab_s, const unsigned short *tab_u,
const unsigned char *tab_sb, int e, unsigned char *dest);
+62 -1
View File
@@ -979,7 +979,7 @@ static int map_invalid_symbology(struct zint_symbol *symbol) {
return warn_number;
}
/* Encode a barcode. If `length` is 0, `source` must be NUL-terminated */
/* Encode a barcode. If `length` is 0 or negative, `source` must be NUL-terminated */
int ZBarcode_Encode(struct zint_symbol *symbol, const unsigned char *source, int length) {
struct zint_seg segs[1];
@@ -2070,6 +2070,67 @@ float ZBarcode_XdimDp_From_Scale(int symbol_id, float scale, float xdim_mm_or_dp
return xdim_mm_or_dpmm;
}
/* Whether `eci` is valid character set ECI */
static int is_valid_char_set_eci(const int eci) {
/* Allowing ECI 1 and ECI 2 for libzueci compatibility (and ECI 0, which is mapped to ECI 2) */
return (eci <= 35 && eci >= 0 && eci != 14 && eci != 19) || eci == 170 || eci == 899;
}
/* Convert UTF-8 `source` of length `length` to `eci`-encoded `dest`, setting `p_dest_length` to length of `dest`
on output. If `length` is 0 or negative, `source` must be NUL-terminated. Returns 0 on success, else
ZINT_ERROR_INVALID_OPTION or ZINT_ERROR_INVALID_DATA. Compatible with libzueci `zueci_utf8_to_eci()` */
int ZBarcode_UTF8_To_ECI(int eci, const unsigned char *source, int length, unsigned char dest[], int *p_dest_length) {
int error_number;
/* Map ECI 0 to ECI 2 (CP437) for libzueci compatibility */
if (eci == 0) {
eci = 2;
}
if (!is_valid_char_set_eci(eci) || !source || !p_dest_length) {
return ZINT_ERROR_INVALID_OPTION;
}
if (length <= 0) {
length = (int) ustrlen(source); /* Note `zueci_utf8_to_eci()` doesn't do this */
}
if (!is_valid_utf8(source, length)) {
return ZINT_ERROR_INVALID_DATA;
}
if (eci == 26) { /* UTF-8 - no change */
memcpy(dest, source, length);
*p_dest_length = length;
return 0;
}
/* Only set `p_dest_length` on success, for libzueci compatibility */
if ((error_number = utf8_to_eci(eci, source, dest, &length)) == 0) {
*p_dest_length = length;
}
return error_number; /* 0 or ZINT_ERROR_INVALID_DATA */
}
/* Calculate sufficient length needed to convert UTF-8 `source` of length `length` from UTF-8 to `eci`, and place
in `p_dest_length`. If `length` is 0 or negative, `source` must be NUL-terminated. Returns 0 on success, else
ZINT_ERROR_INVALID_OPTION or ZINT_ERROR_INVALID_DATA. Compatible with libzueci `zueci_dest_len_eci()` */
int ZBarcode_Dest_Len_ECI(int eci, const unsigned char *source, int length, int *p_dest_length) {
/* Map ECI 0 to ECI 2 (CP437) for libzueci compatibility */
if (eci == 0) {
eci = 2;
}
if (!is_valid_char_set_eci(eci) || !source || !p_dest_length) {
return ZINT_ERROR_INVALID_OPTION;
}
if (length <= 0) {
length = (int) ustrlen(source); /* Note `zueci_dest_len_eci()` doesn't do this */
}
if (!is_valid_utf8(source, length)) {
return ZINT_ERROR_INVALID_DATA;
}
*p_dest_length = get_eci_length(eci, source, length);
return 0;
}
/* Whether Zint built without PNG support */
int ZBarcode_NoPng(void) {
#ifdef ZINT_NO_PNG
+16 -2
View File
@@ -647,6 +647,19 @@ static const unsigned short int windows_1256[] = {
0x064b, 0x064c, 0x064d, 0x064e, 0x00f4, 0x064f, 0x0650, 0x00f7, 0x0651, 0x00f9, 0x0652, 0x00fb, 0x00fc, 0x200e, 0x200f, 0x06d2
};
/* Taken from https://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/PC/CP437.TXT */
static const unsigned short int cp437[] = {
0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7, 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5,
0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9, 0x00ff, 0x00d6, 0x00dc, 0x00a2, 0x00a3, 0x00a5, 0x20a7, 0x0192,
0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba, 0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510,
0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f, 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567,
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b, 0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580,
0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4, 0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229,
0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248, 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0
};
static void test_utf8_to_eci_sb(const testCtx *const p_ctx) {
struct item {
@@ -674,6 +687,7 @@ static void test_utf8_to_eci_sb(const testCtx *const p_ctx) {
/* 16*/ { 22, windows_1251 },
/* 17*/ { 23, windows_1252 },
/* 18*/ { 24, windows_1256 },
/* 19*/ { 2, cp437 },
};
int data_size = ARRAY_SIZE(data);
int i, length, ret;
@@ -749,8 +763,8 @@ static void test_utf8_to_eci_ascii(const testCtx *const p_ctx) {
/* 16*/ { 170, "~", -1, ZINT_ERROR_INVALID_DATA },
/* 17*/ { 170, "\302\200", -1, ZINT_ERROR_INVALID_DATA },
/* 18*/ { 170, "~", -1, ZINT_ERROR_INVALID_DATA },
/* 19*/ { 1, "A", -1, ZINT_ERROR_INVALID_DATA },
/* 20*/ { 2, "A", -1, ZINT_ERROR_INVALID_DATA },
/* 19*/ { 1, "A", -1, 0 }, /* Now succeeds (maps to ISO/ECI 8859-1 for libzueci compatibility) */
/* 20*/ { 2, "A", -1, 0 }, /* Now succeeds (maps to CP437 for libzueci compatibility) */
/* 21*/ { 14, "A", -1, ZINT_ERROR_INVALID_DATA },
/* 22*/ { 19, "A", -1, ZINT_ERROR_INVALID_DATA },
/* 23*/ { 26, "A", -1, ZINT_ERROR_INVALID_DATA },
+33
View File
@@ -1,3 +1,34 @@
/*
libzint - the open source barcode library
Copyright (C) 2021-2025 Robin Stuart <rstuart114@gmail.com>
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the project nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
*/
/* SPDX-License-Identifier: BSD-3-Clause */
/* Generated by gen_test_tab.php from KSX1001.TXT */
static const unsigned int test_ksx1001_tab[] = {
0x222E, 0x00A1,
@@ -8292,3 +8323,5 @@ static const unsigned int test_ksx1001_tab_ind[] = {
15712,
16248,
};
/* vim: set ts=4 sw=4 et : */
+111
View File
@@ -2177,6 +2177,116 @@ static void test_xdimdp_from_scale(const testCtx *const p_ctx) {
testFinish();
}
static void test_utf8_to_eci(const testCtx *const p_ctx) {
struct item {
int eci;
const char *data;
int length;
int ret_dest;
int expected_dest_length;
int ret;
const char *expected;
int expected_length;
};
/* s/\/\*[ 0-9]*\*\//\=printf("\/\*%3d*\/", line(".") - line("'<")): */
static const struct item data[] = {
/* 0*/ { 3, "1234", -1, 0, 4, 0, "1234", -1 },
/* 1*/ { 3, "1234", 0, 0, 4, 0, "1234", -1 }, /* Zero length allowed */
/* 2*/ { 3, "1234", -2, 0, 4, 0, "1234", -1 }, /* Negative length allowed */
/* 3*/ { 3, "", -1, 0, 0, 0, "", 0 }, /* Empty allowed */
/* 4*/ { 3, NULL, -1, ZINT_ERROR_INVALID_OPTION, 0, -1, "", -1 },
/* 5*/ { -1, "1234", -1, ZINT_ERROR_INVALID_OPTION, 0, -1, "", -1 },
/* 6*/ { 0, "1234", -1, 0, 4, 0, "1234", -1 },
/* 7*/ { 1, "1234", -1, 0, 4, 0, "1234", -1 },
/* 8*/ { 2, "1234", -1, 0, 4, 0, "1234", -1 },
/* 9*/ { 0, "1234é", -1, 0, 6, 0, "1234\202", 5 }, /* CP437 */
/* 10*/ { 1, "1234é", -1, 0, 6, 0, "1234\351", 5 }, /* Same as ISO/IEC 8859-1 */
/* 11*/ { 2, "1234é", -1, 0, 6, 0, "1234\202", 5 }, /* CP437 */
/* 12*/ { 3, "1234é", -1, 0, 6, 0, "1234\351", 5 },
/* 13*/ { 4, "1234˘", -1, 0, 6, 0, "1234\242", 5 }, /* ISO/IEC 8859-2 */
/* 14*/ { 5, "1234Ħ", -1, 0, 6, 0, "1234\241", 5 }, /* ISO/IEC 8859-3 */
/* 15*/ { 6, "1234ĸ", -1, 0, 6, 0, "1234\242", 5 }, /* ISO/IEC 8859-4 */
/* 16*/ { 7, "1234Ё", -1, 0, 6, 0, "1234\241", 5 }, /* ISO/IEC 8859-5 */
/* 17*/ { 8, "1234ء", -1, 0, 6, 0, "1234\301", 5 }, /* ISO/IEC 8859-6 */
/* 18*/ { 9, "1234π", -1, 0, 6, 0, "1234\360", 5 }, /* ISO/IEC 8859-7 */
/* 19*/ { 11, "1234ğ", -1, 0, 6, 0, "1234\360", 5 }, /* ISO/IEC 8859-9 */
/* 20*/ { 12, "1234Ŋ", -1, 0, 6, 0, "1234\257", 5 }, /* ISO/IEC 8859-10 */
/* 21*/ { 13, "1234", -1, 0, 7, 0, "1234\360", 5 }, /* ISO/IEC 8859-11 */
/* 22*/ { 14, "1234", -1, ZINT_ERROR_INVALID_OPTION, 0, -1, "", -1 },
/* 23*/ { 15, "1234š", -1, 0, 6, 0, "1234\360", 5 }, /* ISO/IEC 8859-13 */
/* 24*/ { 16, "1234ŵ", -1, 0, 6, 0, "1234\360", 5 }, /* ISO/IEC 8859-14 */
/* 25*/ { 17, "1234œ", -1, 0, 6, 0, "1234\275", 5 }, /* ISO/IEC 8859-15 */
/* 26*/ { 18, "1234Ł", -1, 0, 6, 0, "1234\243", 5 }, /* ISO/IEC 8859-16 */
/* 27*/ { 19, "1234", -1, ZINT_ERROR_INVALID_OPTION, 0, -1, "", -1 },
/* 28*/ { 20, "1234点", -1, 0, 7, 0, "1234\223\137", 6 }, /* Shift JIS */
/* 29*/ { 20, "1234¥", -1, 0, 6, 0, "1234\\", 5 }, /* Shift JIS - Yen sign -> backslash */
/* 30*/ { 20, "1234~", -1, 0, 5, ZINT_ERROR_INVALID_DATA, "", -1 }, /* Shift JIS - no mapping for tilde */
/* 31*/ { 20, "1234\\", -1, 0, 6, 0, "1234\201\137", -1 }, /* Shift JIS - backslash -> full-width reverse solidus */
/* 32*/ { 21, "1234Ą", -1, 0, 6, 0, "1234\245", 5 }, /* Windows-1250 */
/* 33*/ { 22, "1234ѓ", -1, 0, 6, 0, "1234\203", 5 }, /* Windows-1251 */
/* 34*/ { 23, "1234ƒ", -1, 0, 6, 0, "1234\203", 5 }, /* Windows-1252 */
/* 35*/ { 24, "1234پ", -1, 0, 6, 0, "1234\201", 5 }, /* Windows-1256 */
/* 36*/ { 25, "1234é", -1, 0, 10, 0, "\0001\0002\0003\0004\000\351", 10 }, /* UTF-16BE */
/* 37*/ { 26, "1234é", -1, 0, 6, 0, "1234é", 6 }, /* UTF-8 */
/* 38*/ { 27, "1234é", -1, 0, 6, ZINT_ERROR_INVALID_DATA, "", -1 }, /* ASCII */
/* 39*/ { 27, "1234", -1, 0, 4, 0, "1234", -1 }, /* ASCII */
/* 40*/ { 28, "1234_", -1, 0, 7, 0, "1234\241\304", 6 }, /* Big5 */
/* 41*/ { 29, "1234崂", -1, 0, 7, 0, "1234\341\300", 6 }, /* GB 2312 */
/* 42*/ { 30, "1234가", -1, 0, 7, 0, "1234\260\241", 6 }, /* EUC-KR */
/* 43*/ { 31, "1234郎", -1, 0, 7, 0, "1234\375\234", 6 }, /* GBK */
/* 44*/ { 32, "1234崂", -1, 0, 14, 0, "1234\341\300", 6 }, /* GB 18030 */
/* 45*/ { 33, "1234é", -1, 0, 10, 0, "1\0002\0003\0004\000\351\000", 10 }, /* UTF-16LE */
/* 46*/ { 34, "1234é", -1, 0, 20, 0, "\000\000\0001\000\000\0002\000\000\0003\000\000\0004\000\000\000\351", 20 }, /* UTF-16BE */
/* 47*/ { 35, "1234é", -1, 0, 20, 0, "1\000\000\0002\000\000\0003\000\000\0004\000\000\000\351\000\000\000", 20 }, /* UTF-16LE */
/* 48*/ { 170, "1234", -1, 0, 4, 0, "1234", 4 }, /* ISO 646 Invariant */
/* 49*/ { 170, "1234#", -1, 0, 5, ZINT_ERROR_INVALID_DATA, "", -1 }, /* ISO 646 Invariant */
/* 50*/ { 899, "1234\000\127\302\200ÿ", 10, 0, 10, 0, "1234\000\127\200\377", 8 }, /* Binary */
};
const int data_size = ARRAY_SIZE(data);
int i, length, ret;
int expected_length;
testStart("test_utf8_to_eci");
for (i = 0; i < data_size; i++) {
int ret_dest;
unsigned char dest[1024];
int dest_length;
if (testContinue(p_ctx, i)) continue;
length = data[i].length == -1 && data[i].data ? (int) strlen(data[i].data) : data[i].length;
ret_dest = ZBarcode_Dest_Len_ECI(data[i].eci, TCU(data[i].data), length, &dest_length);
assert_equal(ret_dest, data[i].ret_dest, "i:%d ZBarcode_Dest_Len_ECI(%d, %s) ret_dest %d != %d\n",
i, data[i].eci, data[i].data, ret_dest, data[i].ret_dest);
if (ret_dest < ZINT_ERROR) {
assert_equal(dest_length, data[i].expected_dest_length,
"i:%d ZBarcode_Dest_Len_ECI dest_length %d != expected_dest_length %d\n",
i, dest_length, data[i].expected_dest_length);
expected_length = data[i].expected_length == -1 ? (int) strlen(data[i].expected) : data[i].expected_length;
ret = ZBarcode_UTF8_To_ECI(data[i].eci, TCU(data[i].data), length, dest, &dest_length);
assert_equal(ret, data[i].ret, "i:%d ZBarcode_UTF8_To_ECI(%d, %s) ret %d != %d\n",
i, data[i].eci, data[i].data, ret, data[i].ret);
if (ret < ZINT_ERROR) {
assert_equal(dest_length, expected_length,
"i:%d ZBarcode_UTF8_To_ECI dest_length %d != expected_length %d\n",
i, dest_length, expected_length);
#if 0
printf("dest_length %d\n", dest_length); debug_print_escape(TCU(dest), dest_length, NULL); printf("\n");
#endif
assert_zero(memcmp(dest, data[i].expected, expected_length), "i:%d memcmp(\"%s\", \"%s\", %d) != 0\n",
i, dest, data[i].expected, expected_length);
}
}
}
testFinish();
}
int main(int argc, char *argv[]) {
testFunction funcs[] = { /* name, func */
@@ -2205,6 +2315,7 @@ int main(int argc, char *argv[]) {
{ "test_reset", test_reset },
{ "test_scale_from_xdimdp", test_scale_from_xdimdp },
{ "test_xdimdp_from_scale", test_xdimdp_from_scale },
{ "test_utf8_to_eci", test_utf8_to_eci },
};
testRun(argc, argv, funcs, ARRAY_SIZE(funcs));
+95 -5
View File
@@ -2,7 +2,7 @@
/* Generate ECI single-byte tables & routines from unicode.org mapping files */
/*
libzint - the open source barcode library
Copyright (C) 2022-2023 Robin Stuart <rstuart114@gmail.com>
Copyright (C) 2022-2025 Robin Stuart <rstuart114@gmail.com>
*/
/* SPDX-License-Identifier: BSD-3-Clause */
/*
@@ -20,12 +20,13 @@ $out_dirname = isset($opts['o']) ? $opts['o'] : ($dirname . '/..'); // Where to
$out = array();
$head = <<<'EOD'
/* eci_sb.h - Extended Channel Interpretations single-byte, generated by "backend/tools/gen_eci_sb_h.php"
from "https://unicode.org/Public/MAPPINGS/ISO8859/8859-*.TXT"
and "https://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP125*.TXT" */
/* eci_sb.h - Extended Channel Interpretations single-byte, generated by "backend/tools/gen_eci_sb_h.php" from
"https://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/PC/CP437.TXT" (for libzueci compatibility) and
"https://unicode.org/Public/MAPPINGS/ISO8859/8859-*.TXT" and
"https://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP125*.TXT" */
/*
libzint - the open source barcode library
Copyright (C) 2021-2022 Robin Stuart <rstuart114@gmail.com>
Copyright (C) 2021-2025 Robin Stuart <rstuart114@gmail.com>
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
@@ -60,6 +61,95 @@ EOD;
$out = explode("\n", $head);
// Read the CP437 file
$tot_cp437 = 0;
//$file = $data_dirname . '/' . 'CP437.TXT';
$file = 'https://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/PC/CP437.TXT';
if (($get = file_get_contents($file)) === false) {
error_log($error = "$basename: ERROR: Could not read mapping file \"$file\"");
exit($error . PHP_EOL);
}
$lines = explode("\n", $get);
// Parse the file.
$sort = array();
$sb = array();
foreach ($lines as $line) {
$line = trim($line);
if ($line === '' || strncmp($line, '0x', 2) !== 0 || strpos($line, "*** NO MAPPING ***") !== false) {
continue;
}
$matches = array();
if (preg_match('/^0x([0-9a-f]{2})[ \t]+0x([0-9a-f]{4})[ \t].*$/', $line, $matches)) {
$mb = hexdec($matches[1]);
$unicode = hexdec($matches[2]);
if ($unicode >= 0x80) {
$sort[] = $unicode;
$sb[] = $mb;
}
}
}
array_multisort($sort, $sb);
// Output.
$out[] = '';
$out[] = '/* Tables for ECI 2 CP437 (for libzueci compatibility) */';
$cnt = count($sort);
$out[] = 'static const unsigned short cp437_u[' . $cnt . '] = { /* Unicode codepoints sorted */';
$line = ' ';
for ($i = 0; $i < $cnt; $i++) {
if ($i && $i % 8 === 0) {
$out[] = $line;
$line = ' ';
}
$line .= sprintf(' 0x%04X,', $sort[$i]);
}
if ($line !== ' ') {
$out[] = $line;
}
$out[] = '};';
$tot_cp437 += $cnt * 2;
$cnt = count($sb);
$out[] = 'static const unsigned char cp437_sb[' . $cnt . '] = { /* Single-byte in Unicode order */';
$line = ' ';
for ($i = 0; $i < $cnt; $i++) {
if ($i && $i % 8 === 0) {
$out[] = $line;
$line = ' ';
}
$line .= sprintf(' 0x%02X,', $sb[$i]);
}
if ($line !== ' ') {
$out[] = $line;
}
$out[] = '};';
$tot_cp437 += $cnt;
$u_sb = array_flip($sb);
$b = 0x80;
$cnt = 256 - $b;
$max_idx = -1;
for ($i = 0; $i < $cnt; $i++) {
if (isset($u_sb[$i + $b])) {
$max_idx = $i;
}
}
$cnt = $max_idx + 1;
$tot_cp437 += $cnt;
if (0) {
$out[] = '';
$out[] = '/* Total CP437 bytes: ' . $tot_cp437 . ' */';
}
$u_iso8859 = <<<'EOD'
/* Forward reference to base ISO/IEC 8859 routine - see "eci.c" */
+14 -2
View File
@@ -141,7 +141,7 @@ extern "C" {
/* Segment for use with `ZBarcode_Encode_Segs()` below */
struct zint_seg {
unsigned char *source; /* Data to encode */
int length; /* Length of `source`. If 0, `source` must be NUL-terminated */
int length; /* Length of `source`. If 0 or negative, `source` must be NUL-terminated */
int eci; /* Extended Channel Interpretation */
};
@@ -405,7 +405,7 @@ extern "C" {
ZINT_EXTERN void ZBarcode_Delete(struct zint_symbol *symbol);
/* Encode a barcode. If `length` is 0, `source` must be NUL-terminated */
/* Encode a barcode. If `length` is 0 or negative, `source` must be NUL-terminated */
ZINT_EXTERN int ZBarcode_Encode(struct zint_symbol *symbol, const unsigned char *source, int length);
/* Encode a barcode with multiple ECI segments */
@@ -488,6 +488,18 @@ extern "C" {
const char *filetype);
/* Convert UTF-8 `source` of length `length` to `eci`-encoded `dest`, setting `p_dest_length` to length of `dest`
on output. If `length` is 0 or negative, `source` must be NUL-terminated. Returns 0 on success, else
ZINT_ERROR_INVALID_OPTION or ZINT_ERROR_INVALID_DATA. Compatible with libzueci `zueci_utf8_to_eci()` */
ZINT_EXTERN int ZBarcode_UTF8_To_ECI(int eci, const unsigned char *source, int length, unsigned char dest[],
int *p_dest_length);
/* Calculate sufficient length needed to convert UTF-8 `source` of length `length` from UTF-8 to `eci`, and place
in `p_dest_length`. If `length` is 0 or negative, `source` must be NUL-terminated. Returns 0 on success, else
ZINT_ERROR_INVALID_OPTION or ZINT_ERROR_INVALID_DATA. Compatible with libzueci `zueci_dest_len_eci()` */
ZINT_EXTERN int ZBarcode_Dest_Len_ECI(int eci, const unsigned char *source, int length, int *p_dest_length);
/* Whether Zint built without PNG support */
ZINT_EXTERN int ZBarcode_NoPng(void);