diff --git a/app/Makefile b/app/Makefile index 1d065862..2ac98455 100755 --- a/app/Makefile +++ b/app/Makefile @@ -52,7 +52,7 @@ endif APPVERSION_M=0 APPVERSION_N=20 -APPVERSION_P=1 +APPVERSION_P=2 $(info COIN = [$(COIN)]) ifeq ($(COIN),FIL) diff --git a/app/src/apdu_handler.c b/app/src/apdu_handler.c index b5f5a8eb..499fe47b 100644 --- a/app/src/apdu_handler.c +++ b/app/src/apdu_handler.c @@ -52,8 +52,7 @@ void extractHDPath(uint32_t rx, uint32_t offset) { } } -bool process_chunk(volatile uint32_t *tx, uint32_t rx) { - UNUSED(tx); +bool process_chunk(volatile uint32_t *tx, __Z_UNUSED uint32_t rx) { const uint8_t payloadType = G_io_apdu_buffer[OFFSET_PAYLOAD_TYPE]; diff --git a/app/src/common/app_main.c b/app/src/common/app_main.c index e2d031ff..c60a249a 100644 --- a/app/src/common/app_main.c +++ b/app/src/common/app_main.c @@ -34,8 +34,7 @@ static bool tx_initialized = false; unsigned char G_io_seproxyhal_spi_buffer[IO_SEPROXYHAL_BUFFER_SIZE_B]; -unsigned char io_event(unsigned char channel) { - UNUSED(channel); +unsigned char io_event(__Z_UNUSED unsigned char channel) { switch (G_io_seproxyhal_spi_buffer[0]) { case SEPROXYHAL_TAG_FINGER_EVENT: // @@ -96,8 +95,7 @@ unsigned short io_exchange_al(unsigned char channel, unsigned short tx_len) { return 0; } -void handle_generic_apdu(volatile uint32_t *flags, volatile uint32_t *tx, uint32_t rx) { - UNUSED(flags); +void handle_generic_apdu(__Z_UNUSED volatile uint32_t *flags, volatile uint32_t *tx, uint32_t rx) { if (rx > 4 && MEMCMP(G_io_apdu_buffer, "\xE0\x01\x00\x00", 4) == 0) { // Respond to get device info command diff --git a/app/src/parser_impl.c b/app/src/parser_impl.c index f1ea04c5..eca32523 100644 --- a/app/src/parser_impl.c +++ b/app/src/parser_impl.c @@ -493,17 +493,15 @@ parser_error_t _read(const parser_context_t *c, parser_tx_t *v) { return parser_ok; } -parser_error_t _validateTx(const parser_context_t *c, const parser_tx_t *v) { - (void) c; - (void) v; +parser_error_t _validateTx(__Z_UNUSED const parser_context_t *c, __Z_UNUSED const parser_tx_t *v) { // Note: This is place holder for transaction level checks that the project may require before accepting // the parsed values. the parser already validates input // This function is called by parser_validate, where additional checks are made (formatting, UI/UX, etc.( return parser_ok; } -uint8_t _getNumItems(const parser_context_t *c, const parser_tx_t *v) { - UNUSED(c); +uint8_t _getNumItems(__Z_UNUSED const parser_context_t *c, const parser_tx_t *v) { + uint8_t itemCount = 8; return itemCount + v->numparams; diff --git a/deps/ledger-zxlib/.circleci/config.yml b/deps/ledger-zxlib/.circleci/config.yml deleted file mode 100644 index 0c981f72..00000000 --- a/deps/ledger-zxlib/.circleci/config.yml +++ /dev/null @@ -1,19 +0,0 @@ -version: 2 -jobs: - build: - docker: - - image: ubuntu:18.04 - steps: - - run: - name: Install dependencies - command: apt update && apt-get -y install build-essential git sudo wget cmake libssl-dev libgmp-dev autoconf libtool - - checkout - - run: git submodule update --init --recursive - - run: cmake . && make - - run: export GTEST_COLOR=1 && ctest -VV - -workflows: - version: 2 - build_all: - jobs: - - build diff --git a/deps/ledger-zxlib/.github/workflows/main.yml b/deps/ledger-zxlib/.github/workflows/main.yml new file mode 100644 index 00000000..485c5c55 --- /dev/null +++ b/deps/ledger-zxlib/.github/workflows/main.yml @@ -0,0 +1,29 @@ +name: "Test/Build" +on: + workflow_dispatch: + push: + pull_request: + branches: [ main ] + +jobs: + configure: + runs-on: ubuntu-latest + outputs: + uid_gid: ${{ steps.get-user.outputs.uid_gid }} + steps: + - id: get-user + run: echo "::set-output name=uid_gid::$(id -u):$(id -g)" + + build: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + with: + submodules: true + - name: Install deps + run: | + sudo update-alternatives --install /usr/bin/python python /usr/bin/python3 10 + brew install conan + conan config install https://github.com/conan-io/conanclientcert.git + - run: cmake -DCMAKE_BUILD_TYPE=Debug . && make diff --git a/deps/ledger-zxlib/README.md b/deps/ledger-zxlib/README.md index 9dabbf58..d75ac579 100644 --- a/deps/ledger-zxlib/README.md +++ b/deps/ledger-zxlib/README.md @@ -1,5 +1,5 @@ # ledger-zxlib [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) -[![CircleCI](https://circleci.com/gh/Zondax/ledger-zxlib/tree/master.svg?style=shield)](https://circleci.com/gh/Zondax/ledger-zxlib/tree/master) +[![GithubActions](https://github.com/zondax/ledger-zxlib/actions/workflows/main.yml/badge.svg)](https://github.com/Zondax/ledger-zxlib/blob/main/.github/workflows/main.yaml) [![CodeFactor](https://www.codefactor.io/repository/github/zondax/ledger-zxlib/badge)](https://www.codefactor.io/repository/github/zondax/ledger-zxlib) diff --git a/deps/ledger-zxlib/app/common/view.c b/deps/ledger-zxlib/app/common/view.c index 6fda9e4b..0a5fc19f 100644 --- a/deps/ledger-zxlib/app/common/view.c +++ b/deps/ledger-zxlib/app/common/view.c @@ -61,6 +61,11 @@ void h_error_accept(__Z_UNUSED unsigned int _) { app_reply_error(); } +void h_initialize(__Z_UNUSED unsigned int _) { + view_idle_show(0, NULL); + UX_WAIT(); +} + /////////////////////////////////// // Paging related @@ -178,13 +183,22 @@ void h_review_action() { return; } #endif -}; +} zxerr_t h_review_update_data() { if (viewdata.viewfuncGetNumItems == NULL) { zemu_log_stack("h_review_update_data - GetNumItems==NULL"); return zxerr_no_data; } + if (viewdata.viewfuncGetItem == NULL) { + zemu_log_stack("h_review_update_data - GetItem==NULL"); + return zxerr_no_data; + } + + if (viewdata.viewfuncGetItem == NULL) { + zemu_log_stack("h_review_update_data - GetItem==NULL"); + return zxerr_no_data; + } if (viewdata.viewfuncGetItem == NULL) { zemu_log_stack("h_review_update_data - GetItem==NULL"); diff --git a/deps/ledger-zxlib/app/common/view.h b/deps/ledger-zxlib/app/common/view.h index 21a3e421..6c9e7777 100644 --- a/deps/ledger-zxlib/app/common/view.h +++ b/deps/ledger-zxlib/app/common/view.h @@ -44,6 +44,9 @@ zxerr_t secret_enabled(); /// view_init (initializes UI) void view_init(); +/// view_initialize_show (idle view - main menu + status) +void view_initialize_show(uint8_t item_idx, char *statusString); + /// view_idle_show (idle view - main menu + status) void view_idle_show(uint8_t item_idx, char *statusString); diff --git a/deps/ledger-zxlib/app/common/view_internal.h b/deps/ledger-zxlib/app/common/view_internal.h index 3720ba3a..4f08a733 100644 --- a/deps/ledger-zxlib/app/common/view_internal.h +++ b/deps/ledger-zxlib/app/common/view_internal.h @@ -24,13 +24,15 @@ #define CUR_FLOW G_ux.flow_stack[G_ux.stack_count-1] -#if defined(TARGET_NANOX) +#if defined(TARGET_NANOX) || defined(TARGET_NANOS2) #define MAX_CHARS_PER_KEY_LINE 64 #define MAX_CHARS_PER_VALUE1_LINE 4096 #define MAX_CHARS_HEXMESSAGE 160 #else -#define MAX_CHARS_PER_KEY_LINE (17+1) +#ifndef MAX_CHARS_PER_VALUE_LINE #define MAX_CHARS_PER_VALUE_LINE (17) +#endif +#define MAX_CHARS_PER_KEY_LINE (MAX_CHARS_PER_VALUE_LINE+1) #define MAX_CHARS_PER_VALUE1_LINE (2*MAX_CHARS_PER_VALUE_LINE+1) #define MAX_CHARS_PER_VALUE2_LINE (MAX_CHARS_PER_VALUE_LINE+1) #define MAX_CHARS_HEXMESSAGE 40 @@ -100,6 +102,8 @@ max_char_display get_max_char_per_line(); /////////////////////////////////////////////// /////////////////////////////////////////////// +void view_initialize_show_impl(uint8_t item_idx, char *statusString); + void view_idle_show_impl(uint8_t item_idx, char *statusString); void view_message_impl(char *title, char *message); diff --git a/deps/ledger-zxlib/app/common/view_s.c b/deps/ledger-zxlib/app/common/view_s.c index 85e38414..d323b5c7 100644 --- a/deps/ledger-zxlib/app/common/view_s.c +++ b/deps/ledger-zxlib/app/common/view_s.c @@ -23,12 +23,19 @@ #include "bagl.h" #include "zxmacros.h" #include "view_templates.h" +#include "zxutils_ledger.h" #include #include #if defined(TARGET_NANOS) +void h_initialize(); + +#define BAGL_WIDTH 128 +#define BAGL_HEIGHT 32 +#define BAGL_WIDTH_MARGIN 10 + void h_expert_toggle(); void h_expert_update(); void h_review_button_left(); @@ -66,6 +73,17 @@ const ux_menu_entry_t menu_main[] = { UX_MENU_END }; +const ux_menu_entry_t menu_initialize[] = { + {NULL, NULL, 0, &C_icon_app, MENU_MAIN_APP_LINE1, viewdata.key, 33, 12}, + {NULL, h_initialize, 0, &C_icon_app, "Click to", "Initialize", 33, 12}, + {NULL, h_expert_toggle, 0, &C_icon_app, "Expert mode:", viewdata.value, 33, 12}, + {NULL, NULL, 0, &C_icon_app, APPVERSION_LINE1, APPVERSION_LINE2, 33, 12}, + {NULL, NULL, 0, &C_icon_app, "Developed by:", "Zondax.ch", 33, 12}, + {NULL, NULL, 0, &C_icon_app, "License: ", "Apache 2.0", 33, 12}, + {NULL, os_exit, 0, &C_icon_dashboard, "Quit", NULL, 50, 29}, + UX_MENU_END +}; + static const bagl_element_t view_message[] = { UI_BACKGROUND, UI_LabelLine(UIID_LABEL + 0, 0, 8, UI_SCREEN_WIDTH, UI_11PX, UI_WHITE, UI_BLACK, viewdata.key), @@ -200,13 +218,13 @@ void splitValueField() { void splitValueAddress() { uint8_t len = MAX_CHARS_PER_VALUE_LINE; bool exceeding_max = exceed_pixel_in_display(len); - while(exceeding_max) { - len--; + while(exceeding_max && len--) { exceeding_max = exceed_pixel_in_display(len); } print_value2(""); const uint16_t vlen = strlen(viewdata.value); - if (vlen > len) { + //if viewdata.value == NULL --> len = 0 + if (vlen > len && len > 0) { snprintf(viewdata.value2, MAX_CHARS_PER_VALUE2_LINE, "%s", viewdata.value + len); viewdata.value[len] = 0; } @@ -215,18 +233,15 @@ void splitValueAddress() { max_char_display get_max_char_per_line() { uint8_t len = MAX_CHARS_PER_VALUE_LINE; bool exceeding_max = exceed_pixel_in_display(len); - while(exceeding_max) { - len--; + while(exceeding_max && len--) { exceeding_max = exceed_pixel_in_display(len); } //MAX_CHARS_PER_VALUE1_LINE is defined this way - return 2 * len + 1; + return (len > 0) ? (2 * len + 1) : len; } bool exceed_pixel_in_display(const uint8_t length) { - unsigned short strWidth = bagl_compute_line_width((BAGL_FONT_OPEN_SANS_EXTRABOLD_11px - | BAGL_FONT_ALIGNMENT_CENTER |BAGL_FONT_ALIGNMENT_MIDDLE), - 200, viewdata.value, length, BAGL_ENCODING_LATIN1); + const unsigned short strWidth = zx_compute_line_width_light(viewdata.value, length); return (strWidth >= (BAGL_WIDTH - BAGL_WIDTH_MARGIN)); } @@ -236,6 +251,16 @@ bool exceed_pixel_in_display(const uint8_t length) { ////////////////////////// ////////////////////////// +void view_initialize_show_impl(uint8_t item_idx, char *statusString) { + if (statusString == NULL ) { + snprintf(viewdata.key, MAX_CHARS_PER_VALUE_LINE, "%s", MENU_MAIN_APP_LINE2); + } else { + snprintf(viewdata.key, MAX_CHARS_PER_VALUE_LINE, "%s", statusString); + } + h_expert_update(); + UX_MENU_DISPLAY(item_idx, menu_initialize, NULL); +} + void view_idle_show_impl(uint8_t item_idx, char *statusString) { if (statusString == NULL ) { snprintf(viewdata.key, MAX_CHARS_PER_VALUE_LINE, "%s", MENU_MAIN_APP_LINE2); diff --git a/deps/ledger-zxlib/app/common/view_x.c b/deps/ledger-zxlib/app/common/view_x.c index 7db6f935..f8dd8bcb 100644 --- a/deps/ledger-zxlib/app/common/view_x.c +++ b/deps/ledger-zxlib/app/common/view_x.c @@ -33,7 +33,7 @@ #include #include -#if defined(TARGET_NANOX) +#if defined(TARGET_NANOX) || defined(TARGET_NANOS2) void h_expert_toggle(); void h_expert_update(); @@ -76,6 +76,15 @@ const ux_flow_step_t *const ux_idle_flow [] = { /////////// +UX_STEP_NOCB(ux_message_flow_1_step, pbb, { &C_icon_app, viewdata.key, viewdata.value,}); + +UX_FLOW( + ux_message_flow, + &ux_message_flow_1_step +); + +/////////// + UX_STEP_NOCB(ux_error_flow_1_step, bnnn_paging, { .title = viewdata.key, .text = viewdata.value, }); UX_STEP_VALID(ux_error_flow_2_step, pb, h_error_accept(0), { &C_icon_validate_14, "Ok"}); @@ -235,7 +244,7 @@ void h_secret_click() { ////////////////////////// ////////////////////////// -void view_idle_show_impl(uint8_t item_idx, char *statusString) { +void view_idle_show_impl(__Z_UNUSED uint8_t item_idx, char *statusString) { if (statusString == NULL ) { if (app_mode_secret()) { snprintf(viewdata.key, MAX_CHARS_PER_KEY_LINE, "%s", MENU_MAIN_APP_LINE2_SECRET); @@ -263,6 +272,16 @@ void view_review_show_impl(){ ux_flow_init(0, ux_review_flow, NULL); } +void view_message_impl(char *title, char *message) { + snprintf(viewdata.key, MAX_CHARS_PER_KEY_LINE, "%s", title); + snprintf(viewdata.value, MAX_CHARS_PER_VALUE1_LINE, "%s", message); + ux_layout_bnnn_paging_reset(); + if(G_ux.stack_count == 0) { + ux_stack_push(); + } + ux_flow_init(0, ux_message_flow, NULL); +} + void view_error_show_impl() { ux_layout_bnnn_paging_reset(); if(G_ux.stack_count == 0) { diff --git a/deps/ledger-zxlib/cmake/gtest/CMakeLists.txt b/deps/ledger-zxlib/cmake/gtest/CMakeLists.txt index 4f7a8eea..c64d5d8f 100644 --- a/deps/ledger-zxlib/cmake/gtest/CMakeLists.txt +++ b/deps/ledger-zxlib/cmake/gtest/CMakeLists.txt @@ -26,6 +26,6 @@ add_subdirectory( ${CMAKE_BINARY_DIR}/googletest-build ) -if (CMAKE_VERSION VERSION_LESS 2.8.11) +if (CMAKE_VERSION VERSION_LESS 3.0.0) include_directories("${gtest_SOURCE_DIR}/include") endif () diff --git a/deps/ledger-zxlib/cmake/gtest/CMakeLists.txt.gtest.in b/deps/ledger-zxlib/cmake/gtest/CMakeLists.txt.gtest.in index f074ccf6..b30f8be0 100644 --- a/deps/ledger-zxlib/cmake/gtest/CMakeLists.txt.gtest.in +++ b/deps/ledger-zxlib/cmake/gtest/CMakeLists.txt.gtest.in @@ -1,12 +1,12 @@ # Based on https://github.com/google/googletest/tree/master/googletest#incorporating-into-an-existing-cmake-project -cmake_minimum_required(VERSION 2.8.2) +cmake_minimum_required(VERSION 3.0.0) project(googletest-download NONE) include(ExternalProject) ExternalProject_Add(googletest GIT_REPOSITORY https://github.com/google/googletest.git - GIT_TAG master + GIT_TAG release-1.11.0 SOURCE_DIR "${CMAKE_BINARY_DIR}/googletest-src" BINARY_DIR "${CMAKE_BINARY_DIR}/googletest-build" CONFIGURE_COMMAND "" diff --git a/deps/ledger-zxlib/dockerized_build.mk b/deps/ledger-zxlib/dockerized_build.mk index 50f2e4dc..016f6a57 100644 --- a/deps/ledger-zxlib/dockerized_build.mk +++ b/deps/ledger-zxlib/dockerized_build.mk @@ -159,11 +159,11 @@ delete: .PHONY: loadX loadX: - ${LEDGER_SRC}/pkg/installer_x.sh load + ${LEDGER_SRC}/pkg/installer_XL.sh load .PHONY: deleteX deleteX: - ${LEDGER_SRC}/pkg/installer_x.sh delete + ${LEDGER_SRC}/pkg/installer_XL.sh delete .PHONY: show_info_recovery_mode show_info_recovery_mode: diff --git a/deps/ledger-zxlib/include/segwit_addr.h b/deps/ledger-zxlib/include/segwit_addr.h index d03bb11d..f97bcfaf 100644 --- a/deps/ledger-zxlib/include/segwit_addr.h +++ b/deps/ledger-zxlib/include/segwit_addr.h @@ -89,7 +89,7 @@ int bech32_encode( * data_len: Pointer to a size_t that will be updated to be the number * of entries in data. * In: input: Pointer to a null-terminated Bech32 string. - * Returns 1 if succesful. + * Returns 1 if successful. */ int bech32_decode( char *hrp, diff --git a/deps/ledger-zxlib/include/utf8.h b/deps/ledger-zxlib/include/utf8.h index 4a0ca694..fe2e8d9f 100644 --- a/deps/ledger-zxlib/include/utf8.h +++ b/deps/ledger-zxlib/include/utf8.h @@ -1,30 +1,30 @@ -// The latest version of this library is available on GitHub; -// https://github.com/sheredom/utf8.h - -// This is free and unencumbered software released into the public domain. -// -// Anyone is free to copy, modify, publish, use, compile, sell, or -// distribute this software, either in source code form or as a compiled -// binary, for any purpose, commercial or non-commercial, and by any -// means. -// -// In jurisdictions that recognize copyright laws, the author or authors -// of this software dedicate any and all copyright interest in the -// software to the public domain. We make this dedication for the benefit -// of the public at large and to the detriment of our heirs and -// successors. We intend this dedication to be an overt act of -// relinquishment in perpetuity of all present and future rights to this -// software under copyright law. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR -// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// -// For more information, please refer to +/* The latest version of this library is available on GitHub; + * https://github.com/sheredom/utf8.h */ + +/* This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * For more information, please refer to */ #ifndef SHEREDOM_UTF8_H_INCLUDED #define SHEREDOM_UTF8_H_INCLUDED @@ -32,7 +32,14 @@ #if defined(_MSC_VER) #pragma warning(push) -// disable 'bytes padding added after construct' warning +/* disable warning: no function prototype given: converting '()' to '(void)' */ +#pragma warning(disable : 4255) + +/* disable warning: '__cplusplus' is not defined as a preprocessor macro, + * replacing with '0' for '#if/#elif' */ +#pragma warning(disable : 4668) + +/* disable warning: bytes padding added after construct */ #pragma warning(disable : 4820) #endif @@ -43,7 +50,7 @@ #pragma warning(pop) #endif -#if defined(_MSC_VER) +#if defined(_MSC_VER) && (_MSC_VER < 1920) typedef __int32 utf8_int32_t; #else #include @@ -60,16 +67,16 @@ typedef int32_t utf8_int32_t; extern "C" { #endif -#if defined(__clang__) || defined(__GNUC__) -#define utf8_nonnull __attribute__((nonnull)) -#define utf8_pure __attribute__((pure)) -#define utf8_restrict __restrict__ -#define utf8_weak __attribute__((weak)) -#elif defined(_MSC_VER) +#if defined(_MSC_VER) #define utf8_nonnull #define utf8_pure #define utf8_restrict __restrict #define utf8_weak __inline +#elif defined(__clang__) || defined(__GNUC__) +#define utf8_nonnull __attribute__((nonnull)) +#define utf8_pure __attribute__((pure)) +#define utf8_restrict __restrict__ +#define utf8_weak __attribute__((weak)) #else #error Non clang, non gcc, non MSVC compiler found! #endif @@ -80,385 +87,471 @@ extern "C" { #define utf8_null 0 #endif -// Return less than 0, 0, greater than 0 if src1 < src2, src1 == src2, src1 > -// src2 respectively, case insensitive. -utf8_nonnull utf8_pure utf8_weak int utf8casecmp(const void *src1, - const void *src2); - -// Append the utf8 string src onto the utf8 string dst. -utf8_nonnull utf8_weak void *utf8cat(void *utf8_restrict dst, - const void *utf8_restrict src); - -// Find the first match of the utf8 codepoint chr in the utf8 string src. -utf8_nonnull utf8_pure utf8_weak void *utf8chr(const void *src, - utf8_int32_t chr); - -// Return less than 0, 0, greater than 0 if src1 < src2, -// src1 == src2, src1 > src2 respectively. -utf8_nonnull utf8_pure utf8_weak int utf8cmp(const void *src1, - const void *src2); - -// Copy the utf8 string src onto the memory allocated in dst. -utf8_nonnull utf8_weak void *utf8cpy(void *utf8_restrict dst, - const void *utf8_restrict src); - -// Number of utf8 codepoints in the utf8 string src that consists entirely -// of utf8 codepoints not from the utf8 string reject. -utf8_nonnull utf8_pure utf8_weak size_t utf8cspn(const void *src, - const void *reject); - -// Duplicate the utf8 string src by getting its size, malloc'ing a new buffer -// copying over the data, and returning that. Or 0 if malloc failed. -utf8_nonnull utf8_weak void *utf8dup(const void *src); - -// Number of utf8 codepoints in the utf8 string str, -// excluding the null terminating byte. -utf8_nonnull utf8_pure utf8_weak size_t utf8len(const void *str); - -// Return less than 0, 0, greater than 0 if src1 < src2, src1 == src2, src1 > -// src2 respectively, case insensitive. Checking at most n bytes of each utf8 -// string. -utf8_nonnull utf8_pure utf8_weak int utf8ncasecmp(const void *src1, - const void *src2, size_t n); - -// Append the utf8 string src onto the utf8 string dst, -// writing at most n+1 bytes. Can produce an invalid utf8 -// string if n falls partway through a utf8 codepoint. -utf8_nonnull utf8_weak void *utf8ncat(void *utf8_restrict dst, - const void *utf8_restrict src, size_t n); - -// Return less than 0, 0, greater than 0 if src1 < src2, -// src1 == src2, src1 > src2 respectively. Checking at most n -// bytes of each utf8 string. -utf8_nonnull utf8_pure utf8_weak int utf8ncmp(const void *src1, - const void *src2, size_t n); - -// Copy the utf8 string src onto the memory allocated in dst. -// Copies at most n bytes. If there is no terminating null byte in -// the first n bytes of src, the string placed into dst will not be -// null-terminated. If the size (in bytes) of src is less than n, -// extra null terminating bytes are appended to dst such that at -// total of n bytes are written. Can produce an invalid utf8 -// string if n falls partway through a utf8 codepoint. -utf8_nonnull utf8_weak void *utf8ncpy(void *utf8_restrict dst, - const void *utf8_restrict src, size_t n); - -// Similar to utf8dup, except that at most n bytes of src are copied. If src is -// longer than n, only n bytes are copied and a null byte is added. -// -// Returns a new string if successful, 0 otherwise -utf8_nonnull utf8_weak void *utf8ndup(const void *src, size_t n); - -// Locates the first occurence in the utf8 string str of any byte in the -// utf8 string accept, or 0 if no match was found. -utf8_nonnull utf8_pure utf8_weak void *utf8pbrk(const void *str, - const void *accept); - -// Find the last match of the utf8 codepoint chr in the utf8 string src. -utf8_nonnull utf8_pure utf8_weak void *utf8rchr(const void *src, int chr); - -// Number of bytes in the utf8 string str, -// including the null terminating byte. -utf8_nonnull utf8_pure utf8_weak size_t utf8size(const void *str); - -// Number of utf8 codepoints in the utf8 string src that consists entirely -// of utf8 codepoints from the utf8 string accept. -utf8_nonnull utf8_pure utf8_weak size_t utf8spn(const void *src, - const void *accept); - -// The position of the utf8 string needle in the utf8 string haystack. -utf8_nonnull utf8_pure utf8_weak void *utf8str(const void *haystack, - const void *needle); - -// The position of the utf8 string needle in the utf8 string haystack, case -// insensitive. -utf8_nonnull utf8_pure utf8_weak void *utf8casestr(const void *haystack, - const void *needle); - -// Return 0 on success, or the position of the invalid -// utf8 codepoint on failure. -utf8_nonnull utf8_pure utf8_weak void *utf8valid(const void *str); - -// Sets out_codepoint to the next utf8 codepoint in str, and returns the address -// of the utf8 codepoint after the current one in str. -utf8_nonnull utf8_weak void * -utf8codepoint(const void *utf8_restrict str, - utf8_int32_t *utf8_restrict out_codepoint); - -// Returns the size of the given codepoint in bytes. -utf8_weak size_t utf8codepointsize(utf8_int32_t chr); - -// Write a codepoint to the given string, and return the address to the next -// place after the written codepoint. Pass how many bytes left in the buffer to -// n. If there is not enough space for the codepoint, this function returns -// null. -utf8_nonnull utf8_weak void *utf8catcodepoint(void *utf8_restrict str, - utf8_int32_t chr, size_t n); - -// Returns 1 if the given character is lowercase, or 0 if it is not. -utf8_weak int utf8islower(utf8_int32_t chr); - -// Returns 1 if the given character is uppercase, or 0 if it is not. -utf8_weak int utf8isupper(utf8_int32_t chr); - -// Transform the given string into all lowercase codepoints. -utf8_nonnull utf8_weak void utf8lwr(void *utf8_restrict str); +#if (defined(__cplusplus) && __cplusplus >= 201402L) +#define utf8_constexpr14 constexpr +#define utf8_constexpr14_impl constexpr +#else +/* constexpr and weak are incompatible. so only enable one of them */ +#define utf8_constexpr14 utf8_weak +#define utf8_constexpr14_impl +#endif -// Transform the given string into all uppercase codepoints. -utf8_nonnull utf8_weak void utf8upr(void *utf8_restrict str); +#if defined(__cplusplus) && __cplusplus >= 202002L +using utf8_int8_t = char8_t; /* Introduced in C++20 */ +#else +typedef char utf8_int8_t; +#endif -// Make a codepoint lower case if possible. -utf8_weak utf8_int32_t utf8lwrcodepoint(utf8_int32_t cp); +/* Return less than 0, 0, greater than 0 if src1 < src2, src1 == src2, src1 > + * src2 respectively, case insensitive. */ +utf8_constexpr14 utf8_nonnull utf8_pure int +utf8casecmp(const utf8_int8_t *src1, const utf8_int8_t *src2); + +/* Append the utf8 string src onto the utf8 string dst. */ +utf8_nonnull utf8_weak utf8_int8_t * +utf8cat(utf8_int8_t *utf8_restrict dst, const utf8_int8_t *utf8_restrict src); + +/* Find the first match of the utf8 codepoint chr in the utf8 string src. */ +utf8_constexpr14 utf8_nonnull utf8_pure utf8_int8_t * +utf8chr(const utf8_int8_t *src, utf8_int32_t chr); + +/* Return less than 0, 0, greater than 0 if src1 < src2, + * src1 == src2, src1 > src2 respectively. */ +utf8_constexpr14 utf8_nonnull utf8_pure int utf8cmp(const utf8_int8_t *src1, + const utf8_int8_t *src2); + +/* Copy the utf8 string src onto the memory allocated in dst. */ +utf8_nonnull utf8_weak utf8_int8_t * + utf8cpy(utf8_int8_t *utf8_restrict dst, const utf8_int8_t *utf8_restrict src); + +/* Number of utf8 codepoints in the utf8 string src that consists entirely + * of utf8 codepoints not from the utf8 string reject. */ +utf8_constexpr14 utf8_nonnull utf8_pure size_t +utf8cspn(const utf8_int8_t *src, const utf8_int8_t *reject); + +/* Duplicate the utf8 string src by getting its size, malloc'ing a new buffer + * copying over the data, and returning that. Or 0 if malloc failed. */ +utf8_weak utf8_int8_t *utf8dup(const utf8_int8_t *src); + +/* Number of utf8 codepoints in the utf8 string str, + * excluding the null terminating byte. */ +utf8_constexpr14 utf8_nonnull utf8_pure size_t utf8len(const utf8_int8_t *str); + +/* Similar to utf8len, except that only at most n bytes of src are looked. */ +utf8_constexpr14 utf8_nonnull utf8_pure size_t utf8nlen(const utf8_int8_t *str, + size_t n); + +/* Return less than 0, 0, greater than 0 if src1 < src2, src1 == src2, src1 > + * src2 respectively, case insensitive. Checking at most n bytes of each utf8 + * string. */ +utf8_constexpr14 utf8_nonnull utf8_pure int +utf8ncasecmp(const utf8_int8_t *src1, const utf8_int8_t *src2, size_t n); + +/* Append the utf8 string src onto the utf8 string dst, + * writing at most n+1 bytes. Can produce an invalid utf8 + * string if n falls partway through a utf8 codepoint. */ +utf8_nonnull utf8_weak utf8_int8_t * + utf8ncat(utf8_int8_t *utf8_restrict dst, const utf8_int8_t *utf8_restrict src, +size_t n); + +/* Return less than 0, 0, greater than 0 if src1 < src2, + * src1 == src2, src1 > src2 respectively. Checking at most n + * bytes of each utf8 string. */ +utf8_constexpr14 utf8_nonnull utf8_pure int +utf8ncmp(const utf8_int8_t *src1, const utf8_int8_t *src2, size_t n); + +/* Copy the utf8 string src onto the memory allocated in dst. + * Copies at most n bytes. If n falls partway through a utf8 + * codepoint, or if dst doesn't have enough room for a null + * terminator, the final string will be cut short to preserve + * utf8 validity. */ + +utf8_nonnull utf8_weak utf8_int8_t * + utf8ncpy(utf8_int8_t *utf8_restrict dst, const utf8_int8_t *utf8_restrict src, +size_t n); + +/* Similar to utf8dup, except that at most n bytes of src are copied. If src is + * longer than n, only n bytes are copied and a null byte is added. + * + * Returns a new string if successful, 0 otherwise */ +utf8_weak utf8_int8_t *utf8ndup(const utf8_int8_t *src, size_t n); + +/* Locates the first occurrence in the utf8 string str of any byte in the + * utf8 string accept, or 0 if no match was found. */ +utf8_constexpr14 utf8_nonnull utf8_pure utf8_int8_t * +utf8pbrk(const utf8_int8_t *str, const utf8_int8_t *accept); + +/* Find the last match of the utf8 codepoint chr in the utf8 string src. */ +utf8_constexpr14 utf8_nonnull utf8_pure utf8_int8_t * +utf8rchr(const utf8_int8_t *src, int chr); + +/* Number of bytes in the utf8 string str, + * including the null terminating byte. */ +utf8_constexpr14 utf8_nonnull utf8_pure size_t utf8size(const utf8_int8_t *str); + +/* Similar to utf8size, except that the null terminating byte is excluded. */ +utf8_constexpr14 utf8_nonnull utf8_pure size_t +utf8size_lazy(const utf8_int8_t *str); + +/* Similar to utf8size, except that only at most n bytes of src are looked and + * the null terminating byte is excluded. */ +utf8_constexpr14 utf8_nonnull utf8_pure size_t +utf8nsize_lazy(const utf8_int8_t *str, size_t n); + +/* Number of utf8 codepoints in the utf8 string src that consists entirely + * of utf8 codepoints from the utf8 string accept. */ +utf8_constexpr14 utf8_nonnull utf8_pure size_t +utf8spn(const utf8_int8_t *src, const utf8_int8_t *accept); + +/* The position of the utf8 string needle in the utf8 string haystack. */ +utf8_constexpr14 utf8_nonnull utf8_pure utf8_int8_t * +utf8str(const utf8_int8_t *haystack, const utf8_int8_t *needle); + +/* The position of the utf8 string needle in the utf8 string haystack, case + * insensitive. */ +utf8_constexpr14 utf8_nonnull utf8_pure utf8_int8_t * +utf8casestr(const utf8_int8_t *haystack, const utf8_int8_t *needle); + +/* Return 0 on success, or the position of the invalid + * utf8 codepoint on failure. */ +utf8_constexpr14 utf8_nonnull utf8_pure utf8_int8_t * +utf8valid(const utf8_int8_t *str); + +/* Similar to utf8valid, except that only at most n bytes of src are looked. */ +utf8_constexpr14 utf8_nonnull utf8_pure utf8_int8_t * +utf8nvalid(const utf8_int8_t *str, size_t n); + +/* Given a null-terminated string, makes the string valid by replacing invalid + * codepoints with a 1-byte replacement. Returns 0 on success. */ +utf8_nonnull utf8_weak int utf8makevalid(utf8_int8_t *str, +const utf8_int32_t replacement); + +/* Sets out_codepoint to the current utf8 codepoint in str, and returns the + * address of the next utf8 codepoint after the current one in str. */ +utf8_constexpr14 utf8_nonnull utf8_int8_t * +utf8codepoint(const utf8_int8_t *utf8_restrict str, + utf8_int32_t *utf8_restrict out_codepoint); -// Make a codepoint upper case if possible. -utf8_weak utf8_int32_t utf8uprcodepoint(utf8_int32_t cp); +/* Calculates the size of the next utf8 codepoint in str. */ +utf8_constexpr14 utf8_nonnull size_t +utf8codepointcalcsize(const utf8_int8_t *str); + +/* Returns the size of the given codepoint in bytes. */ +utf8_constexpr14 size_t utf8codepointsize(utf8_int32_t chr); + +/* Write a codepoint to the given string, and return the address to the next + * place after the written codepoint. Pass how many bytes left in the buffer to + * n. If there is not enough space for the codepoint, this function returns + * null. */ +utf8_nonnull utf8_weak utf8_int8_t * + utf8catcodepoint(utf8_int8_t *str, utf8_int32_t chr, size_t n); + +/* Returns 1 if the given character is lowercase, or 0 if it is not. */ +utf8_constexpr14 int utf8islower(utf8_int32_t chr); + +/* Returns 1 if the given character is uppercase, or 0 if it is not. */ +utf8_constexpr14 int utf8isupper(utf8_int32_t chr); + +/* Transform the given string into all lowercase codepoints. */ +utf8_nonnull utf8_weak void utf8lwr(utf8_int8_t *utf8_restrict str); + +/* Transform the given string into all uppercase codepoints. */ +utf8_nonnull utf8_weak void utf8upr(utf8_int8_t *utf8_restrict str); + +/* Make a codepoint lower case if possible. */ +utf8_constexpr14 utf8_int32_t utf8lwrcodepoint(utf8_int32_t cp); + +/* Make a codepoint upper case if possible. */ +utf8_constexpr14 utf8_int32_t utf8uprcodepoint(utf8_int32_t cp); + +/* Sets out_codepoint to the current utf8 codepoint in str, and returns the + * address of the previous utf8 codepoint before the current one in str. */ +utf8_constexpr14 utf8_nonnull utf8_int8_t * +utf8rcodepoint(const utf8_int8_t *utf8_restrict str, + utf8_int32_t *utf8_restrict out_codepoint); + +/* Duplicate the utf8 string src by getting its size, calling alloc_func_ptr to + * copy over data to a new buffer, and returning that. Or 0 if alloc_func_ptr + * returned null. */ +utf8_weak utf8_int8_t *utf8dup_ex(const utf8_int8_t *src, + utf8_int8_t *(*alloc_func_ptr)(utf8_int8_t *, + size_t), + utf8_int8_t *user_data); + +/* Similar to utf8dup, except that at most n bytes of src are copied. If src is + * longer than n, only n bytes are copied and a null byte is added. + * + * Returns a new string if successful, 0 otherwise. */ +utf8_weak utf8_int8_t *utf8ndup_ex(const utf8_int8_t *src, size_t n, + utf8_int8_t *(*alloc_func_ptr)(utf8_int8_t *, + size_t), + utf8_int8_t *user_data); #undef utf8_weak #undef utf8_pure #undef utf8_nonnull -int utf8casecmp(const void *src1, const void *src2) { - utf8_int32_t src1_cp, src2_cp, src1_orig_cp, src2_orig_cp; +utf8_constexpr14_impl int utf8casecmp(const utf8_int8_t *src1, + const utf8_int8_t *src2) { + utf8_int32_t src1_lwr_cp = 0, src2_lwr_cp = 0, src1_upr_cp = 0, + src2_upr_cp = 0, src1_orig_cp = 0, src2_orig_cp = 0; for (;;) { - src1 = utf8codepoint(src1, &src1_cp); - src2 = utf8codepoint(src2, &src2_cp); + src1 = utf8codepoint(src1, &src1_orig_cp); + src2 = utf8codepoint(src2, &src2_orig_cp); - // Take a copy of src1 & src2 - src1_orig_cp = src1_cp; - src2_orig_cp = src2_cp; + /* lower the srcs if required */ + src1_lwr_cp = utf8lwrcodepoint(src1_orig_cp); + src2_lwr_cp = utf8lwrcodepoint(src2_orig_cp); - // Lower the srcs if required - src1_cp = utf8lwrcodepoint(src1_cp); - src2_cp = utf8lwrcodepoint(src2_cp); + /* lower the srcs if required */ + src1_upr_cp = utf8uprcodepoint(src1_orig_cp); + src2_upr_cp = utf8uprcodepoint(src2_orig_cp); - // Check if the lowered codepoints match + /* check if the lowered codepoints match */ if ((0 == src1_orig_cp) && (0 == src2_orig_cp)) { return 0; - } else if (src1_cp == src2_cp) { + } else if ((src1_lwr_cp == src2_lwr_cp) || (src1_upr_cp == src2_upr_cp)) { continue; } - // If they don't match, then we return which of the original's are less - if (src1_orig_cp < src2_orig_cp) { - return -1; - } else if (src1_orig_cp > src2_orig_cp) { - return 1; - } + /* if they don't match, then we return the difference between the characters + */ + return src1_lwr_cp - src2_lwr_cp; } } -void *utf8cat(void *utf8_restrict dst, const void *utf8_restrict src) { - char *d = (char *)dst; - const char *s = (const char *)src; - - // find the null terminating byte in dst - while ('\0' != *d) { - d++; - } +utf8_int8_t *utf8cat(utf8_int8_t *utf8_restrict dst, +const utf8_int8_t *utf8_restrict src) { +utf8_int8_t *d = dst; +/* find the null terminating byte in dst */ +while ('\0' != *d) { +d++; +} - // overwriting the null terminating byte in dst, append src byte-by-byte - while ('\0' != *s) { - *d++ = *s++; - } +/* overwriting the null terminating byte in dst, append src byte-by-byte */ +while ('\0' != *src) { +*d++ = *src++; +} - // write out a new null terminating byte into dst - *d = '\0'; +/* write out a new null terminating byte into dst */ +*d = '\0'; - return dst; +return dst; } -void *utf8chr(const void *src, utf8_int32_t chr) { - char c[5] = {'\0', '\0', '\0', '\0', '\0'}; +utf8_constexpr14_impl utf8_int8_t *utf8chr(const utf8_int8_t *src, + utf8_int32_t chr) { + utf8_int8_t c[5] = {'\0', '\0', '\0', '\0', '\0'}; if (0 == chr) { - // being asked to return position of null terminating byte, so - // just run s to the end, and return! - const char *s = (const char *)src; - while ('\0' != *s) { - s++; + /* being asked to return position of null terminating byte, so + * just run s to the end, and return! */ + while ('\0' != *src) { + src++; } - return (void *)s; + return (utf8_int8_t *)src; } else if (0 == ((utf8_int32_t)0xffffff80 & chr)) { - // 1-byte/7-bit ascii - // (0b0xxxxxxx) - c[0] = (char)chr; + /* 1-byte/7-bit ascii + * (0b0xxxxxxx) */ + c[0] = (utf8_int8_t)chr; } else if (0 == ((utf8_int32_t)0xfffff800 & chr)) { - // 2-byte/11-bit utf8 code point - // (0b110xxxxx 0b10xxxxxx) - c[0] = 0xc0 | (char)(chr >> 6); - c[1] = 0x80 | (char)(chr & 0x3f); + /* 2-byte/11-bit utf8 code point + * (0b110xxxxx 0b10xxxxxx) */ + c[0] = (utf8_int8_t)(0xc0 | (utf8_int8_t)(chr >> 6)); + c[1] = (utf8_int8_t)(0x80 | (utf8_int8_t)(chr & 0x3f)); } else if (0 == ((utf8_int32_t)0xffff0000 & chr)) { - // 3-byte/16-bit utf8 code point - // (0b1110xxxx 0b10xxxxxx 0b10xxxxxx) - c[0] = 0xe0 | (char)(chr >> 12); - c[1] = 0x80 | (char)((chr >> 6) & 0x3f); - c[2] = 0x80 | (char)(chr & 0x3f); - } else { // if (0 == ((int)0xffe00000 & chr)) { - // 4-byte/21-bit utf8 code point - // (0b11110xxx 0b10xxxxxx 0b10xxxxxx 0b10xxxxxx) - c[0] = 0xf0 | (char)(chr >> 18); - c[1] = 0x80 | (char)((chr >> 12) & 0x3f); - c[2] = 0x80 | (char)((chr >> 6) & 0x3f); - c[3] = 0x80 | (char)(chr & 0x3f); + /* 3-byte/16-bit utf8 code point + * (0b1110xxxx 0b10xxxxxx 0b10xxxxxx) */ + c[0] = (utf8_int8_t)(0xe0 | (utf8_int8_t)(chr >> 12)); + c[1] = (utf8_int8_t)(0x80 | (utf8_int8_t)((chr >> 6) & 0x3f)); + c[2] = (utf8_int8_t)(0x80 | (utf8_int8_t)(chr & 0x3f)); + } else { /* if (0 == ((int)0xffe00000 & chr)) { */ + /* 4-byte/21-bit utf8 code point + * (0b11110xxx 0b10xxxxxx 0b10xxxxxx 0b10xxxxxx) */ + c[0] = (utf8_int8_t)(0xf0 | (utf8_int8_t)(chr >> 18)); + c[1] = (utf8_int8_t)(0x80 | (utf8_int8_t)((chr >> 12) & 0x3f)); + c[2] = (utf8_int8_t)(0x80 | (utf8_int8_t)((chr >> 6) & 0x3f)); + c[3] = (utf8_int8_t)(0x80 | (utf8_int8_t)(chr & 0x3f)); } - // we've made c into a 2 utf8 codepoint string, one for the chr we are - // seeking, another for the null terminating byte. Now use utf8str to - // search + /* we've made c into a 2 utf8 codepoint string, one for the chr we are + * seeking, another for the null terminating byte. Now use utf8str to + * search */ return utf8str(src, c); } -int utf8cmp(const void *src1, const void *src2) { - const unsigned char *s1 = (const unsigned char *)src1; - const unsigned char *s2 = (const unsigned char *)src2; - - while (('\0' != *s1) || ('\0' != *s2)) { - if (*s1 < *s2) { +utf8_constexpr14_impl int utf8cmp(const utf8_int8_t *src1, + const utf8_int8_t *src2) { + while (('\0' != *src1) || ('\0' != *src2)) { + if (*src1 < *src2) { return -1; - } else if (*s1 > *s2) { + } else if (*src1 > *src2) { return 1; } - s1++; - s2++; + src1++; + src2++; } - // both utf8 strings matched + /* both utf8 strings matched */ return 0; } -int utf8coll(const void *src1, const void *src2); +utf8_constexpr14_impl int utf8coll(const utf8_int8_t *src1, + const utf8_int8_t *src2); -void *utf8cpy(void *utf8_restrict dst, const void *utf8_restrict src) { - char *d = (char *)dst; - const char *s = (const char *)src; +utf8_int8_t *utf8cpy(utf8_int8_t *utf8_restrict dst, +const utf8_int8_t *utf8_restrict src) { +utf8_int8_t *d = dst; - // overwriting anything previously in dst, write byte-by-byte - // from src - while ('\0' != *s) { - *d++ = *s++; - } +/* overwriting anything previously in dst, write byte-by-byte + * from src */ +while ('\0' != *src) { +*d++ = *src++; +} - // append null terminating byte - *d = '\0'; +/* append null terminating byte */ +*d = '\0'; - return dst; +return dst; } -size_t utf8cspn(const void *src, const void *reject) { - const char *s = (const char *)src; +utf8_constexpr14_impl size_t utf8cspn(const utf8_int8_t *src, + const utf8_int8_t *reject) { size_t chars = 0; - while ('\0' != *s) { - const char *r = (const char *)reject; + while ('\0' != *src) { + const utf8_int8_t *r = reject; size_t offset = 0; while ('\0' != *r) { - // checking that if *r is the start of a utf8 codepoint - // (it is not 0b10xxxxxx) and we have successfully matched - // a previous character (0 < offset) - we found a match + /* checking that if *r is the start of a utf8 codepoint + * (it is not 0b10xxxxxx) and we have successfully matched + * a previous character (0 < offset) - we found a match */ if ((0x80 != (0xc0 & *r)) && (0 < offset)) { return chars; } else { - if (*r == s[offset]) { - // part of a utf8 codepoint matched, so move our checking - // onwards to the next byte + if (*r == src[offset]) { + /* part of a utf8 codepoint matched, so move our checking + * onwards to the next byte */ offset++; r++; } else { - // r could be in the middle of an unmatching utf8 code point, - // so we need to march it on to the next character beginning, + /* r could be in the middle of an unmatching utf8 code point, + * so we need to march it on to the next character beginning, */ do { r++; } while (0x80 == (0xc0 & *r)); - // reset offset too as we found a mismatch + /* reset offset too as we found a mismatch */ offset = 0; } } } - // the current utf8 codepoint in src did not match reject, but src - // could have been partway through a utf8 codepoint, so we need to - // march it onto the next utf8 codepoint starting byte + /* found a match at the end of *r, so didn't get a chance to test it */ + if (0 < offset) { + return chars; + } + + /* the current utf8 codepoint in src did not match reject, but src + * could have been partway through a utf8 codepoint, so we need to + * march it onto the next utf8 codepoint starting byte */ do { - s++; - } while ((0x80 == (0xc0 & *s))); + src++; + } while ((0x80 == (0xc0 & *src))); chars++; } return chars; } -size_t utf8size(const void *str); +utf8_int8_t *utf8dup(const utf8_int8_t *src) { + return utf8dup_ex(src, utf8_null, utf8_null); +} -void *utf8dup(const void *src) { - const char *s = (const char *)src; - char *n = utf8_null; +utf8_int8_t *utf8dup_ex(const utf8_int8_t *src, + utf8_int8_t *(*alloc_func_ptr)(utf8_int8_t *, size_t), + utf8_int8_t *user_data) { +utf8_int8_t *n = utf8_null; - // figure out how many bytes (including the terminator) we need to copy first - size_t bytes = utf8size(src); +/* figure out how many bytes (including the terminator) we need to copy first + */ +size_t bytes = utf8size(src); - n = (char *)malloc(bytes); +if (alloc_func_ptr) { +n = alloc_func_ptr(user_data, bytes); +} else { +n = (utf8_int8_t *)malloc(bytes); +} - if (utf8_null == n) { - // out of memory so we bail - return utf8_null; - } else { - bytes = 0; +if (utf8_null == n) { +/* out of memory so we bail */ +return utf8_null; +} else { +bytes = 0; - // copy src byte-by-byte into our new utf8 string - while ('\0' != s[bytes]) { - n[bytes] = s[bytes]; - bytes++; - } +/* copy src byte-by-byte into our new utf8 string */ +while ('\0' != src[bytes]) { +n[bytes] = src[bytes]; +bytes++; +} - // append null terminating byte - n[bytes] = '\0'; - return n; - } +/* append null terminating byte */ +n[bytes] = '\0'; +return n; +} } -void *utf8fry(const void *str); +utf8_constexpr14_impl utf8_int8_t *utf8fry(const utf8_int8_t *str); -size_t utf8len(const void *str) { - const unsigned char *s = (const unsigned char *)str; +utf8_constexpr14_impl size_t utf8len(const utf8_int8_t *str) { + return utf8nlen(str, SIZE_MAX); +} + +utf8_constexpr14_impl size_t utf8nlen(const utf8_int8_t *str, size_t n) { + const utf8_int8_t *t = str; size_t length = 0; - while ('\0' != *s) { - if (0xf0 == (0xf8 & *s)) { - // 4-byte utf8 code point (began with 0b11110xxx) - s += 4; - } else if (0xe0 == (0xf0 & *s)) { - // 3-byte utf8 code point (began with 0b1110xxxx) - s += 3; - } else if (0xc0 == (0xe0 & *s)) { - // 2-byte utf8 code point (began with 0b110xxxxx) - s += 2; - } else { // if (0x00 == (0x80 & *s)) { - // 1-byte ascii (began with 0b0xxxxxxx) - s += 1; + while ((size_t)(str - t) < n && '\0' != *str) { + if (0xf0 == (0xf8 & *str)) { + /* 4-byte utf8 code point (began with 0b11110xxx) */ + str += 4; + } else if (0xe0 == (0xf0 & *str)) { + /* 3-byte utf8 code point (began with 0b1110xxxx) */ + str += 3; + } else if (0xc0 == (0xe0 & *str)) { + /* 2-byte utf8 code point (began with 0b110xxxxx) */ + str += 2; + } else { /* if (0x00 == (0x80 & *s)) { */ + /* 1-byte ascii (began with 0b0xxxxxxx) */ + str += 1; } - // no matter the bytes we marched s forward by, it was - // only 1 utf8 codepoint + /* no matter the bytes we marched s forward by, it was + * only 1 utf8 codepoint */ length++; } + if ((size_t)(str - t) > n) { + length--; + } return length; } -int utf8ncasecmp(const void *src1, const void *src2, size_t n) { - utf8_int32_t src1_cp, src2_cp, src1_orig_cp, src2_orig_cp; +utf8_constexpr14_impl int utf8ncasecmp(const utf8_int8_t *src1, + const utf8_int8_t *src2, size_t n) { + utf8_int32_t src1_lwr_cp = 0, src2_lwr_cp = 0, src1_upr_cp = 0, + src2_upr_cp = 0, src1_orig_cp = 0, src2_orig_cp = 0; do { - const unsigned char *const s1 = (const unsigned char *)src1; - const unsigned char *const s2 = (const unsigned char *)src2; + const utf8_int8_t *const s1 = src1; + const utf8_int8_t *const s2 = src2; - // first check that we have enough bytes left in n to contain an entire - // codepoint + /* first check that we have enough bytes left in n to contain an entire + * codepoint */ if (0 == n) { return 0; } @@ -468,9 +561,7 @@ int utf8ncasecmp(const void *src1, const void *src2, size_t n) { const utf8_int32_t c2 = (0xe0 & *s2); if (c1 < c2) { - return -1; - } else if (c1 > c2) { - return 1; + return c1 - c2; } else { return 0; } @@ -481,9 +572,7 @@ int utf8ncasecmp(const void *src1, const void *src2, size_t n) { const utf8_int32_t c2 = (0xf0 & *s2); if (c1 < c2) { - return -1; - } else if (c1 > c2) { - return 1; + return c1 - c2; } else { return 0; } @@ -494,309 +583,333 @@ int utf8ncasecmp(const void *src1, const void *src2, size_t n) { const utf8_int32_t c2 = (0xf8 & *s2); if (c1 < c2) { - return -1; - } else if (c1 > c2) { - return 1; + return c1 - c2; } else { return 0; } } - src1 = utf8codepoint(src1, &src1_cp); - src2 = utf8codepoint(src2, &src2_cp); - n -= utf8codepointsize(src1_cp); + src1 = utf8codepoint(src1, &src1_orig_cp); + src2 = utf8codepoint(src2, &src2_orig_cp); + n -= utf8codepointsize(src1_orig_cp); - // Take a copy of src1 & src2 - src1_orig_cp = src1_cp; - src2_orig_cp = src2_cp; + src1_lwr_cp = utf8lwrcodepoint(src1_orig_cp); + src2_lwr_cp = utf8lwrcodepoint(src2_orig_cp); - // Lower srcs if required - src1_cp = utf8lwrcodepoint(src1_cp); - src2_cp = utf8lwrcodepoint(src2_cp); + src1_upr_cp = utf8uprcodepoint(src1_orig_cp); + src2_upr_cp = utf8uprcodepoint(src2_orig_cp); - // Check if the lowered codepoints match + /* check if the lowered codepoints match */ if ((0 == src1_orig_cp) && (0 == src2_orig_cp)) { return 0; - } else if (src1_cp == src2_cp) { + } else if ((src1_lwr_cp == src2_lwr_cp) || (src1_upr_cp == src2_upr_cp)) { continue; } - // If they don't match, then we return which of the original's are less - if (src1_orig_cp < src2_orig_cp) { - return -1; - } else if (src1_orig_cp > src2_orig_cp) { - return 1; - } + /* if they don't match, then we return the difference between the characters + */ + return src1_lwr_cp - src2_lwr_cp; } while (0 < n); - // both utf8 strings matched + /* both utf8 strings matched */ return 0; } -void *utf8ncat(void *utf8_restrict dst, const void *utf8_restrict src, - size_t n) { - char *d = (char *)dst; - const char *s = (const char *)src; +utf8_int8_t *utf8ncat(utf8_int8_t *utf8_restrict dst, +const utf8_int8_t *utf8_restrict src, size_t n) { +utf8_int8_t *d = dst; - // find the null terminating byte in dst - while ('\0' != *d) { - d++; - } +/* find the null terminating byte in dst */ +while ('\0' != *d) { +d++; +} - // overwriting the null terminating byte in dst, append src byte-by-byte - // stopping if we run out of space - do { - *d++ = *s++; - } while (('\0' != *s) && (0 != --n)); +/* overwriting the null terminating byte in dst, append src byte-by-byte + * stopping if we run out of space */ +do { +*d++ = *src++; +} while (('\0' != *src) && (0 != --n)); - // write out a new null terminating byte into dst - *d = '\0'; +/* write out a new null terminating byte into dst */ +*d = '\0'; - return dst; +return dst; } -int utf8ncmp(const void *src1, const void *src2, size_t n) { - const unsigned char *s1 = (const unsigned char *)src1; - const unsigned char *s2 = (const unsigned char *)src2; - - while ((0 != n--) && (('\0' != *s1) || ('\0' != *s2))) { - if (*s1 < *s2) { +utf8_constexpr14_impl int utf8ncmp(const utf8_int8_t *src1, + const utf8_int8_t *src2, size_t n) { + while ((0 != n--) && (('\0' != *src1) || ('\0' != *src2))) { + if (*src1 < *src2) { return -1; - } else if (*s1 > *s2) { + } else if (*src1 > *src2) { return 1; } - s1++; - s2++; + src1++; + src2++; } - // both utf8 strings matched + /* both utf8 strings matched */ return 0; } -void *utf8ncpy(void *utf8_restrict dst, const void *utf8_restrict src, - size_t n) { - char *d = (char *)dst; - const char *s = (const char *)src; - size_t index; +utf8_int8_t *utf8ncpy(utf8_int8_t *utf8_restrict dst, +const utf8_int8_t *utf8_restrict src, size_t n) { +utf8_int8_t *d = dst; +size_t index = 0, check_index = 0; - // overwriting anything previously in dst, write byte-by-byte - // from src - for (index = 0; index < n; index++) { - d[index] = s[index]; - if ('\0' == s[index]) { - break; - } - } +if (n == 0) { +return dst; +} - // append null terminating byte - for (; index < n; index++) { - d[index] = 0; - } +/* overwriting anything previously in dst, write byte-by-byte + * from src */ +for (index = 0; index < n; index++) { +d[index] = src[index]; +if ('\0' == src[index]) { +break; +} +} - return dst; +for (check_index = index - 1; +check_index > 0 && 0x80 == (0xc0 & d[check_index]); check_index--) { +/* just moving the index */ } -void *utf8ndup(const void *src, size_t n) { - const char *s = (const char *)src; - char *c = utf8_null; - size_t bytes = 0; +if (check_index < index && +(index - check_index) < utf8codepointsize(d[check_index])) { +index = check_index; +} - // Find the end of the string or stop when n is reached - while ('\0' != s[bytes] && bytes < n) { - bytes++; - } +/* append null terminating byte */ +for (; index < n; index++) { +d[index] = 0; +} + +return dst; +} - // In case bytes is actually less than n, we need to set it - // to be used later in the copy byte by byte. - n = bytes; +utf8_int8_t *utf8ndup(const utf8_int8_t *src, size_t n) { + return utf8ndup_ex(src, n, utf8_null, utf8_null); +} - c = (char *)malloc(bytes + 1); - if (utf8_null == c) { - // out of memory so we bail - return utf8_null; - } +utf8_int8_t *utf8ndup_ex(const utf8_int8_t *src, size_t n, + utf8_int8_t *(*alloc_func_ptr)(utf8_int8_t *, size_t), + utf8_int8_t *user_data) { +utf8_int8_t *c = utf8_null; +size_t bytes = 0; - bytes = 0; +/* Find the end of the string or stop when n is reached */ +while ('\0' != src[bytes] && bytes < n) { +bytes++; +} - // copy src byte-by-byte into our new utf8 string - while ('\0' != s[bytes] && bytes < n) { - c[bytes] = s[bytes]; - bytes++; - } +/* In case bytes is actually less than n, we need to set it + * to be used later in the copy byte by byte. */ +n = bytes; - // append null terminating byte - c[bytes] = '\0'; - return c; +if (alloc_func_ptr) { +c = alloc_func_ptr(user_data, bytes + 1); +} else { +c = (utf8_int8_t *)malloc(bytes + 1); } -void *utf8rchr(const void *src, int chr) { - const char *s = (const char *)src; - const char *match = utf8_null; - char c[5] = {'\0', '\0', '\0', '\0', '\0'}; +if (utf8_null == c) { +/* out of memory so we bail */ +return utf8_null; +} + +bytes = 0; + +/* copy src byte-by-byte into our new utf8 string */ +while ('\0' != src[bytes] && bytes < n) { +c[bytes] = src[bytes]; +bytes++; +} + +/* append null terminating byte */ +c[bytes] = '\0'; +return c; +} + +utf8_constexpr14_impl utf8_int8_t *utf8rchr(const utf8_int8_t *src, int chr) { + + utf8_int8_t *match = utf8_null; + utf8_int8_t c[5] = {'\0', '\0', '\0', '\0', '\0'}; if (0 == chr) { - // being asked to return position of null terminating byte, so - // just run s to the end, and return! - while ('\0' != *s) { - s++; + /* being asked to return position of null terminating byte, so + * just run s to the end, and return! */ + while ('\0' != *src) { + src++; } - return (void *)s; + return (utf8_int8_t *)src; } else if (0 == ((int)0xffffff80 & chr)) { - // 1-byte/7-bit ascii - // (0b0xxxxxxx) - c[0] = (char)chr; + /* 1-byte/7-bit ascii + * (0b0xxxxxxx) */ + c[0] = (utf8_int8_t)chr; } else if (0 == ((int)0xfffff800 & chr)) { - // 2-byte/11-bit utf8 code point - // (0b110xxxxx 0b10xxxxxx) - c[0] = 0xc0 | (char)(chr >> 6); - c[1] = 0x80 | (char)(chr & 0x3f); + /* 2-byte/11-bit utf8 code point + * (0b110xxxxx 0b10xxxxxx) */ + c[0] = (utf8_int8_t)(0xc0 | (utf8_int8_t)(chr >> 6)); + c[1] = (utf8_int8_t)(0x80 | (utf8_int8_t)(chr & 0x3f)); } else if (0 == ((int)0xffff0000 & chr)) { - // 3-byte/16-bit utf8 code point - // (0b1110xxxx 0b10xxxxxx 0b10xxxxxx) - c[0] = 0xe0 | (char)(chr >> 12); - c[1] = 0x80 | (char)((chr >> 6) & 0x3f); - c[2] = 0x80 | (char)(chr & 0x3f); - } else { // if (0 == ((int)0xffe00000 & chr)) { - // 4-byte/21-bit utf8 code point - // (0b11110xxx 0b10xxxxxx 0b10xxxxxx 0b10xxxxxx) - c[0] = 0xf0 | (char)(chr >> 18); - c[1] = 0x80 | (char)((chr >> 12) & 0x3f); - c[2] = 0x80 | (char)((chr >> 6) & 0x3f); - c[3] = 0x80 | (char)(chr & 0x3f); + /* 3-byte/16-bit utf8 code point + * (0b1110xxxx 0b10xxxxxx 0b10xxxxxx) */ + c[0] = (utf8_int8_t)(0xe0 | (utf8_int8_t)(chr >> 12)); + c[1] = (utf8_int8_t)(0x80 | (utf8_int8_t)((chr >> 6) & 0x3f)); + c[2] = (utf8_int8_t)(0x80 | (utf8_int8_t)(chr & 0x3f)); + } else { /* if (0 == ((int)0xffe00000 & chr)) { */ + /* 4-byte/21-bit utf8 code point + * (0b11110xxx 0b10xxxxxx 0b10xxxxxx 0b10xxxxxx) */ + c[0] = (utf8_int8_t)(0xf0 | (utf8_int8_t)(chr >> 18)); + c[1] = (utf8_int8_t)(0x80 | (utf8_int8_t)((chr >> 12) & 0x3f)); + c[2] = (utf8_int8_t)(0x80 | (utf8_int8_t)((chr >> 6) & 0x3f)); + c[3] = (utf8_int8_t)(0x80 | (utf8_int8_t)(chr & 0x3f)); } - // we've created a 2 utf8 codepoint string in c that is - // the utf8 character asked for by chr, and a null - // terminating byte + /* we've created a 2 utf8 codepoint string in c that is + * the utf8 character asked for by chr, and a null + * terminating byte */ - while ('\0' != *s) { + while ('\0' != *src) { size_t offset = 0; - while (s[offset] == c[offset]) { + while (src[offset] == c[offset]) { offset++; } if ('\0' == c[offset]) { - // we found a matching utf8 code point - match = s; - s += offset; + /* we found a matching utf8 code point */ + match = (utf8_int8_t *)src; + src += offset; } else { - s += offset; + src += offset; - // need to march s along to next utf8 codepoint start - // (the next byte that doesn't match 0b10xxxxxx) - if ('\0' != *s) { + /* need to march s along to next utf8 codepoint start + * (the next byte that doesn't match 0b10xxxxxx) */ + if ('\0' != *src) { do { - s++; - } while (0x80 == (0xc0 & *s)); + src++; + } while (0x80 == (0xc0 & *src)); } } } - // return the last match we found (or 0 if no match was found) - return (void *)match; + /* return the last match we found (or 0 if no match was found) */ + return match; } -void *utf8pbrk(const void *str, const void *accept) { - const char *s = (const char *)str; - - while ('\0' != *s) { - const char *a = (const char *)accept; +utf8_constexpr14_impl utf8_int8_t *utf8pbrk(const utf8_int8_t *str, + const utf8_int8_t *accept) { + while ('\0' != *str) { + const utf8_int8_t *a = accept; size_t offset = 0; while ('\0' != *a) { - // checking that if *a is the start of a utf8 codepoint - // (it is not 0b10xxxxxx) and we have successfully matched - // a previous character (0 < offset) - we found a match + /* checking that if *a is the start of a utf8 codepoint + * (it is not 0b10xxxxxx) and we have successfully matched + * a previous character (0 < offset) - we found a match */ if ((0x80 != (0xc0 & *a)) && (0 < offset)) { - return (void *)s; + return (utf8_int8_t *)str; } else { - if (*a == s[offset]) { - // part of a utf8 codepoint matched, so move our checking - // onwards to the next byte + if (*a == str[offset]) { + /* part of a utf8 codepoint matched, so move our checking + * onwards to the next byte */ offset++; a++; } else { - // r could be in the middle of an unmatching utf8 code point, - // so we need to march it on to the next character beginning, + /* r could be in the middle of an unmatching utf8 code point, + * so we need to march it on to the next character beginning, */ do { a++; } while (0x80 == (0xc0 & *a)); - // reset offset too as we found a mismatch + /* reset offset too as we found a mismatch */ offset = 0; } } } - // we found a match on the last utf8 codepoint + /* we found a match on the last utf8 codepoint */ if (0 < offset) { - return (void *)s; + return (utf8_int8_t *)str; } - // the current utf8 codepoint in src did not match accept, but src - // could have been partway through a utf8 codepoint, so we need to - // march it onto the next utf8 codepoint starting byte + /* the current utf8 codepoint in src did not match accept, but src + * could have been partway through a utf8 codepoint, so we need to + * march it onto the next utf8 codepoint starting byte */ do { - s++; - } while ((0x80 == (0xc0 & *s))); + str++; + } while ((0x80 == (0xc0 & *str))); } return utf8_null; } -size_t utf8size(const void *str) { - const char *s = (const char *)str; +utf8_constexpr14_impl size_t utf8size(const utf8_int8_t *str) { + return utf8size_lazy(str) + 1; +} + +utf8_constexpr14_impl size_t utf8size_lazy(const utf8_int8_t *str) { + return utf8nsize_lazy(str, SIZE_MAX); +} + +utf8_constexpr14_impl size_t utf8nsize_lazy(const utf8_int8_t *str, size_t n) { size_t size = 0; - while ('\0' != s[size]) { + while (size < n && '\0' != str[size]) { size++; } - - // we are including the null terminating byte in the size calculation - size++; return size; } -size_t utf8spn(const void *src, const void *accept) { - const char *s = (const char *)src; +utf8_constexpr14_impl size_t utf8spn(const utf8_int8_t *src, + const utf8_int8_t *accept) { size_t chars = 0; - while ('\0' != *s) { - const char *a = (const char *)accept; + while ('\0' != *src) { + const utf8_int8_t *a = accept; size_t offset = 0; while ('\0' != *a) { - // checking that if *r is the start of a utf8 codepoint - // (it is not 0b10xxxxxx) and we have successfully matched - // a previous character (0 < offset) - we found a match + /* checking that if *r is the start of a utf8 codepoint + * (it is not 0b10xxxxxx) and we have successfully matched + * a previous character (0 < offset) - we found a match */ if ((0x80 != (0xc0 & *a)) && (0 < offset)) { - // found a match, so increment the number of utf8 codepoints - // that have matched and stop checking whether any other utf8 - // codepoints in a match + /* found a match, so increment the number of utf8 codepoints + * that have matched and stop checking whether any other utf8 + * codepoints in a match */ chars++; - s += offset; + src += offset; + offset = 0; break; } else { - if (*a == s[offset]) { + if (*a == src[offset]) { offset++; a++; } else { - // a could be in the middle of an unmatching utf8 codepoint, - // so we need to march it on to the next character beginning, + /* a could be in the middle of an unmatching utf8 codepoint, + * so we need to march it on to the next character beginning, */ do { a++; } while (0x80 == (0xc0 & *a)); - // reset offset too as we found a mismatch + /* reset offset too as we found a mismatch */ offset = 0; } } } - // if a got to its terminating null byte, then we didn't find a match. - // Return the current number of matched utf8 codepoints + /* found a match at the end of *a, so didn't get a chance to test it */ + if (0 < offset) { + chars++; + src += offset; + continue; + } + + /* if a got to its terminating null byte, then we didn't find a match. + * Return the current number of matched utf8 codepoints */ if ('\0' == *a) { return chars; } @@ -805,304 +918,405 @@ size_t utf8spn(const void *src, const void *accept) { return chars; } -void *utf8str(const void *haystack, const void *needle) { - const char *h = (const char *)haystack; - utf8_int32_t throwaway_codepoint; +utf8_constexpr14_impl utf8_int8_t *utf8str(const utf8_int8_t *haystack, + const utf8_int8_t *needle) { + utf8_int32_t throwaway_codepoint = 0; - // if needle has no utf8 codepoints before the null terminating - // byte then return haystack - if ('\0' == *((const char *)needle)) { - return (void *)haystack; + /* if needle has no utf8 codepoints before the null terminating + * byte then return haystack */ + if ('\0' == *needle) { + return (utf8_int8_t *)haystack; } - while ('\0' != *h) { - const char *maybeMatch = h; - const char *n = (const char *)needle; + while ('\0' != *haystack) { + const utf8_int8_t *maybeMatch = haystack; + const utf8_int8_t *n = needle; - while (*h == *n && (*h != '\0' && *n != '\0')) { + while (*haystack == *n && (*haystack != '\0' && *n != '\0')) { n++; - h++; + haystack++; } if ('\0' == *n) { - // we found the whole utf8 string for needle in haystack at - // maybeMatch, so return it - return (void *)maybeMatch; + /* we found the whole utf8 string for needle in haystack at + * maybeMatch, so return it */ + return (utf8_int8_t *)maybeMatch; } else { - // h could be in the middle of an unmatching utf8 codepoint, - // so we need to march it on to the next character beginning - // starting from the current character - h = (const char*)utf8codepoint(maybeMatch, &throwaway_codepoint); + /* h could be in the middle of an unmatching utf8 codepoint, + * so we need to march it on to the next character beginning + * starting from the current character */ + haystack = utf8codepoint(maybeMatch, &throwaway_codepoint); } } - // no match + /* no match */ return utf8_null; } -void *utf8casestr(const void *haystack, const void *needle) { - const void *h = haystack; - - // if needle has no utf8 codepoints before the null terminating - // byte then return haystack - if ('\0' == *((const char *)needle)) { - return (void *)haystack; +utf8_constexpr14_impl utf8_int8_t *utf8casestr(const utf8_int8_t *haystack, + const utf8_int8_t *needle) { + /* if needle has no utf8 codepoints before the null terminating + * byte then return haystack */ + if ('\0' == *needle) { + return (utf8_int8_t *)haystack; } for (;;) { - const void *maybeMatch = h; - const void *n = needle; - utf8_int32_t h_cp, n_cp; + const utf8_int8_t *maybeMatch = haystack; + const utf8_int8_t *n = needle; + utf8_int32_t h_cp = 0, n_cp = 0; - // Get the next code point and track it - const void *nextH = h = utf8codepoint(h, &h_cp); + /* Get the next code point and track it */ + const utf8_int8_t *nextH = haystack = utf8codepoint(haystack, &h_cp); n = utf8codepoint(n, &n_cp); while ((0 != h_cp) && (0 != n_cp)) { h_cp = utf8lwrcodepoint(h_cp); n_cp = utf8lwrcodepoint(n_cp); - // if we find a mismatch, bail out! + /* if we find a mismatch, bail out! */ if (h_cp != n_cp) { break; } - h = utf8codepoint(h, &h_cp); + haystack = utf8codepoint(haystack, &h_cp); n = utf8codepoint(n, &n_cp); } if (0 == n_cp) { - // we found the whole utf8 string for needle in haystack at - // maybeMatch, so return it - return (void *)maybeMatch; + /* we found the whole utf8 string for needle in haystack at + * maybeMatch, so return it */ + return (utf8_int8_t *)maybeMatch; } if (0 == h_cp) { - // no match + /* no match */ return utf8_null; } - // Roll back to the next code point in the haystack to test - h = nextH; + /* Roll back to the next code point in the haystack to test */ + haystack = nextH; } } -void *utf8valid(const void *str) { - const char *s = (const char *)str; +utf8_constexpr14_impl utf8_int8_t *utf8valid(const utf8_int8_t *str) { + return utf8nvalid(str, SIZE_MAX); +} + +utf8_constexpr14_impl utf8_int8_t *utf8nvalid(const utf8_int8_t *str, + size_t n) { + const utf8_int8_t *t = str; + size_t consumed = 0, remained = 0; + + while ((void)(consumed = (size_t)(str - t)), consumed < n && '\0' != *str) { + remained = n - consumed; + + if (0xf0 == (0xf8 & *str)) { + /* ensure that there's 4 bytes or more remained */ + if (remained < 4) { + return (utf8_int8_t *)str; + } + + /* ensure each of the 3 following bytes in this 4-byte + * utf8 codepoint began with 0b10xxxxxx */ + if ((0x80 != (0xc0 & str[1])) || (0x80 != (0xc0 & str[2])) || + (0x80 != (0xc0 & str[3]))) { + return (utf8_int8_t *)str; + } + + /* ensure that our utf8 codepoint ended after 4 bytes */ + if (0x80 == (0xc0 & str[4])) { + return (utf8_int8_t *)str; + } - while ('\0' != *s) { - if (0xf0 == (0xf8 & *s)) { - // ensure each of the 3 following bytes in this 4-byte - // utf8 codepoint began with 0b10xxxxxx - if ((0x80 != (0xc0 & s[1])) || (0x80 != (0xc0 & s[2])) || - (0x80 != (0xc0 & s[3]))) { - return (void *)s; + /* ensure that the top 5 bits of this 4-byte utf8 + * codepoint were not 0, as then we could have used + * one of the smaller encodings */ + if ((0 == (0x07 & str[0])) && (0 == (0x30 & str[1]))) { + return (utf8_int8_t *)str; } - // ensure that our utf8 codepoint ended after 4 bytes - if (0x80 == (0xc0 & s[4])) { - return (void *)s; + /* 4-byte utf8 code point (began with 0b11110xxx) */ + str += 4; + } else if (0xe0 == (0xf0 & *str)) { + /* ensure that there's 3 bytes or more remained */ + if (remained < 3) { + return (utf8_int8_t *)str; } - // ensure that the top 5 bits of this 4-byte utf8 - // codepoint were not 0, as then we could have used - // one of the smaller encodings - if ((0 == (0x07 & s[0])) && (0 == (0x30 & s[1]))) { - return (void *)s; + /* ensure each of the 2 following bytes in this 3-byte + * utf8 codepoint began with 0b10xxxxxx */ + if ((0x80 != (0xc0 & str[1])) || (0x80 != (0xc0 & str[2]))) { + return (utf8_int8_t *)str; } - // 4-byte utf8 code point (began with 0b11110xxx) - s += 4; - } else if (0xe0 == (0xf0 & *s)) { - // ensure each of the 2 following bytes in this 3-byte - // utf8 codepoint began with 0b10xxxxxx - if ((0x80 != (0xc0 & s[1])) || (0x80 != (0xc0 & s[2]))) { - return (void *)s; + /* ensure that our utf8 codepoint ended after 3 bytes */ + if (0x80 == (0xc0 & str[3])) { + return (utf8_int8_t *)str; } - // ensure that our utf8 codepoint ended after 3 bytes - if (0x80 == (0xc0 & s[3])) { - return (void *)s; + /* ensure that the top 5 bits of this 3-byte utf8 + * codepoint were not 0, as then we could have used + * one of the smaller encodings */ + if ((0 == (0x0f & str[0])) && (0 == (0x20 & str[1]))) { + return (utf8_int8_t *)str; } - // ensure that the top 5 bits of this 3-byte utf8 - // codepoint were not 0, as then we could have used - // one of the smaller encodings - if ((0 == (0x0f & s[0])) && (0 == (0x20 & s[1]))) { - return (void *)s; + /* 3-byte utf8 code point (began with 0b1110xxxx) */ + str += 3; + } else if (0xc0 == (0xe0 & *str)) { + /* ensure that there's 2 bytes or more remained */ + if (remained < 2) { + return (utf8_int8_t *)str; } - // 3-byte utf8 code point (began with 0b1110xxxx) - s += 3; - } else if (0xc0 == (0xe0 & *s)) { - // ensure the 1 following byte in this 2-byte - // utf8 codepoint began with 0b10xxxxxx - if (0x80 != (0xc0 & s[1])) { - return (void *)s; + /* ensure the 1 following byte in this 2-byte + * utf8 codepoint began with 0b10xxxxxx */ + if (0x80 != (0xc0 & str[1])) { + return (utf8_int8_t *)str; } - // ensure that our utf8 codepoint ended after 2 bytes - if (0x80 == (0xc0 & s[2])) { - return (void *)s; + /* ensure that our utf8 codepoint ended after 2 bytes */ + if (0x80 == (0xc0 & str[2])) { + return (utf8_int8_t *)str; } - // ensure that the top 4 bits of this 2-byte utf8 - // codepoint were not 0, as then we could have used - // one of the smaller encodings - if (0 == (0x1e & s[0])) { - return (void *)s; + /* ensure that the top 4 bits of this 2-byte utf8 + * codepoint were not 0, as then we could have used + * one of the smaller encodings */ + if (0 == (0x1e & str[0])) { + return (utf8_int8_t *)str; } - // 2-byte utf8 code point (began with 0b110xxxxx) - s += 2; - } else if (0x00 == (0x80 & *s)) { - // 1-byte ascii (began with 0b0xxxxxxx) - s += 1; + /* 2-byte utf8 code point (began with 0b110xxxxx) */ + str += 2; + } else if (0x00 == (0x80 & *str)) { + /* 1-byte ascii (began with 0b0xxxxxxx) */ + str += 1; } else { - // we have an invalid 0b1xxxxxxx utf8 code point entry - return (void *)s; + /* we have an invalid 0b1xxxxxxx utf8 code point entry */ + return (utf8_int8_t *)str; } } return utf8_null; } -void *utf8codepoint(const void *utf8_restrict str, - utf8_int32_t *utf8_restrict out_codepoint) { - const char *s = (const char *)str; +int utf8makevalid(utf8_int8_t *str, const utf8_int32_t replacement) { +utf8_int8_t *read = str; +utf8_int8_t *write = read; +const utf8_int8_t r = (utf8_int8_t)replacement; +utf8_int32_t codepoint = 0; - if (0xf0 == (0xf8 & s[0])) { - // 4 byte utf8 codepoint - *out_codepoint = ((0x07 & s[0]) << 18) | ((0x3f & s[1]) << 12) | - ((0x3f & s[2]) << 6) | (0x3f & s[3]); - s += 4; - } else if (0xe0 == (0xf0 & s[0])) { - // 3 byte utf8 codepoint +if (replacement > 0x7f) { +return -1; +} + +while ('\0' != *read) { +if (0xf0 == (0xf8 & *read)) { +/* ensure each of the 3 following bytes in this 4-byte + * utf8 codepoint began with 0b10xxxxxx */ +if ((0x80 != (0xc0 & read[1])) || (0x80 != (0xc0 & read[2])) || +(0x80 != (0xc0 & read[3]))) { +*write++ = r; +read++; +continue; +} + +/* 4-byte utf8 code point (began with 0b11110xxx) */ +read = utf8codepoint(read, &codepoint); +write = utf8catcodepoint(write, codepoint, 4); +} else if (0xe0 == (0xf0 & *read)) { +/* ensure each of the 2 following bytes in this 3-byte + * utf8 codepoint began with 0b10xxxxxx */ +if ((0x80 != (0xc0 & read[1])) || (0x80 != (0xc0 & read[2]))) { +*write++ = r; +read++; +continue; +} + +/* 3-byte utf8 code point (began with 0b1110xxxx) */ +read = utf8codepoint(read, &codepoint); +write = utf8catcodepoint(write, codepoint, 3); +} else if (0xc0 == (0xe0 & *read)) { +/* ensure the 1 following byte in this 2-byte + * utf8 codepoint began with 0b10xxxxxx */ +if (0x80 != (0xc0 & read[1])) { +*write++ = r; +read++; +continue; +} + +/* 2-byte utf8 code point (began with 0b110xxxxx) */ +read = utf8codepoint(read, &codepoint); +write = utf8catcodepoint(write, codepoint, 2); +} else if (0x00 == (0x80 & *read)) { +/* 1-byte ascii (began with 0b0xxxxxxx) */ +read = utf8codepoint(read, &codepoint); +write = utf8catcodepoint(write, codepoint, 1); +} else { +/* if we got here then we've got a dangling continuation (0b10xxxxxx) */ +*write++ = r; +read++; +continue; +} +} + +*write = '\0'; + +return 0; +} + +utf8_constexpr14_impl utf8_int8_t * +utf8codepoint(const utf8_int8_t *utf8_restrict str, + utf8_int32_t *utf8_restrict out_codepoint) { + if (0xf0 == (0xf8 & str[0])) { + /* 4 byte utf8 codepoint */ + *out_codepoint = ((0x07 & str[0]) << 18) | ((0x3f & str[1]) << 12) | + ((0x3f & str[2]) << 6) | (0x3f & str[3]); + str += 4; + } else if (0xe0 == (0xf0 & str[0])) { + /* 3 byte utf8 codepoint */ *out_codepoint = - ((0x0f & s[0]) << 12) | ((0x3f & s[1]) << 6) | (0x3f & s[2]); - s += 3; - } else if (0xc0 == (0xe0 & s[0])) { - // 2 byte utf8 codepoint - *out_codepoint = ((0x1f & s[0]) << 6) | (0x3f & s[1]); - s += 2; + ((0x0f & str[0]) << 12) | ((0x3f & str[1]) << 6) | (0x3f & str[2]); + str += 3; + } else if (0xc0 == (0xe0 & str[0])) { + /* 2 byte utf8 codepoint */ + *out_codepoint = ((0x1f & str[0]) << 6) | (0x3f & str[1]); + str += 2; } else { - // 1 byte utf8 codepoint otherwise - *out_codepoint = s[0]; - s += 1; + /* 1 byte utf8 codepoint otherwise */ + *out_codepoint = str[0]; + str += 1; + } + + return (utf8_int8_t *)str; +} + +utf8_constexpr14_impl size_t utf8codepointcalcsize(const utf8_int8_t *str) { + if (0xf0 == (0xf8 & str[0])) { + /* 4 byte utf8 codepoint */ + return 4; + } else if (0xe0 == (0xf0 & str[0])) { + /* 3 byte utf8 codepoint */ + return 3; + } else if (0xc0 == (0xe0 & str[0])) { + /* 2 byte utf8 codepoint */ + return 2; } - return (void *)s; + /* 1 byte utf8 codepoint otherwise */ + return 1; } -size_t utf8codepointsize(utf8_int32_t chr) { +utf8_constexpr14_impl size_t utf8codepointsize(utf8_int32_t chr) { if (0 == ((utf8_int32_t)0xffffff80 & chr)) { return 1; } else if (0 == ((utf8_int32_t)0xfffff800 & chr)) { return 2; } else if (0 == ((utf8_int32_t)0xffff0000 & chr)) { return 3; - } else { // if (0 == ((int)0xffe00000 & chr)) { + } else { /* if (0 == ((int)0xffe00000 & chr)) { */ return 4; } } -void *utf8catcodepoint(void *utf8_restrict str, utf8_int32_t chr, size_t n) { - char *s = (char *)str; - - if (0 == ((utf8_int32_t)0xffffff80 & chr)) { - // 1-byte/7-bit ascii - // (0b0xxxxxxx) - if (n < 1) { - return utf8_null; - } - s[0] = (char)chr; - s += 1; - } else if (0 == ((utf8_int32_t)0xfffff800 & chr)) { - // 2-byte/11-bit utf8 code point - // (0b110xxxxx 0b10xxxxxx) - if (n < 2) { - return utf8_null; - } - s[0] = 0xc0 | (char)(chr >> 6); - s[1] = 0x80 | (char)(chr & 0x3f); - s += 2; - } else if (0 == ((utf8_int32_t)0xffff0000 & chr)) { - // 3-byte/16-bit utf8 code point - // (0b1110xxxx 0b10xxxxxx 0b10xxxxxx) - if (n < 3) { - return utf8_null; - } - s[0] = 0xe0 | (char)(chr >> 12); - s[1] = 0x80 | (char)((chr >> 6) & 0x3f); - s[2] = 0x80 | (char)(chr & 0x3f); - s += 3; - } else { // if (0 == ((int)0xffe00000 & chr)) { - // 4-byte/21-bit utf8 code point - // (0b11110xxx 0b10xxxxxx 0b10xxxxxx 0b10xxxxxx) - if (n < 4) { - return utf8_null; - } - s[0] = 0xf0 | (char)(chr >> 18); - s[1] = 0x80 | (char)((chr >> 12) & 0x3f); - s[2] = 0x80 | (char)((chr >> 6) & 0x3f); - s[3] = 0x80 | (char)(chr & 0x3f); - s += 4; - } - - return s; +utf8_int8_t *utf8catcodepoint(utf8_int8_t *str, utf8_int32_t chr, size_t n) { +if (0 == ((utf8_int32_t)0xffffff80 & chr)) { +/* 1-byte/7-bit ascii + * (0b0xxxxxxx) */ +if (n < 1) { +return utf8_null; +} +str[0] = (utf8_int8_t)chr; +str += 1; +} else if (0 == ((utf8_int32_t)0xfffff800 & chr)) { +/* 2-byte/11-bit utf8 code point + * (0b110xxxxx 0b10xxxxxx) */ +if (n < 2) { +return utf8_null; +} +str[0] = (utf8_int8_t)(0xc0 | (utf8_int8_t)((chr >> 6) & 0x1f)); +str[1] = (utf8_int8_t)(0x80 | (utf8_int8_t)(chr & 0x3f)); +str += 2; +} else if (0 == ((utf8_int32_t)0xffff0000 & chr)) { +/* 3-byte/16-bit utf8 code point + * (0b1110xxxx 0b10xxxxxx 0b10xxxxxx) */ +if (n < 3) { +return utf8_null; +} +str[0] = (utf8_int8_t)(0xe0 | (utf8_int8_t)((chr >> 12) & 0x0f)); +str[1] = (utf8_int8_t)(0x80 | (utf8_int8_t)((chr >> 6) & 0x3f)); +str[2] = (utf8_int8_t)(0x80 | (utf8_int8_t)(chr & 0x3f)); +str += 3; +} else { /* if (0 == ((int)0xffe00000 & chr)) { */ +/* 4-byte/21-bit utf8 code point + * (0b11110xxx 0b10xxxxxx 0b10xxxxxx 0b10xxxxxx) */ +if (n < 4) { +return utf8_null; +} +str[0] = (utf8_int8_t)(0xf0 | (utf8_int8_t)((chr >> 18) & 0x07)); +str[1] = (utf8_int8_t)(0x80 | (utf8_int8_t)((chr >> 12) & 0x3f)); +str[2] = (utf8_int8_t)(0x80 | (utf8_int8_t)((chr >> 6) & 0x3f)); +str[3] = (utf8_int8_t)(0x80 | (utf8_int8_t)(chr & 0x3f)); +str += 4; } -int utf8islower(utf8_int32_t chr) { return chr != utf8uprcodepoint(chr); } - -int utf8isupper(utf8_int32_t chr) { return chr != utf8lwrcodepoint(chr); } +return str; +} -void utf8lwr(void *utf8_restrict str) { - void *p, *pn; - utf8_int32_t cp; +utf8_constexpr14_impl int utf8islower(utf8_int32_t chr) { + return chr != utf8uprcodepoint(chr); +} - p = (char *)str; - pn = utf8codepoint(p, &cp); +utf8_constexpr14_impl int utf8isupper(utf8_int32_t chr) { + return chr != utf8lwrcodepoint(chr); +} - while (cp != 0) { - const utf8_int32_t lwr_cp = utf8lwrcodepoint(cp); - const size_t size = utf8codepointsize(lwr_cp); +void utf8lwr(utf8_int8_t *utf8_restrict str) { +utf8_int32_t cp = 0; +utf8_int8_t *pn = utf8codepoint(str, &cp); - if (lwr_cp != cp) { - utf8catcodepoint(p, lwr_cp, size); - } +while (cp != 0) { +const utf8_int32_t lwr_cp = utf8lwrcodepoint(cp); +const size_t size = utf8codepointsize(lwr_cp); - p = pn; - pn = utf8codepoint(p, &cp); - } +if (lwr_cp != cp) { +utf8catcodepoint(str, lwr_cp, size); } -void utf8upr(void *utf8_restrict str) { - void *p, *pn; - utf8_int32_t cp; +str = pn; +pn = utf8codepoint(str, &cp); +} +} - p = (char *)str; - pn = utf8codepoint(p, &cp); +void utf8upr(utf8_int8_t *utf8_restrict str) { +utf8_int32_t cp = 0; +utf8_int8_t *pn = utf8codepoint(str, &cp); - while (cp != 0) { - const utf8_int32_t lwr_cp = utf8uprcodepoint(cp); - const size_t size = utf8codepointsize(lwr_cp); +while (cp != 0) { +const utf8_int32_t lwr_cp = utf8uprcodepoint(cp); +const size_t size = utf8codepointsize(lwr_cp); - if (lwr_cp != cp) { - utf8catcodepoint(p, lwr_cp, size); - } +if (lwr_cp != cp) { +utf8catcodepoint(str, lwr_cp, size); +} - p = pn; - pn = utf8codepoint(p, &cp); - } +str = pn; +pn = utf8codepoint(str, &cp); +} } -utf8_int32_t utf8lwrcodepoint(utf8_int32_t cp) { +utf8_constexpr14_impl utf8_int32_t utf8lwrcodepoint(utf8_int32_t cp) { if (((0x0041 <= cp) && (0x005a >= cp)) || ((0x00c0 <= cp) && (0x00d6 >= cp)) || ((0x00d8 <= cp) && (0x00de >= cp)) || ((0x0391 <= cp) && (0x03a1 >= cp)) || - ((0x03a3 <= cp) && (0x03ab >= cp))) { + ((0x03a3 <= cp) && (0x03ab >= cp)) || + ((0x0410 <= cp) && (0x042f >= cp))) { cp += 32; + } else if ((0x0400 <= cp) && (0x040f >= cp)) { + cp += 80; } else if (((0x0100 <= cp) && (0x012f >= cp)) || ((0x0132 <= cp) && (0x0137 >= cp)) || ((0x014a <= cp) && (0x0177 >= cp)) || @@ -1112,7 +1326,9 @@ utf8_int32_t utf8lwrcodepoint(utf8_int32_t cp) { ((0x01f8 <= cp) && (0x021f >= cp)) || ((0x0222 <= cp) && (0x0233 >= cp)) || ((0x0246 <= cp) && (0x024f >= cp)) || - ((0x03d8 <= cp) && (0x03ef >= cp))) { + ((0x03d8 <= cp) && (0x03ef >= cp)) || + ((0x0460 <= cp) && (0x0481 >= cp)) || + ((0x048a <= cp) && (0x04ff >= cp))) { cp |= 0x1; } else if (((0x0139 <= cp) && (0x0148 >= cp)) || ((0x0179 <= cp) && (0x017e >= cp)) || @@ -1123,62 +1339,150 @@ utf8_int32_t utf8lwrcodepoint(utf8_int32_t cp) { cp &= ~0x1; } else { switch (cp) { - default: break; - case 0x0178: cp = 0x00ff; break; - case 0x0243: cp = 0x0180; break; - case 0x018e: cp = 0x01dd; break; - case 0x023d: cp = 0x019a; break; - case 0x0220: cp = 0x019e; break; - case 0x01b7: cp = 0x0292; break; - case 0x01c4: cp = 0x01c6; break; - case 0x01c7: cp = 0x01c9; break; - case 0x01ca: cp = 0x01cc; break; - case 0x01f1: cp = 0x01f3; break; - case 0x01f7: cp = 0x01bf; break; - case 0x0187: cp = 0x0188; break; - case 0x018b: cp = 0x018c; break; - case 0x0191: cp = 0x0192; break; - case 0x0198: cp = 0x0199; break; - case 0x01a7: cp = 0x01a8; break; - case 0x01ac: cp = 0x01ad; break; - case 0x01af: cp = 0x01b0; break; - case 0x01b8: cp = 0x01b9; break; - case 0x01bc: cp = 0x01bd; break; - case 0x01f4: cp = 0x01f5; break; - case 0x023b: cp = 0x023c; break; - case 0x0241: cp = 0x0242; break; - case 0x03fd: cp = 0x037b; break; - case 0x03fe: cp = 0x037c; break; - case 0x03ff: cp = 0x037d; break; - case 0x037f: cp = 0x03f3; break; - case 0x0386: cp = 0x03ac; break; - case 0x0388: cp = 0x03ad; break; - case 0x0389: cp = 0x03ae; break; - case 0x038a: cp = 0x03af; break; - case 0x038c: cp = 0x03cc; break; - case 0x038e: cp = 0x03cd; break; - case 0x038f: cp = 0x03ce; break; - case 0x0370: cp = 0x0371; break; - case 0x0372: cp = 0x0373; break; - case 0x0376: cp = 0x0377; break; - case 0x03f4: cp = 0x03d1; break; - case 0x03cf: cp = 0x03d7; break; - case 0x03f9: cp = 0x03f2; break; - case 0x03f7: cp = 0x03f8; break; - case 0x03fa: cp = 0x03fb; break; + default: + break; + case 0x0178: + cp = 0x00ff; + break; + case 0x0243: + cp = 0x0180; + break; + case 0x018e: + cp = 0x01dd; + break; + case 0x023d: + cp = 0x019a; + break; + case 0x0220: + cp = 0x019e; + break; + case 0x01b7: + cp = 0x0292; + break; + case 0x01c4: + cp = 0x01c6; + break; + case 0x01c7: + cp = 0x01c9; + break; + case 0x01ca: + cp = 0x01cc; + break; + case 0x01f1: + cp = 0x01f3; + break; + case 0x01f7: + cp = 0x01bf; + break; + case 0x0187: + cp = 0x0188; + break; + case 0x018b: + cp = 0x018c; + break; + case 0x0191: + cp = 0x0192; + break; + case 0x0198: + cp = 0x0199; + break; + case 0x01a7: + cp = 0x01a8; + break; + case 0x01ac: + cp = 0x01ad; + break; + case 0x01af: + cp = 0x01b0; + break; + case 0x01b8: + cp = 0x01b9; + break; + case 0x01bc: + cp = 0x01bd; + break; + case 0x01f4: + cp = 0x01f5; + break; + case 0x023b: + cp = 0x023c; + break; + case 0x0241: + cp = 0x0242; + break; + case 0x03fd: + cp = 0x037b; + break; + case 0x03fe: + cp = 0x037c; + break; + case 0x03ff: + cp = 0x037d; + break; + case 0x037f: + cp = 0x03f3; + break; + case 0x0386: + cp = 0x03ac; + break; + case 0x0388: + cp = 0x03ad; + break; + case 0x0389: + cp = 0x03ae; + break; + case 0x038a: + cp = 0x03af; + break; + case 0x038c: + cp = 0x03cc; + break; + case 0x038e: + cp = 0x03cd; + break; + case 0x038f: + cp = 0x03ce; + break; + case 0x0370: + cp = 0x0371; + break; + case 0x0372: + cp = 0x0373; + break; + case 0x0376: + cp = 0x0377; + break; + case 0x03f4: + cp = 0x03b8; + break; + case 0x03cf: + cp = 0x03d7; + break; + case 0x03f9: + cp = 0x03f2; + break; + case 0x03f7: + cp = 0x03f8; + break; + case 0x03fa: + cp = 0x03fb; + break; } } return cp; } -utf8_int32_t utf8uprcodepoint(utf8_int32_t cp) { +utf8_constexpr14_impl utf8_int32_t utf8uprcodepoint(utf8_int32_t cp) { if (((0x0061 <= cp) && (0x007a >= cp)) || ((0x00e0 <= cp) && (0x00f6 >= cp)) || ((0x00f8 <= cp) && (0x00fe >= cp)) || ((0x03b1 <= cp) && (0x03c1 >= cp)) || - ((0x03c3 <= cp) && (0x03cb >= cp))) { + ((0x03c3 <= cp) && (0x03cb >= cp)) || + ((0x0430 <= cp) && (0x044f >= cp))) { cp -= 32; + } else if ((0x0450 <= cp) && (0x045f >= cp)) { + cp -= 80; } else if (((0x0100 <= cp) && (0x012f >= cp)) || ((0x0132 <= cp) && (0x0137 >= cp)) || ((0x014a <= cp) && (0x0177 >= cp)) || @@ -1188,7 +1492,9 @@ utf8_int32_t utf8uprcodepoint(utf8_int32_t cp) { ((0x01f8 <= cp) && (0x021f >= cp)) || ((0x0222 <= cp) && (0x0233 >= cp)) || ((0x0246 <= cp) && (0x024f >= cp)) || - ((0x03d8 <= cp) && (0x03ef >= cp))) { + ((0x03d8 <= cp) && (0x03ef >= cp)) || + ((0x0460 <= cp) && (0x0481 >= cp)) || + ((0x048a <= cp) && (0x04ff >= cp))) { cp &= ~0x1; } else if (((0x0139 <= cp) && (0x0148 >= cp)) || ((0x0179 <= cp) && (0x017e >= cp)) || @@ -1199,64 +1505,178 @@ utf8_int32_t utf8uprcodepoint(utf8_int32_t cp) { cp |= 0x1; } else { switch (cp) { - default: break; - case 0x00ff: cp = 0x0178; break; - case 0x0180: cp = 0x0243; break; - case 0x01dd: cp = 0x018e; break; - case 0x019a: cp = 0x023d; break; - case 0x019e: cp = 0x0220; break; - case 0x0292: cp = 0x01b7; break; - case 0x01c6: cp = 0x01c4; break; - case 0x01c9: cp = 0x01c7; break; - case 0x01cc: cp = 0x01ca; break; - case 0x01f3: cp = 0x01f1; break; - case 0x01bf: cp = 0x01f7; break; - case 0x0188: cp = 0x0187; break; - case 0x018c: cp = 0x018b; break; - case 0x0192: cp = 0x0191; break; - case 0x0199: cp = 0x0198; break; - case 0x01a8: cp = 0x01a7; break; - case 0x01ad: cp = 0x01ac; break; - case 0x01b0: cp = 0x01af; break; - case 0x01b9: cp = 0x01b8; break; - case 0x01bd: cp = 0x01bc; break; - case 0x01f5: cp = 0x01f4; break; - case 0x023c: cp = 0x023b; break; - case 0x0242: cp = 0x0241; break; - case 0x037b: cp = 0x03fd; break; - case 0x037c: cp = 0x03fe; break; - case 0x037d: cp = 0x03ff; break; - case 0x03f3: cp = 0x037f; break; - case 0x03ac: cp = 0x0386; break; - case 0x03ad: cp = 0x0388; break; - case 0x03ae: cp = 0x0389; break; - case 0x03af: cp = 0x038a; break; - case 0x03cc: cp = 0x038c; break; - case 0x03cd: cp = 0x038e; break; - case 0x03ce: cp = 0x038f; break; - case 0x0371: cp = 0x0370; break; - case 0x0373: cp = 0x0372; break; - case 0x0377: cp = 0x0376; break; - case 0x03d1: cp = 0x03f4; break; - case 0x03d7: cp = 0x03cf; break; - case 0x03f2: cp = 0x03f9; break; - case 0x03f8: cp = 0x03f7; break; - case 0x03fb: cp = 0x03fa; break; + default: + break; + case 0x00ff: + cp = 0x0178; + break; + case 0x0180: + cp = 0x0243; + break; + case 0x01dd: + cp = 0x018e; + break; + case 0x019a: + cp = 0x023d; + break; + case 0x019e: + cp = 0x0220; + break; + case 0x0292: + cp = 0x01b7; + break; + case 0x01c6: + cp = 0x01c4; + break; + case 0x01c9: + cp = 0x01c7; + break; + case 0x01cc: + cp = 0x01ca; + break; + case 0x01f3: + cp = 0x01f1; + break; + case 0x01bf: + cp = 0x01f7; + break; + case 0x0188: + cp = 0x0187; + break; + case 0x018c: + cp = 0x018b; + break; + case 0x0192: + cp = 0x0191; + break; + case 0x0199: + cp = 0x0198; + break; + case 0x01a8: + cp = 0x01a7; + break; + case 0x01ad: + cp = 0x01ac; + break; + case 0x01b0: + cp = 0x01af; + break; + case 0x01b9: + cp = 0x01b8; + break; + case 0x01bd: + cp = 0x01bc; + break; + case 0x01f5: + cp = 0x01f4; + break; + case 0x023c: + cp = 0x023b; + break; + case 0x0242: + cp = 0x0241; + break; + case 0x037b: + cp = 0x03fd; + break; + case 0x037c: + cp = 0x03fe; + break; + case 0x037d: + cp = 0x03ff; + break; + case 0x03f3: + cp = 0x037f; + break; + case 0x03ac: + cp = 0x0386; + break; + case 0x03ad: + cp = 0x0388; + break; + case 0x03ae: + cp = 0x0389; + break; + case 0x03af: + cp = 0x038a; + break; + case 0x03cc: + cp = 0x038c; + break; + case 0x03cd: + cp = 0x038e; + break; + case 0x03ce: + cp = 0x038f; + break; + case 0x0371: + cp = 0x0370; + break; + case 0x0373: + cp = 0x0372; + break; + case 0x0377: + cp = 0x0376; + break; + case 0x03d1: + cp = 0x0398; + break; + case 0x03d7: + cp = 0x03cf; + break; + case 0x03f2: + cp = 0x03f9; + break; + case 0x03f8: + cp = 0x03f7; + break; + case 0x03fb: + cp = 0x03fa; + break; } } return cp; } +utf8_constexpr14_impl utf8_int8_t * +utf8rcodepoint(const utf8_int8_t *utf8_restrict str, + utf8_int32_t *utf8_restrict out_codepoint) { + const utf8_int8_t *s = (const utf8_int8_t *)str; + + if (0xf0 == (0xf8 & s[0])) { + /* 4 byte utf8 codepoint */ + *out_codepoint = ((0x07 & s[0]) << 18) | ((0x3f & s[1]) << 12) | + ((0x3f & s[2]) << 6) | (0x3f & s[3]); + } else if (0xe0 == (0xf0 & s[0])) { + /* 3 byte utf8 codepoint */ + *out_codepoint = + ((0x0f & s[0]) << 12) | ((0x3f & s[1]) << 6) | (0x3f & s[2]); + } else if (0xc0 == (0xe0 & s[0])) { + /* 2 byte utf8 codepoint */ + *out_codepoint = ((0x1f & s[0]) << 6) | (0x3f & s[1]); + } else { + /* 1 byte utf8 codepoint otherwise */ + *out_codepoint = s[0]; + } + + do { + s--; + } while ((0 != (0x80 & s[0])) && (0x80 == (0xc0 & s[0]))); + + return (utf8_int8_t *)s; +} + #undef utf8_restrict +#undef utf8_constexpr14 #undef utf8_null #ifdef __cplusplus -} // extern "C" +} /* extern "C" */ #endif #if defined(__clang__) #pragma clang diagnostic pop #endif -#endif // SHEREDOM_UTF8_H_INCLUDED +#endif /* SHEREDOM_UTF8_H_INCLUDED */ diff --git a/deps/ledger-zxlib/include/view_templates.h b/deps/ledger-zxlib/include/view_templates.h index e653b031..a301b609 100644 --- a/deps/ledger-zxlib/include/view_templates.h +++ b/deps/ledger-zxlib/include/view_templates.h @@ -91,7 +91,7 @@ text, /* text */ \ } -#if defined(TARGET_NANOX) +#if defined(TARGET_NANOX) || defined(TARGET_NANOS2) #define UI_SCREEN_WIDTH 128 #define UI_SCREEN_HEIGHT 64 diff --git a/deps/ledger-zxlib/include/zxformat.h b/deps/ledger-zxlib/include/zxformat.h index d40170d2..d7e54db1 100644 --- a/deps/ledger-zxlib/include/zxformat.h +++ b/deps/ledger-zxlib/include/zxformat.h @@ -147,11 +147,11 @@ __Z_INLINE int64_t str_to_int64(const char *start, const char *end, char *error) } int64_t value = 0; - uint64_t multiplier = 1; + int64_t multiplier = 1; for (const char *s = end - 1; s >= start; s--) { - int delta = (*s - '0'); + int64_t delta = (*s - '0'); if (delta >= 0 && delta <= 9) { - value += (delta * multiplier); + value += delta * multiplier; multiplier *= 10; } else { if (error != NULL) { @@ -320,6 +320,44 @@ __Z_INLINE void pageString(char *outValue, uint16_t outValueLen, pageStringExt(outValue, outValueLen, inValue, (uint16_t) strlen(inValue), pageIdx, pageCount); } +__Z_INLINE zxerr_t formatBufferData( + const uint8_t *ptr, + uint64_t len, + char *outValue, + uint16_t outValueLen, + uint8_t pageIdx, + uint8_t *pageCount) { + char bufferUI[500 + 1]; + MEMZERO(bufferUI, sizeof(bufferUI)); + MEMZERO(outValue, 0); + CHECK_APP_CANARY() + + if (len >= sizeof(bufferUI)) { + return zxerr_buffer_too_small; + } + memcpy(bufferUI, ptr, len); + + // Check we have all ascii + uint8_t allAscii = 1; + for (size_t i = 0; i < len && allAscii; i++) { + if (bufferUI[i] < 32 || bufferUI[i] > 127) { + allAscii = 0; + } + } + + if (!allAscii) { + bufferUI[0] = '0'; + bufferUI[1] = 'x'; + if (array_to_hexstr(bufferUI + 2, sizeof(bufferUI) - 2, ptr, len) == 0) { + return zxerr_buffer_too_small; + } + } + + pageString(outValue, outValueLen, bufferUI, pageIdx, pageCount); + + return zxerr_ok; +} + size_t asciify(char *utf8_in); size_t asciify_ext(const char *utf8_in, char *ascii_only_out); diff --git a/deps/ledger-zxlib/include/zxmacros.h b/deps/ledger-zxlib/include/zxmacros.h index 2c661d1a..b5bf7e87 100644 --- a/deps/ledger-zxlib/include/zxmacros.h +++ b/deps/ledger-zxlib/include/zxmacros.h @@ -44,16 +44,12 @@ extern void explicit_bzero(void *s, size_t n) __THROW __nonnull ((1)); #include "bolos_target.h" #endif -#if defined (TARGET_NANOS) || defined(TARGET_NANOX) +#if defined (TARGET_NANOS) || defined(TARGET_NANOX) || defined(TARGET_NANOS2) #include "zxmacros_ledger.h" #else #include "zxmacros_x64.h" -#ifndef UNUSED -#define UNUSED(x) (void)x -#endif - #endif #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ @@ -88,7 +84,8 @@ void handle_stack_overflow(); void zemu_log_stack(const char *ctx); -#if defined(ZEMU_LOGGING) && (defined (TARGET_NANOS) || defined(TARGET_NANOX)) +#if (defined (TARGET_NANOS) || defined(TARGET_NANOX) || defined(TARGET_NANOS2)) +#if defined(ZEMU_LOGGING) __Z_INLINE void zemu_log(const char *buf) { asm volatile ( @@ -99,11 +96,19 @@ __Z_INLINE void zemu_log(const char *buf) ); } #else - __Z_INLINE void zemu_log(__Z_UNUSED const char *_) {} - +#endif +#else +__Z_INLINE void zemu_log(__Z_UNUSED const char *msg) { + printf("%s\n", msg); +} #endif +#if APP_TESTING +#define ZEMU_LOGF(SIZE, ...) { char tmp[(SIZE)]; snprintf(tmp, (SIZE), __VA_ARGS__); zemu_log(tmp); } +#else +#define ZEMU_LOGF(SIZE, ...) {} +#endif #ifdef __cplusplus } diff --git a/deps/ledger-zxlib/include/zxmacros_ledger.h b/deps/ledger-zxlib/include/zxmacros_ledger.h index a48802fd..7604b827 100644 --- a/deps/ledger-zxlib/include/zxmacros_ledger.h +++ b/deps/ledger-zxlib/include/zxmacros_ledger.h @@ -15,7 +15,7 @@ ********************************************************************************/ #pragma once -#if defined (TARGET_NANOS) || defined(TARGET_NANOX) +#if defined (TARGET_NANOS) || defined(TARGET_NANOX) || defined(TARGET_NANOS2) #include "os.h" #include "cx.h" @@ -30,7 +30,7 @@ #define MEMCMP memcmp #define MEMZERO explicit_bzero -#if defined(TARGET_NANOX) +#if defined(TARGET_NANOX) || defined(TARGET_NANOS2) #include "ux.h" #define NV_CONST const #define NV_VOLATILE volatile diff --git a/deps/ledger-zxlib/include/zxmacros_x64.h b/deps/ledger-zxlib/include/zxmacros_x64.h index eea387a8..22d27dc7 100644 --- a/deps/ledger-zxlib/include/zxmacros_x64.h +++ b/deps/ledger-zxlib/include/zxmacros_x64.h @@ -15,7 +15,7 @@ ********************************************************************************/ #pragma once -#if !defined (TARGET_NANOS) && !defined(TARGET_NANOX) +#if !defined (TARGET_NANOS) && !defined(TARGET_NANOX) && !defined(TARGET_NANOS2) // This macros are kept for backwards compatibility // the most recent SDK has unified implementations and deprecated the original os_*** diff --git a/deps/ledger-zxlib/include/zxutils_ledger.h b/deps/ledger-zxlib/include/zxutils_ledger.h new file mode 100644 index 00000000..7d3fc051 --- /dev/null +++ b/deps/ledger-zxlib/include/zxutils_ledger.h @@ -0,0 +1,12 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +unsigned short zx_compute_line_width_light(const char* text, unsigned char text_length); + + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/deps/ledger-zxlib/include/zxversion.h b/deps/ledger-zxlib/include/zxversion.h index bd7e9432..41d6607e 100644 --- a/deps/ledger-zxlib/include/zxversion.h +++ b/deps/ledger-zxlib/include/zxversion.h @@ -15,6 +15,6 @@ ********************************************************************************/ #pragma once -#define ZXLIB_MAJOR 10 -#define ZXLIB_MINOR 2 +#define ZXLIB_MAJOR 11 +#define ZXLIB_MINOR 0 #define ZXLIB_PATCH 0 diff --git a/deps/ledger-zxlib/src/app_mode.c b/deps/ledger-zxlib/src/app_mode.c index 1f1834b5..9d80d02e 100644 --- a/deps/ledger-zxlib/src/app_mode.c +++ b/deps/ledger-zxlib/src/app_mode.c @@ -26,7 +26,7 @@ typedef struct { app_mode_temporary_t app_mode_temporary; -#if defined(TARGET_NANOS) || defined(TARGET_NANOX) +#if defined(TARGET_NANOS) || defined(TARGET_NANOX) || defined(TARGET_NANOS2) ////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////// diff --git a/deps/ledger-zxlib/src/bignum.c b/deps/ledger-zxlib/src/bignum.c index ec82f4b4..442ef70a 100644 --- a/deps/ledger-zxlib/src/bignum.c +++ b/deps/ledger-zxlib/src/bignum.c @@ -54,7 +54,7 @@ void bignumLittleEndian_to_bcd(uint8_t *bcdOut, uint16_t bcdOutLen, const uint8_t *binValue, uint16_t binValueLen) { MEMZERO(bcdOut, bcdOutLen); - uint8_t carry; + uint8_t carry = 0; for (uint16_t bitIdx = 0; bitIdx < binValueLen * 8; bitIdx++) { // Fix bcd for (uint16_t j = 0; j < bcdOutLen; j++) { @@ -120,7 +120,7 @@ void bignumBigEndian_to_bcd(uint8_t *bcdOut, uint16_t bcdOutLen, const uint8_t *binValue, uint16_t binValueLen) { MEMZERO(bcdOut, bcdOutLen); - uint8_t carry; + uint8_t carry = 0; for (uint16_t bitIdx = 0; bitIdx < binValueLen * 8; bitIdx++) { // Fix bcd for (uint16_t j = 0; j < bcdOutLen; j++) { diff --git a/deps/ledger-zxlib/src/zxformat.c b/deps/ledger-zxlib/src/zxformat.c index 6047ab80..ee6d5ce4 100644 --- a/deps/ledger-zxlib/src/zxformat.c +++ b/deps/ledger-zxlib/src/zxformat.c @@ -77,7 +77,7 @@ uint8_t intstr_to_fpstr_inplace(char *number, size_t number_max_size, uint8_t de numChars = 1; } else { // Trim leading zeros - MEMCPY(number, number + firstDigit, numChars - firstDigit); + MEMMOVE(number, number + firstDigit, numChars - firstDigit); MEMZERO(number + numChars - firstDigit, firstDigit); } diff --git a/deps/ledger-zxlib/src/zxmacros.c b/deps/ledger-zxlib/src/zxmacros.c index e33475b7..5dd172b6 100644 --- a/deps/ledger-zxlib/src/zxmacros.c +++ b/deps/ledger-zxlib/src/zxmacros.c @@ -20,7 +20,7 @@ void handle_stack_overflow() { zemu_log("!!!!!!!!!!!!!!!!!!!!!! CANARY TRIGGERED!!! STACK OVERFLOW DETECTED\n"); -#if defined (TARGET_NANOS) || defined(TARGET_NANOX) +#if defined (TARGET_NANOS) || defined(TARGET_NANOX) || defined(TARGET_NANOS2) io_seproxyhal_se_reset(); #else while (1); @@ -30,12 +30,12 @@ void handle_stack_overflow() { #pragma clang diagnostic pop __Z_UNUSED void check_app_canary() { -#if defined (TARGET_NANOS) || defined(TARGET_NANOX) +#if defined (TARGET_NANOS) || defined(TARGET_NANOX) || defined(TARGET_NANOS2) if (app_stack_canary != APP_STACK_CANARY_MAGIC) handle_stack_overflow(); #endif } -#if defined(ZEMU_LOGGING) && (defined (TARGET_NANOS) || defined(TARGET_NANOX)) +#if defined(ZEMU_LOGGING) && (defined (TARGET_NANOS) || defined(TARGET_NANOX) || defined(TARGET_NANOS2)) void zemu_log_stack(const char *ctx) { #define STACK_SHIFT 20 void* p = NULL; @@ -55,7 +55,7 @@ void zemu_log_stack(__Z_UNUSED const char *ctx) {} #endif -#if defined(ZEMU_LOGGING) && (defined (TARGET_NANOS) || defined(TARGET_NANOX)) +#if defined(ZEMU_LOGGING) && (defined (TARGET_NANOS) || defined(TARGET_NANOX) || defined(TARGET_NANOS2)) void zemu_trace(const char *file, uint32_t line) { char buf[200]; snprintf(buf, sizeof(buf), "|TRACE| %s:%d\n", file, line); diff --git a/deps/ledger-zxlib/src/zxutils_ledger.c b/deps/ledger-zxlib/src/zxutils_ledger.c new file mode 100644 index 00000000..48006657 --- /dev/null +++ b/deps/ledger-zxlib/src/zxutils_ledger.c @@ -0,0 +1,154 @@ +//#******************************************************************************* +//#* (c) 2021 Zondax GmbH +//#* (c) 2020 Ledger SAS +//#* +//#* Licensed under the Apache License, Version 2.0 (the "License"); +//#* you may not use this file except in compliance with the License. +//#* You may obtain a copy of the License at +//#* +//#* http://www.apache.org/licenses/LICENSE-2.0 +//#* +//#* Unless required by applicable law or agreed to in writing, software +//#* distributed under the License is distributed on an "AS IS" BASIS, +//#* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +//#* See the License for the specific language governing permissions and +//#* limitations under the License. +//#******************************************************************************** +#include "zxutils_ledger.h" + +#ifndef NULL +#define NULL ((void *)0) +#endif + +// We implement a light mechanism in order to be able to retrieve the width of +// nano S characters, in the two possible fonts: +// - BAGL_FONT_OPEN_SANS_EXTRABOLD_11px, +// - BAGL_FONT_OPEN_SANS_REGULAR_11px. +#define NANOS_FIRST_CHAR 0x20 +#define NANOS_LAST_CHAR 0x7F + +// OPEN_SANS_REGULAR_11PX << 4 | OPEN_SANS_EXTRABOLD_11PX +const char nanos_characters_width[96] = { + 3 << 4 | 3, /* code 0020 */ + 3 << 4 | 3, /* code 0021 */ + 4 << 4 | 6, /* code 0022 */ + 7 << 4 | 7, /* code 0023 */ + 6 << 4 | 6, /* code 0024 */ + 9 << 4 | 10, /* code 0025 */ + 8 << 4 | 9, /* code 0026 */ + 2 << 4 | 3, /* code 0027 */ + 3 << 4 | 4, /* code 0028 */ + 3 << 4 | 4, /* code 0029 */ + 6 << 4 | 6, /* code 002A */ + 6 << 4 | 6, /* code 002B */ + 3 << 4 | 3, /* code 002C */ + 4 << 4 | 4, /* code 002D */ + 3 << 4 | 3, /* code 002E */ + 4 << 4 | 5, /* code 002F */ + 6 << 4 | 8, /* code 0030 */ + 6 << 4 | 6, /* code 0031 */ + 6 << 4 | 7, /* code 0032 */ + 6 << 4 | 7, /* code 0033 */ + 8 << 4 | 8, /* code 0034 */ + 6 << 4 | 6, /* code 0035 */ + 6 << 4 | 8, /* code 0036 */ + 6 << 4 | 7, /* code 0037 */ + 6 << 4 | 8, /* code 0038 */ + 6 << 4 | 8, /* code 0039 */ + 3 << 4 | 3, /* code 003A */ + 3 << 4 | 3, /* code 003B */ + 6 << 4 | 5, /* code 003C */ + 6 << 4 | 6, /* code 003D */ + 6 << 4 | 5, /* code 003E */ + 5 << 4 | 6, /* code 003F */ + 10 << 4 | 10, /* code 0040 */ + 7 << 4 | 8, /* code 0041 */ + 7 << 4 | 7, /* code 0042 */ + 7 << 4 | 7, /* code 0043 */ + 8 << 4 | 8, /* code 0044 */ + 6 << 4 | 6, /* code 0045 */ + 6 << 4 | 6, /* code 0046 */ + 8 << 4 | 8, /* code 0047 */ + 8 << 4 | 8, /* code 0048 */ + 3 << 4 | 4, /* code 0049 */ + 4 << 4 | 5, /* code 004A */ + 7 << 4 | 8, /* code 004B */ + 6 << 4 | 6, /* code 004C */ + 10 << 4 | 11, /* code 004D */ + 8 << 4 | 9, /* code 004E */ + 9 << 4 | 9, /* code 004F */ + 7 << 4 | 7, /* code 0050 */ + 9 << 4 | 9, /* code 0051 */ + 7 << 4 | 8, /* code 0052 */ + 6 << 4 | 6, /* code 0053 */ + 7 << 4 | 6, /* code 0054 */ + 8 << 4 | 8, /* code 0055 */ + 7 << 4 | 6, /* code 0056 */ + 10 << 4 | 11, /* code 0057 */ + 6 << 4 | 8, /* code 0058 */ + 6 << 4 | 7, /* code 0059 */ + 6 << 4 | 7, /* code 005A */ + 4 << 4 | 5, /* code 005B */ + 4 << 4 | 5, /* code 005C */ + 4 << 4 | 5, /* code 005D */ + 6 << 4 | 7, /* code 005E */ + 5 << 4 | 6, /* code 005F */ + 6 << 4 | 7, /* code 0060 */ + 6 << 4 | 7, /* code 0061 */ + 7 << 4 | 7, /* code 0062 */ + 5 << 4 | 6, /* code 0063 */ + 7 << 4 | 7, /* code 0064 */ + 6 << 4 | 7, /* code 0065 */ + 5 << 4 | 6, /* code 0066 */ + 6 << 4 | 7, /* code 0067 */ + 7 << 4 | 7, /* code 0068 */ + 3 << 4 | 4, /* code 0069 */ + 4 << 4 | 5, /* code 006A */ + 6 << 4 | 7, /* code 006B */ + 3 << 4 | 4, /* code 006C */ + 10 << 4 | 10, /* code 006D */ + 7 << 4 | 7, /* code 006E */ + 7 << 4 | 7, /* code 006F */ + 7 << 4 | 7, /* code 0070 */ + 7 << 4 | 7, /* code 0071 */ + 4 << 4 | 5, /* code 0072 */ + 5 << 4 | 6, /* code 0073 */ + 4 << 4 | 5, /* code 0074 */ + 7 << 4 | 7, /* code 0075 */ + 6 << 4 | 7, /* code 0076 */ + 9 << 4 | 10, /* code 0077 */ + 6 << 4 | 7, /* code 0078 */ + 6 << 4 | 7, /* code 0079 */ + 5 << 4 | 6, /* code 007A */ + 4 << 4 | 5, /* code 007B */ + 6 << 4 | 6, /* code 007C */ + 4 << 4 | 5, /* code 007D */ + 6 << 4 | 6, /* code 007E */ + 7 << 4 | 6, /* code 007F */ +}; + +unsigned short zx_compute_line_width_light(const char* text, unsigned char text_length) { + char current_char; + unsigned short line_width = 0; + + if(text == NULL) { + return 0xFFFF; + } + + // We parse the characters of the input text on all the input length. + while (text_length--) { + current_char = *text; + + if (current_char < NANOS_FIRST_CHAR || current_char > NANOS_LAST_CHAR) { + if (current_char == '\n' || current_char == '\r') { + break; + } + } + else { + // Regular. + line_width += (nanos_characters_width[current_char - NANOS_FIRST_CHAR] >> 0x04) & 0x0F; + } + text++; + } + return line_width; +} diff --git a/deps/ledger-zxlib/templates/Makefile.root b/deps/ledger-zxlib/templates/Makefile.root index 7c211328..566f6073 100644 --- a/deps/ledger-zxlib/templates/Makefile.root +++ b/deps/ledger-zxlib/templates/Makefile.root @@ -14,7 +14,7 @@ #* limitations under the License. #******************************************************************************** -# We use BOLOS_SDK to determine the develoment environment that is being used +# We use BOLOS_SDK to determine the development environment that is being used # BOLOS_SDK IS DEFINED We use the plain Makefile for Ledger # BOLOS_SDK NOT DEFINED We use a containerized build approach diff --git a/deps/ledger-zxlib/tests/base64.cpp b/deps/ledger-zxlib/tests/base64.cpp index fe24854b..af9a8e55 100644 --- a/deps/ledger-zxlib/tests/base64.cpp +++ b/deps/ledger-zxlib/tests/base64.cpp @@ -53,5 +53,5 @@ namespace { base64_encode(out, sizeof(out), data, 10); EXPECT_STREQ(out, "AQMFBwkLDQ8REw=="); - }; + } } diff --git a/deps/ledger-zxlib/tests/doubledabble.cpp b/deps/ledger-zxlib/tests/doubledabble.cpp index c0c3108d..4b7b0488 100644 --- a/deps/ledger-zxlib/tests/doubledabble.cpp +++ b/deps/ledger-zxlib/tests/doubledabble.cpp @@ -33,7 +33,7 @@ class BignumLittleEndianTests : public ::testing::TestWithParam { }; -INSTANTIATE_TEST_CASE_P +INSTANTIATE_TEST_SUITE_P ( BignumTestCases, BignumLittleEndianTests, testing::Values( @@ -99,7 +99,7 @@ TEST(BignumLittleEndianTests, range) { } } -INSTANTIATE_TEST_CASE_P +INSTANTIATE_TEST_SUITE_P ( BignumTestCases, BignumBigEndianTests, testing::Values( diff --git a/deps/ledger-zxlib/tests/timeutils.cpp b/deps/ledger-zxlib/tests/timeutils.cpp deleted file mode 100644 index 6cf1bfd4..00000000 --- a/deps/ledger-zxlib/tests/timeutils.cpp +++ /dev/null @@ -1,92 +0,0 @@ -/******************************************************************************* -* (c) 2018 Zondax GmbH -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ -#include -#include -#include - -namespace { - TEST(TIMEUTILS, basic) { - uint64_t t = 1104937465; - char output[50]; - - zxerr_t err = printTime(output, sizeof(output), t); - - EXPECT_EQ(err, zxerr_ok); - EXPECT_STREQ(output, "05Jan2005 15:04:25UTC"); - } - - TEST(TIMEUTILS, yearlookup) { - struct tm t = {0}; // Initalize to all 0's - for (uint64_t year = 70; year < 470; year++) { - t.tm_year = year; // This is year-1900, so 112 = 2012 - t.tm_mon = 0; - t.tm_mday = 1; - t.tm_hour = 0; - t.tm_min = 0; - t.tm_sec = 0; - setenv("TZ", "UTC", 1); - time_t timeSinceEpoch = mktime(&t); - - const uint32_t day = 60*60*24; - uint64_t daysSinceStart = timeSinceEpoch / day; - - std::cout << " " << daysSinceStart << ", " << std::endl; - } - } - - TEST(TIMEUTILS, loop) { - char output[50]; - char expected_output[50]; - - for (uint64_t t = 0; t < 8640000000; t += 1234567) { - zxerr_t err = printTime(output, sizeof(output), t); - EXPECT_EQ(err, zxerr_ok); - time_t tmp = t; - auto expected = gmtime(&tmp); - snprintf(expected_output, sizeof(expected_output), "%02d%s%d %02d:%02d:%02dUTC", - expected->tm_mday, - getMonth(expected->tm_mon + 1), - expected->tm_year + 1900, - expected->tm_hour, - expected->tm_min, - expected->tm_sec - ); - - std::cout << t << " " << output << " " << expected_output << std::endl; - - EXPECT_STREQ(output, expected_output); - } - } - - TEST(TIMEUTILS, zero) { - uint64_t t = 0; - char output[50]; - - zxerr_t err = printTime(output, sizeof(output), t); - - EXPECT_EQ(err, zxerr_ok); - EXPECT_STREQ(output, "01Jan1970 00:00:00UTC"); - } - - TEST(TIMEUTILS, huge) { - uint64_t t = 86400ULL * 365ULL * 5000ULL; - char output[50]; - - zxerr_t err = printTime(output, sizeof(output), t); - - EXPECT_EQ(err, zxerr_out_of_bounds); - } -} diff --git a/tests_zemu/snapshots/s-mainmenu/00002.png b/tests_zemu/snapshots/s-mainmenu/00002.png index 41728747..d1d7d5c6 100644 Binary files a/tests_zemu/snapshots/s-mainmenu/00002.png and b/tests_zemu/snapshots/s-mainmenu/00002.png differ diff --git a/tests_zemu/snapshots/s-sign_basic/00007.png b/tests_zemu/snapshots/s-sign_basic/00007.png index 3d881108..6c785ae1 100644 Binary files a/tests_zemu/snapshots/s-sign_basic/00007.png and b/tests_zemu/snapshots/s-sign_basic/00007.png differ diff --git a/tests_zemu/snapshots/s-sign_basic/00009.png b/tests_zemu/snapshots/s-sign_basic/00009.png index 9b5f916c..1126c221 100644 Binary files a/tests_zemu/snapshots/s-sign_basic/00009.png and b/tests_zemu/snapshots/s-sign_basic/00009.png differ diff --git a/tests_zemu/snapshots/s-sign_basic/00010.png b/tests_zemu/snapshots/s-sign_basic/00010.png index c0729ef2..2fb41a2b 100644 Binary files a/tests_zemu/snapshots/s-sign_basic/00010.png and b/tests_zemu/snapshots/s-sign_basic/00010.png differ diff --git a/tests_zemu/snapshots/s-sign_proposal/00004.png b/tests_zemu/snapshots/s-sign_proposal/00004.png index 58f1a9c9..b585bd5c 100644 Binary files a/tests_zemu/snapshots/s-sign_proposal/00004.png and b/tests_zemu/snapshots/s-sign_proposal/00004.png differ diff --git a/tests_zemu/snapshots/s-sign_proposal/00006.png b/tests_zemu/snapshots/s-sign_proposal/00006.png index f5a0beef..e65fef61 100644 Binary files a/tests_zemu/snapshots/s-sign_proposal/00006.png and b/tests_zemu/snapshots/s-sign_proposal/00006.png differ diff --git a/tests_zemu/snapshots/s-sign_proposal/00007.png b/tests_zemu/snapshots/s-sign_proposal/00007.png index c0729ef2..2fb41a2b 100644 Binary files a/tests_zemu/snapshots/s-sign_proposal/00007.png and b/tests_zemu/snapshots/s-sign_proposal/00007.png differ diff --git a/tests_zemu/snapshots/s-sign_proposal/00009.png b/tests_zemu/snapshots/s-sign_proposal/00009.png index a1a78aa7..350ad12d 100644 Binary files a/tests_zemu/snapshots/s-sign_proposal/00009.png and b/tests_zemu/snapshots/s-sign_proposal/00009.png differ diff --git a/tests_zemu/snapshots/s-sign_proposal/00010.png b/tests_zemu/snapshots/s-sign_proposal/00010.png index 3066cc90..a90ce3ab 100644 Binary files a/tests_zemu/snapshots/s-sign_proposal/00010.png and b/tests_zemu/snapshots/s-sign_proposal/00010.png differ diff --git a/tests_zemu/snapshots/x-mainmenu/00002.png b/tests_zemu/snapshots/x-mainmenu/00002.png index a7c87a98..7995e1c0 100644 Binary files a/tests_zemu/snapshots/x-mainmenu/00002.png and b/tests_zemu/snapshots/x-mainmenu/00002.png differ