NAME mb::JSON - JSON encode/decode for multibyte (UTF-8) strings SYNOPSIS use mb::JSON; # decode: JSON text -> Perl data my $data = mb::JSON::decode('{"name":"Alice","age":30,"active":true}'); print $data->{name}; # Alice print $data->{age}; # 30 print $data->{active}; # true (mb::JSON::Boolean object) # parse: alias for decode() -- both names are interchangeable my $data = mb::JSON::parse('{"key":"value"}'); # encode: Perl data -> JSON text my $json = mb::JSON::encode({ name => 'Alice', active => mb::JSON::true, score => undef, }); # -> {"active":true,"name":"Alice","score":null} # stringify: alias for encode() -- both names are interchangeable my $json = mb::JSON::stringify({ name => 'Alice', active => mb::JSON::true, score => undef, }); # -> {"active":true,"name":"Alice","score":null} # Boolean values my $json = mb::JSON::encode({ flag => mb::JSON::true, done => mb::JSON::false, }); # -> {"done":false,"flag":true} DESCRIPTION mb::JSON is a simple, dependency-free JSON encoder and decoder designed for Perl 5.005_03 and later. It handles UTF-8 multibyte strings correctly, making it suitable for environments where standard JSON modules requiring Perl 5.8+ are unavailable. mb::JSON provides two pairs of symmetric functions: decode() / parse() -- JSON text -> Perl data encode() / stringify() -- Perl data -> JSON text Within each pair, both names are aliases and produce identical output. parse() mirrors decode(), stringify() mirrors encode(). FUNCTIONS mb::JSON::decode($json_text) Converts a JSON text string to a Perl data structure. If no argument is given, $_ is used. mb::JSON::parse($json_text) Alias for decode(). Both names are interchangeable. mb::JSON::encode($data) Converts a Perl data structure to a JSON text string. Hash keys are sorted alphabetically for deterministic output. UTF-8 multibyte bytes are output as-is (not \uXXXX-escaped). If called with no argument at all, $_ is used; encode(undef) still returns null. mb::JSON::stringify($data) Alias for encode(). Both names are interchangeable. Mirrors the JSON.stringify() function in JavaScript. mb::JSON::true Returns the mb::JSON::Boolean object representing JSON true. Numifies to 1, stringifies to "true". mb::JSON::false Returns the mb::JSON::Boolean object representing JSON false. Numifies to 0, stringifies to "false". ENCODING RULES undef -> null mb::JSON::true -> true mb::JSON::false -> false number-like scalar -> number (no quotes) other scalar -> "string" (UTF-8 bytes kept as-is) ARRAY reference -> [...] HASH reference -> {...} (keys sorted alphabetically) DECODING RULES null -> undef true -> mb::JSON::Boolean (numifies to 1) false -> mb::JSON::Boolean (numifies to 0) number -> Perl number string -> Perl string (\uXXXX converted to UTF-8; UTF-16 surrogate pairs combined into 4-byte UTF-8 for code points > U+FFFF) object -> hash reference (a repeated key keeps the last value) array -> array reference A leading UTF-8 byte order mark (EF BB BF) is skipped before parsing. Whitespace between tokens is space, tab, LF and CR -- exactly the set RFC 8259 defines. Form feed and vertical tab are not whitespace. The set is spelled out rather than written as perl's \s so that it is the same on every supported perl. CONFIGURATION $mb::JSON::MAX_DEPTH (default 512) Maximum nesting depth accepted by decode() and produced by encode(). Deeper input or data is rejected with an error rather than exhausting the Perl stack. A false value disables the check. The limit counts objects and arrays, not values, and both directions stop at the same count, so anything decode() accepts can be handed straight back to encode(). $mb::JSON::STRICT (default 0) When false, decode() copies string bytes through unchanged: raw control characters are accepted and UTF-8 is not validated. When true, decode() rejects a raw control character U+0000-U+001F inside a string and rejects a string whose bytes are not well-formed UTF-8. Both are ordinary package variables, so local() works: local $mb::JSON::MAX_DEPTH = 64; local $mb::JSON::STRICT = 1; my $data = mb::JSON::decode($untrusted); BOOLEAN VALUES Perl has no native boolean type. mb::JSON provides two singleton objects for unambiguous boolean encoding: mb::JSON::true -- stringifies as "true", numifies as 1 mb::JSON::false -- stringifies as "false", numifies as 0 A plain 1 or 0 encodes as a JSON number, not a boolean: encode({ count => 1 }) -> '{"count":1}' encode({ flag => mb::JSON::true }) -> '{"flag":true}' INCLUDED DOCUMENTATION The doc/ directory contains JSON cheat sheets in 21 languages for use as quick reference materials. INSTALLATION To install this module type the following: perl Makefile.PL make make test make install Or using pmake.bat (Windows): pmake.bat test pmake.bat install COMPATIBILITY This module works with Perl 5.005_03 and later. WHY PERL 5.005_03 SPECIFICATION? This module adheres to the Perl 5.005_03 specification--not because we use the old interpreter, but because this specification represents the simple, original Perl programming model that makes programming enjoyable. THE STRENGTH OF MODERN TIMES Some people think the strength of modern times is the ability to use modern technology. That thinking is insufficient. The strength of modern times is the ability to use ALL technology up to the present day. By adhering to the Perl 5.005_03 specification, we gain access to the entire history of Perl--from 5.005_03 to 5.42 and beyond--rather than limiting ourselves to only the latest versions. Key reasons: - Simplicity: Original Perl approach keeps programming "raku" (easy/fun) - JPerl: Final version of JPerl (Japanese Perl) - Universal: Runs on ALL Perl versions (5.005_03 through 5.42+) - Philosophy: Programming should be enjoyable (Camel Book readers know!) Perl 5.6+ introduced character encoding complexity that made programming harder. By following the 5.005_03 specification, we maintain the joy of Perl programming. TARGET USE CASES - Processing JSON data with UTF-8 multibyte strings - Environments where JSON::PP or JSON::XS cannot be installed - Legacy Perl environments (5.005_03 and later) - Lightweight scripts and utilities with no external dependencies LIMITATIONS - Numbers are not distinguished from strings if the value matches the number pattern, so the string "30" is encoded as the number 30. Leading-zero strings such as "007" stay strings. - Numbers pass through Perl's own numeric conversion, so 1.0 and 1e2 are re-encoded as 1 and 100, and an integer wider than the platform's floating point mantissa loses precision. - A number literal outside the range of this perl's floating point type is rejected by decode()/parse() rather than silently converted: it would otherwise become Inf at one end, or 0 after losing every significant digit it carried at the other. Where the range ends depends on how perl was built -- an ordinary double runs out around 1e308, so 1e400 and 1e-400 are rejected there, while a perl built -Duselongdouble or -Dusequadmath accepts both. A literal that is genuinely zero, including 0e-400, is unaffected on every build. - References other than ARRAY and HASH are stringified rather than raising an error. A blessed hash or array reference is stringified too, because ref() returns the class name. - Inf and NaN have no JSON representation and are rejected by encode()/stringify(). They are recognized by how perl prints them, so a string spelling exactly "Inf", "-Inf", "Infinity", "NaN" or one of the "1.#INF" forms is rejected too. Longer words such as "Info" and "nano" are unaffected. - By default the decoder does not validate UTF-8 and accepts raw control characters inside strings. Set $mb::JSON::STRICT to enable those checks. AUTHOR INABA Hitoshi COPYRIGHT AND LICENSE Copyright (c) 2021, 2022, 2026 INABA Hitoshi This software is free software; you can redistribute it and/or modify it under the same terms as Perl itself.