Skip to content

Commit b59f684

Browse files
tbeunmoinvaz
authored andcommitted
#998 Add MZ_ICU option for string encoding conversion
Add ICU as an alternative backend to libiconv using ucnv_convert. ICU is detected via CMake's FindICU module on non-Windows platforms. Add CI build configuration for ICU in GitHub Actions.
1 parent cde8b2f commit b59f684

4 files changed

Lines changed: 83 additions & 0 deletions

File tree

.github/workflows/build.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,15 @@ jobs:
176176
packages: clang-14 llvm-14
177177
gcov-exec: llvm-cov-14 gcov
178178

179+
- name: Ubuntu Clang ICU
180+
os: ubuntu-latest
181+
compiler: clang-14
182+
cxx-compiler: clang++-14
183+
cmake-args: -D MZ_CODE_COVERAGE=ON -D MZ_ICU=ON -D MZ_ICONV=OFF
184+
codecov: ubuntu_clang_icu
185+
packages: clang-14 llvm-14 libicu-dev
186+
gcov-exec: llvm-cov-14 gcov
187+
179188
# No code coverage supported
180189
- name: Windows MSVC
181190
os: windows-latest

CMakeLists.txt

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ option(MZ_OPENSSL "Enables OpenSSL for encryption" ${UNIX})
6060
cmake_dependent_option(MZ_LIBBSD "Builds with libbsd crypto random" ON "UNIX" OFF)
6161
# Character conversion options
6262
option(MZ_ICONV "Enables iconv for string encoding conversion" ON)
63+
option(MZ_ICU "Enables ICU for string encoding conversion" OFF)
6364
# Code generation options
6465
option(MZ_COMPRESS_ONLY "Only support compression" OFF)
6566
option(MZ_DECOMPRESS_ONLY "Only support decompression" OFF)
@@ -586,6 +587,12 @@ else()
586587
list(APPEND MINIZIP_DEF -DMZ_ZIP_NO_CRYPTO)
587588
endif()
588589

590+
# Iconv and ICU are mutually exclusive; ICU takes precedence
591+
if (MZ_ICU AND MZ_ICONV)
592+
message(STATUS "ICU enabled, disabling Iconv")
593+
set(MZ_ICONV OFF)
594+
endif()
595+
589596
# Iconv is only necessary when it is not already built-in
590597
# FindIconv requires cmake 3.11 or higher
591598
if (MZ_ICONV)
@@ -606,6 +613,24 @@ else()
606613

607614
set(MZ_ICONV OFF)
608615
endif()
616+
617+
if (MZ_ICU)
618+
find_package(ICU COMPONENTS uc QUIET)
619+
endif()
620+
621+
if(ICU_FOUND)
622+
message(STATUS "Using ICU ${ICU_VERSION}")
623+
624+
list(APPEND MINIZIP_DEF -DHAVE_ICU)
625+
list(APPEND MINIZIP_DEP_PKG ICU)
626+
list(APPEND MINIZIP_LIB ICU::uc)
627+
set(PC_PRIVATE_LIBS "${PC_PRIVATE_LIBS} -licuuc")
628+
else()
629+
if(MZ_ICU)
630+
message(STATUS "ICU library not found")
631+
set(MZ_ICU OFF)
632+
endif()
633+
endif()
609634
endif()
610635

611636
# Setup predefined macros
@@ -1056,6 +1081,7 @@ add_feature_info(MZ_OPENSSL MZ_OPENSSL "Enables OpenSSL for encryption")
10561081
add_feature_info(MZ_LIBBSD MZ_LIBBSD "Builds with libbsd crypto random")
10571082
# Character conversion options
10581083
add_feature_info(MZ_ICONV MZ_ICONV "Enables iconv string encoding conversion library")
1084+
add_feature_info(MZ_ICU MZ_ICU "Enables ICU string encoding conversion library")
10591085
# Code generation options
10601086
add_feature_info(MZ_COMPRESS_ONLY MZ_COMPRESS_ONLY "Only support compression")
10611087
add_feature_info(MZ_DECOMPRESS_ONLY MZ_DECOMPRESS_ONLY "Only support decompression")

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ cmake --build build
8282
| MZ_OPENSSL | Enables OpenSSL encryption | UNIX |
8383
| MZ_LIBBSD | Builds with libbsd crypto random | UNIX |
8484
| MZ_ICONV | Enables iconv encoding conversion | ON |
85+
| MZ_ICU | Enables ICU encoding conversion | OFF |
8586
| MZ_COMPRESS_ONLY | Only support compression | OFF |
8687
| MZ_DECOMPRESS_ONLY | Only support decompression | OFF |
8788
| MZ_FILE32_API | Builds using posix 32-bit file api | OFF |

mz_os_posix.c

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818
#if defined(HAVE_ICONV)
1919
# include <iconv.h>
2020
#endif
21+
#if defined(HAVE_ICU)
22+
# include <unicode/ucnv.h>
23+
#endif
2124
#include <string.h>
2225
#include <sys/types.h>
2326
#include <sys/stat.h>
@@ -88,6 +91,50 @@ char *mz_os_utf8_string_create(const char *string, int32_t encoding) {
8891

8992
return string_utf8;
9093
}
94+
#elif defined(HAVE_ICU)
95+
char *mz_os_utf8_string_create(const char *string, int32_t encoding) {
96+
char string_encoding[16];
97+
const char *from_encoding = NULL;
98+
int32_t string_length = 0;
99+
int32_t string_utf8_size = 0;
100+
char *string_utf8 = NULL;
101+
int32_t result = 0;
102+
UErrorCode status = U_ZERO_ERROR;
103+
104+
if (!string || encoding <= 0)
105+
return NULL;
106+
107+
if (encoding == MZ_ENCODING_UTF8)
108+
from_encoding = "UTF-8";
109+
else if (encoding == MZ_ENCODING_CODEPAGE_437)
110+
from_encoding = "ibm-437";
111+
else if (encoding == MZ_ENCODING_CODEPAGE_932)
112+
from_encoding = "windows-932-2000";
113+
else if (encoding == MZ_ENCODING_CODEPAGE_936)
114+
from_encoding = "windows-936-2000";
115+
else if (encoding == MZ_ENCODING_CODEPAGE_950)
116+
from_encoding = "windows-950-2000";
117+
else {
118+
snprintf(string_encoding, sizeof(string_encoding), "windows-%" PRId32 "-2000", encoding);
119+
from_encoding = string_encoding;
120+
}
121+
122+
string_length = (int32_t)strlen(string);
123+
string_utf8_size = string_length * 4 + 1;
124+
string_utf8 = (char *)calloc(string_utf8_size, sizeof(char));
125+
126+
if (!string_utf8)
127+
return NULL;
128+
129+
result = ucnv_convert("UTF-8", from_encoding, string_utf8, string_utf8_size, string, string_length, &status);
130+
131+
if (U_FAILURE(status) || result < 0) {
132+
free(string_utf8);
133+
string_utf8 = NULL;
134+
}
135+
136+
return string_utf8;
137+
}
91138
#else
92139
char *mz_os_utf8_string_create(const char *string, int32_t encoding) {
93140
return strdup(string);

0 commit comments

Comments
 (0)