Repository navigation
Mojibake v0.6.0
Codename: [GRAVE ACCENT]
Added
- Rust crates in
src/rust/:mojibake-syscompiles the library with Cargo and declares the raw
FFI, andmojibake-rs(imported asmojibake) adds a safe API for normalization, locale
casing, caseless matching, segmentation, terminal width, character properties, collation, IDNA,
and confusables. Run their tests withmake test-rust mojibake-sysbinds every public function except the variadic andva_listformatting ones.
The declarations insrc/rust/mojibake-sys/src/functions.rsare generated from
utils/generate/functions.tsbymake generate- The
mojibake-rscrate addsencoding, which validates, decodes, encodes, counts, and converts
UTF-8, UTF-16LE/BE, and UTF-32LE/BE byte slices with aMalformedpolicy (stop with the byte
offset, replace with U+FFFD, or skip), andbidi, whoseParagraphresolves embedding levels
and reorders lines, splits them into runs, and renders them in visual order with mirroring - The
mojibake-rscrate addsfilterwith combinableFilterflags,is_identifierwith an
IdentifierProfile,emoji::{sequence, is_sequence, is_rgi}for UTS #51 sequences,
security::resolved_scriptsfor UTS #39 mixed-script detection, and aPropertytype that
looks up any of the library's properties by name forCharExt::has_propertyand
CharExt::property_value.CharExtalso gainsscript_extensions,is_id_start,
is_id_continue,is_pattern_syntax, andis_pattern_white_space.mojibake-sysadds the
filter, emoji sequence, emoji qualification, and script set constants, checked against C - The
mojibake-rscrate exposes the wholemjb_characterrecord:CharExt::inforeturns a
CharInfowith the general category, canonical combining class,BidiClass,Bidi_Mirrored,
DecompositionType, decimal, digit, and numeric values, and simple case mappings, andCharExt
gainscanonical_combining_class,bidi_class,is_bidi_mirrored,decomposition_type, and
simple_uppercase,simple_lowercase, andsimple_titlecase.bidi::BidiChargains a
classfield with the resolved bidi class.mojibake-sysadds the bidi class, decomposition
type, andMJB_NUMBER_NOT_VALIDconstants - The
mojibake-rscrate addsLanguageTag, which parses a BCP 47 tag strictly with
mjb_locale_parseand exposes its case-normalized language, extended language, script, region,
variant, extension, private-use, and grandfathered subtags, and the casingLocaleit selects.
It implementsFromStrandDisplay, which writes the tag in canonical case - The
mojibake-rscrate addshangul::{compose, decompose, syllable_name}and the Hangul
syllable and jamo predicates,CharExt::{is_cjk_ideograph, is_cjk_extension_ideograph}, and
grapheme_prefixandword_prefix, which return the first N graphemes or word-break segments
in one pass.idna::IdnaError::errorsis now a typedIdnaErrorsflag set instead of au32 - The
mojibake-rscrate addsPlaneandCharExt::plane, with the plane number, name,
abbreviation, and codepoint range. Planes 4 to 13 have no name.mojibake-sysadds the
MJB_PLANE_*constants, checked against C make package-rustvendors the C sources intomojibake-sysand runscargo packageand
cargo publish --dry-runfor both crates, also in CI.make update-versionsets the crates'
version.src/rust/README.mddescribes the release stepsmjb_nul_terminated_lengthreturns the byte length of a string that ends at its first NUL code
unit, in any input encoding
Changed
- The Rust example in
examples/rust/now uses the safemojibakecrate through Cargo instead of
hand-written FFI declarations, andmake -C examples example-rustmaps theFEATURE_*variables
to the crate's Cargo features.README.mddocuments the Rust crates mjb_text_makeand themjb_text_*helpers resolve aMJB_NUL_TERMINATEDlength when the text
is created, so it is scanned once. The sentinel is kept when the buffer is NULL or the encoding is
invalid, and the function that takes the text reports the errormjb_decode_nextandmjb_decode_previousreturnMJB_STATUS_INVALID_ARGUMENTfor a text whose
byte_lengthisMJB_NUL_TERMINATED, like the break iterators. They rescanned the whole string
for its terminator on every call, so iterating took quadratic time- All internal decoding uses the whole-scalar decoder of
mjb_decode_next, inlined. The streaming
DFA decoder is removed. Decoding valid text is faster: about 2.4x for UTF-8, 2x for UTF-16 and
1.4x for UTF-32 in a 2 MB mixed-script loop - Break iterators on malformed input: each maximal subpart of a malformed subsequence is one
U+FFFD with a position of its own, as inmjb_decode_next. A run of malformed bytes used to be
merged into one U+FFFD, and an incomplete sequence at the end of the text was dropped - Break iterators return
MJB_BT_NOT_SETfor an invalid encoding and for generic UTF-16 or UTF-32
text without a byte order mark, instead of iterating over replacement characters - The
stateandin_errormembers ofmjb_grapheme_break_state,mjb_word_break_state,
mjb_sentence_break_state, andmjb_line_break_stateare removed. Callers only setindex make test-wasmandnmake /F Makefile.nmake test-wasmrebuild and sync the WASM artifacts
before testing, so they no longer test a stalesrc/api/mojibake.wasm
Fixed
mjb_planegave the Supplementary Special-purpose Plane and Supplementary Private Use Area-A
the values 4 and 5. They are nowMJB_PLANE_SSP = 14andMJB_PLANE_PUA_A = 15, matching
mjb_codepoint_plane, somjb_plane_name(mjb_codepoint_plane(0xE0001), false)returns
"Supplementary Special-purpose Plane" instead of "Unassigned", and planes 4 and 5 are now
"Unassigned". This changes the values of public enum constants (an ABI change); the TypeScript
Planeenum changes the same waymjb_bidi_reorder_lineskipped UAX #9 rule L1 for lines that end inside the paragraph:
whitespace and isolate formatting characters at the end of such a line kept their resolved level
and were reordered with the text before them. In an RTL paragraph, the space of the line"abc "
of"abc def"was placed aftercinstead of at the line end. The line levels are now reset on
a private copy, andmjb_bidi_line_runsreports the same levels.mjb_bidi_line_runsalso
returnsMJB_STATUS_INVALID_ARGUMENTfor a visual-order index outside the paragraph. The
BidiTest.txt conformance test now checks every two-line split of each case- Grapheme segmentation split an emoji flag that followed another flag and a control, CR, or LF:
"🇮🇹\n🇮🇹"gave four clusters instead of three. The regional indicator count now restarts at
every codepoint that is not a regional indicator (GB12, GB13) - Grapheme segmentation joined an Extended_Pictographic to a preceding ZWJ that was followed by
Extend characters or another ZWJ, as in U+1F468 U+200D U+0308 U+1F468. GB11 requires the ZWJ to
immediately precede the Extended_Pictographic - The Windows CLI interactive mode stopped accepting input after an unpaired surrogate key event.
It decodes key events withmjb_decode_nextand skips malformed surrogates. The internal
mjb_utf16_decode_stephelper andsrc/utf16.hare removed mjb_grapheme_prefix_length,mjb_word_prefix_length, and their_for_widthvariants
estimated boundary offsets from the replacement codepoint and could cut at the wrong byte in
malformed text. They use the exact offsets of the iterator- The line break iterator now reports the LB3 mandatory break at the end of a text that holds only
a byte order mark mjb_bidi_resolvebyte offsets of multi-byte UTF-8 characters, and of the first character after a
byte order mark, are the offset of the first byte- Out-of-range and surrogate UTF-32 code units were silently dropped instead of being reported as
malformed input, so functions such asmjb_normalizeaccepted them or passed them through - A UTF-16 code unit following an unpaired high surrogate was swallowed together with the
surrogate instead of being decoded on its own