Skip to content

Commit ce2b3f8

Browse files
authored
Implement JSON (#25)
* Implement minimal json parser * Implement minimal json serializer * Add documentation * Update DESCRIPTION * Fix up Valgrind issues * Add complete escape sequence support * Add unicode support * Add proper escaping support * Optimization pass * Support top level objects for encoder and decoder * Support top level primitives in decoder * Review pass * Add file path test * Add JSON RFC 8259 link * More explicit raw vector parsing
1 parent 63ee632 commit ce2b3f8

File tree

19 files changed

+834
-48
lines changed

19 files changed

+834
-48
lines changed

DESCRIPTION

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
Type: Package
22
Package: secretbase
3-
Title: Cryptographic Hash, Extendable-Output and Binary Encoding Functions
3+
Title: Cryptographic Hash, Extendable-Output and Binary/Text Encoding
4+
Functions
45
Version: 1.1.1.9000
56
Authors@R: c(
67
person("Charlie", "Gao", , "charlie.gao@posit.co", role = c("aut", "cre"),
@@ -9,13 +10,14 @@ Authors@R: c(
910
comment = c(ROR = "03wc8by49")),
1011
person("Hibiki AI Limited", role = "cph")
1112
)
12-
Description: Fast and memory-efficient streaming hash functions, binary
13-
encoding and serialization. Hashes strings and raw vectors directly.
14-
Stream hashes files which can be larger than memory, as well as
15-
in-memory objects through R's serialization mechanism. Implements the
16-
SHA-256, SHA-3 and 'Keccak' cryptographic hash functions, SHAKE256
17-
extendable-output function (XOF), 'SipHash' pseudo-random function,
18-
base64 and base58 encoding, and 'CBOR' serialization.
13+
Description: Fast and memory-efficient streaming hash functions,
14+
binary/text encoding and serialization. Hashes strings and raw vectors
15+
directly. Stream hashes files which can be larger than memory, as
16+
well as in-memory objects through R's serialization mechanism.
17+
Implements the SHA-256, SHA-3 and 'Keccak' cryptographic hash
18+
functions, SHAKE256 extendable-output function (XOF), 'SipHash'
19+
pseudo-random function, base64 and base58 encoding, 'CBOR' and 'JSON'
20+
serialization.
1921
License: MIT + file LICENSE
2022
URL: https://shikokuchuo.net/secretbase/,
2123
https://github.com/shikokuchuo/secretbase/

NAMESPACE

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ export(base64dec)
66
export(base64enc)
77
export(cbordec)
88
export(cborenc)
9+
export(jsondec)
10+
export(jsonenc)
911
export(keccak)
1012
export(sha256)
1113
export(sha3)

NEWS.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# secretbase (development version)
22

3+
* Adds `jsonenc()` and `jsondec()` for a minimal JSON encoding/decoding implementation.
4+
35
# secretbase 1.1.1
46

57
* CBOR: performance optimizations; scalar values with attributes now encode as scalars rather than arrays.

R/base.R

Lines changed: 81 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# secretbase - Base64 Functions ------------------------------------------------
1+
# secretbase - Encoding and Decoding Functions ---------------------------------
22

33
#' Base64 Encode
44
#'
@@ -206,5 +206,84 @@ cborenc <- function(x) .Call(secretbase_cborenc, x)
206206
#' cbordec(cborenc(original))
207207
#'
208208
#' @export
209-
#'
210209
cbordec <- function(x) .Call(secretbase_cbordec, x)
210+
211+
#' JSON Encode
212+
#'
213+
#' Minimal JSON encoder. Converts an R object to a JSON string.
214+
#'
215+
#' This is a minimal implementation designed for creating HTTP API request
216+
#' bodies.
217+
#'
218+
#' @section Type Mappings:
219+
#' \itemize{
220+
#' \item Named list -> object `{}`
221+
#' \item Unnamed list -> array `[]`
222+
#' \item Character -> string (with escaping)
223+
#' \item Numeric/integer -> number
224+
#' \item Logical -> `true`/`false`
225+
#' \item `NULL`, `NA` -> `null`
226+
#' \item Scalars (length 1) -> primitive value
227+
#' \item Vectors (length > 1) -> array `[]`
228+
#' \item Unsupported types (e.g., functions) -> `null`
229+
#' }
230+
#'
231+
#' @param x An R object to encode as JSON.
232+
#'
233+
#' @return A character string containing the JSON representation.
234+
#'
235+
#' @seealso [jsondec()]
236+
#'
237+
#' @examples
238+
#' jsonenc(list(name = "John", age = 30L))
239+
#' jsonenc(list(valid = TRUE, count = NULL))
240+
#' jsonenc(list(nested = list(a = 1, b = list(2, 3))))
241+
#' jsonenc(list(nums = 1:3, strs = c("a", "b")))
242+
#'
243+
#' @export
244+
jsonenc <- function(x) .Call(secretbase_jsonenc, x)
245+
246+
#' JSON Decode
247+
#'
248+
#' Minimal JSON parser. Converts JSON to R objects with proper type handling.
249+
#'
250+
#' This is a minimal implementation designed for parsing HTTP API responses.
251+
#'
252+
#' @section Type Mappings:
253+
#' \itemize{
254+
#' \item Object `{}` -> named list
255+
#' \item Array `[]` -> unnamed list
256+
#' \item String -> character
257+
#' \item Number -> numeric
258+
#' \item `true`/`false` -> logical
259+
#' \item `null` -> `NULL`
260+
#' }
261+
#'
262+
#' @section RFC 8259 Non-conformance:
263+
#' \itemize{
264+
#' \item Invalid JSON returns an empty list instead of erroring.
265+
#' \item Duplicate keys are preserved; R accessors (`$`, `[[`) return first
266+
#' match.
267+
#' \item Non-standard number forms may be accepted (e.g., leading zeros,
268+
#' hexadecimal).
269+
#' \item Invalid escape sequences are output literally (e.g., `\\uZZZZ`
270+
#' becomes `"uZZZZ"`).
271+
#' \item Incomplete Unicode escape sequences for emoji are tolerated.
272+
#' \item Nesting depth is limited to 512 levels.
273+
#' }
274+
#'
275+
#' @param x Character string or raw vector containing JSON data.
276+
#'
277+
#' @return The corresponding R object, or an empty list for invalid input.
278+
#'
279+
#' @seealso [jsonenc()]
280+
#'
281+
#' @examples
282+
#' jsondec('{"name": "John", "age": 30}')
283+
#' jsondec('[1, 2, 3]')
284+
#' jsondec('"a string"')
285+
#' jsondec('123')
286+
#' jsondec('true')
287+
#'
288+
#' @export
289+
jsondec <- function(x) .Call(secretbase_jsondec, x)

README.Rmd

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,11 @@ knitr::opts_chunk$set(
3232

3333
[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/shikokuchuo/secretbase)
3434

35-
Fast and memory-efficient streaming hash functions, binary encoding and serialization.
35+
Fast and memory-efficient streaming hash functions, binary/text encoding and serialization.
3636

3737
Hashes strings and raw vectors directly. Stream hashes files which can be larger than memory, as well as in-memory objects through R's serialization mechanism.
3838

39-
Implements the SHA-256, SHA-3 and 'Keccak' cryptographic hash functions, SHAKE256 extendable-output function (XOF), 'SipHash' pseudo-random function, base64 and base58 encoding, and 'CBOR' serialization.
39+
Implements the SHA-256, SHA-3 and 'Keccak' cryptographic hash functions, SHAKE256 extendable-output function (XOF), 'SipHash' pseudo-random function, base64 and base58 encoding, ‘CBOR’ and 'JSON' serialization.
4040

4141
| Function | Purpose |
4242
|----------|---------|
@@ -46,6 +46,7 @@ Implements the SHA-256, SHA-3 and 'Keccak' cryptographic hash functions, SHAKE25
4646
| `base64enc()` `base64dec()` | Base64 encoding |
4747
| `base58enc()` `base58dec()` | Base58 encoding with checksum |
4848
| `cborenc()` `cbordec()` | CBOR serialization |
49+
| `jsonenc()` `jsondec()` | JSON serialization |
4950

5051
### Installation
5152

@@ -175,6 +176,15 @@ cborenc(list(a = 1L, b = "hello", c = TRUE))
175176
cbordec(cborenc(list(a = 1L, b = "hello", c = TRUE)))
176177
```
177178

179+
#### JSON
180+
181+
Minimal JSON encoder/decoder for HTTP API request/response bodies:
182+
183+
```{r}
184+
jsonenc(list(name = "John", age = 30L, active = TRUE))
185+
jsondec('{"name": "John", "age": 30, "active": true}')
186+
```
187+
178188
### Implementation
179189

180190
The SHA-3 Secure Hash Standard was published by the National Institute of Standards and Technology (NIST) in 2015 at [doi:10.6028/NIST.FIPS.202](https://dx.doi.org/10.6028/NIST.FIPS.202). SHA-3 is based on the Keccak algorithm, designed by G. Bertoni, J. Daemen, M. Peeters and G. Van Assche.
@@ -191,6 +201,8 @@ The base58 implementation is based on 'libbase58' by Luke Dashjr at <https://git
191201

192202
The CBOR implementation follows RFC 8949, *"Concise Binary Object Representation (CBOR)"*, available at <https://www.rfc-editor.org/rfc/rfc8949>.
193203

204+
The JSON implementation is not fully compliant with RFC 8259, *"The JavaScript Object Notation (JSON) Data Interchange Format"*, available at <https://www.rfc-editor.org/rfc/rfc8259>.
205+
194206
### References
195207

196208
[1] Pierre L’Ecuyer, David Munger, Boris Oreshkin and Richard Simard (2017), *"Random numbers for parallel computers: Requirements and methods, with emphasis on GPUs"*, Mathematics and Computers in Simulation, Vol. 135, May 2017, pp. 3-17 [doi:10.1016/j.matcom.2016.05.00](https://doi.org/10.1016/j.matcom.2016.05.005).
@@ -205,7 +217,8 @@ Mbed TLS website: <https://www.trustedfirmware.org/projects/mbed-tls><br />
205217
SipHash streaming implementation: <https://github.com/c-util/c-siphash><br />
206218
SipHash reference implementation: <https://github.com/veorq/SipHash><br />
207219
libbase58: <https://github.com/luke-jr/libbase58><br />
208-
CBOR RFC 8949: <https://www.rfc-editor.org/rfc/rfc8949>
220+
CBOR RFC 8949: <https://www.rfc-editor.org/rfc/rfc8949><br />
221+
JSON RFC 8259: <https://www.rfc-editor.org/rfc/rfc8259>
209222

210223
--
211224

README.md

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,16 @@ coverage](https://codecov.io/gh/shikokuchuo/secretbase/graph/badge.svg)](https:/
2323
[![Ask
2424
DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/shikokuchuo/secretbase)
2525

26-
Fast and memory-efficient streaming hash functions, binary encoding and
27-
serialization.
26+
Fast and memory-efficient streaming hash functions, binary/text encoding
27+
and serialization.
2828

2929
Hashes strings and raw vectors directly. Stream hashes files which can
3030
be larger than memory, as well as in-memory objects through R’s
3131
serialization mechanism.
3232

3333
Implements the SHA-256, SHA-3 and ‘Keccak’ cryptographic hash functions,
3434
SHAKE256 extendable-output function (XOF), ‘SipHash’ pseudo-random
35-
function, base64 and base58 encoding, and ‘CBOR’ serialization.
35+
function, base64 and base58 encoding, ‘CBOR’ and ‘JSON’ serialization.
3636

3737
| Function | Purpose |
3838
|--------------------------------|------------------------------------|
@@ -42,6 +42,7 @@ function, base64 and base58 encoding, and ‘CBOR’ serialization.
4242
| `base64enc()` `base64dec()` | Base64 encoding |
4343
| `base58enc()` `base58dec()` | Base58 encoding with checksum |
4444
| `cborenc()` `cbordec()` | CBOR serialization |
45+
| `jsonenc()` `jsondec()` | JSON serialization |
4546

4647
### Installation
4748

@@ -203,6 +204,24 @@ cbordec(cborenc(list(a = 1L, b = "hello", c = TRUE)))
203204
#> [1] TRUE
204205
```
205206

207+
#### JSON
208+
209+
Minimal JSON encoder/decoder for HTTP API request/response bodies:
210+
211+
``` r
212+
jsonenc(list(name = "John", age = 30L, active = TRUE))
213+
#> [1] "{\"name\":\"John\",\"age\":30,\"active\":true}"
214+
jsondec('{"name": "John", "age": 30, "active": true}')
215+
#> $name
216+
#> [1] "John"
217+
#>
218+
#> $age
219+
#> [1] 30
220+
#>
221+
#> $active
222+
#> [1] TRUE
223+
```
224+
206225
### Implementation
207226

208227
The SHA-3 Secure Hash Standard was published by the National Institute
@@ -235,6 +254,10 @@ The CBOR implementation follows RFC 8949, *“Concise Binary Object
235254
Representation (CBOR)”*, available at
236255
<https://www.rfc-editor.org/rfc/rfc8949>.
237256

257+
The JSON implementation is not fully compliant with RFC 8259, *“The
258+
JavaScript Object Notation (JSON) Data Interchange Format”*, available
259+
at <https://www.rfc-editor.org/rfc/rfc8259>.
260+
238261
### References
239262

240263
\[1\] Pierre L’Ecuyer, David Munger, Boris Oreshkin and Richard Simard
@@ -257,7 +280,8 @@ streaming implementation: <https://github.com/c-util/c-siphash><br />
257280
SipHash reference implementation:
258281
<https://github.com/veorq/SipHash><br /> libbase58:
259282
<https://github.com/luke-jr/libbase58><br /> CBOR RFC 8949:
260-
<https://www.rfc-editor.org/rfc/rfc8949>
283+
<https://www.rfc-editor.org/rfc/rfc8949><br /> JSON RFC 8259:
284+
<https://www.rfc-editor.org/rfc/rfc8259>
261285

262286
263287

man/jsondec.Rd

Lines changed: 58 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/jsonenc.Rd

Lines changed: 46 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/secretbase-package.Rd

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
File renamed without changes.

0 commit comments

Comments
 (0)