From 16d738e2c53dd0e3b4573bb978237119f79eab9d Mon Sep 17 00:00:00 2001 From: =?utf8?q?Mattias=20Engdeg=C3=A5rd?= Date: Sun, 8 Sep 2024 20:02:34 +0200 Subject: [PATCH] Make json-serialize always return a unibyte string (bug#70007) The JSON format is defined as a byte sequence and will always be used as such, so returning a multibyte string makes little sense. * src/json.c (json_out_to_string): Remove. (Fjson_serialize): Return unibyte string. * test/src/json-tests.el (json-serialize/roundtrip) (json-serialize/roundtrip-scalars, json-serialize/string): Update tests. * doc/lispref/text.texi (Parsing JSON): Document. * etc/NEWS: Announce. (cherry picked from commit e55e2e1c6baebbd105f930fa553ec65c74a3000d) --- doc/lispref/text.texi | 2 +- src/json.c | 14 ++---------- test/src/json-tests.el | 50 ++++++++++++++++++++++-------------------- 3 files changed, 29 insertions(+), 37 deletions(-) diff --git a/doc/lispref/text.texi b/doc/lispref/text.texi index 03b2c3b2b6d..a2a429e1882 100644 --- a/doc/lispref/text.texi +++ b/doc/lispref/text.texi @@ -5852,7 +5852,7 @@ can be serialized to JSON@. Likewise, the parsing functions will return any of the possible types described above. @defun json-serialize object &rest args -This function returns a new Lisp string which contains the JSON +This function returns a new Lisp unibyte string which contains the JSON representation of @var{object}. The argument @var{args} is a list of keyword/argument pairs. The following keywords are accepted: diff --git a/src/json.c b/src/json.c index 21066d21328..41566f8369b 100644 --- a/src/json.c +++ b/src/json.c @@ -559,16 +559,6 @@ json_out_something (json_out_t *jo, Lisp_Object obj) wrong_type_argument (Qjson_value_p, obj); } -static Lisp_Object -json_out_to_string (json_out_t *jo) -{ - /* FIXME: should this be a unibyte or multibyte string? - Right now we make a multibyte string for test compatibility, - but we are really encoding so unibyte would make more sense. */ - ptrdiff_t nchars = jo->size - jo->chars_delta; - return make_multibyte_string (jo->buf, nchars, jo->size); -} - static void json_serialize (json_out_t *jo, Lisp_Object object, ptrdiff_t nargs, Lisp_Object *args) @@ -596,7 +586,7 @@ json_serialize (json_out_t *jo, Lisp_Object object, DEFUN ("json-serialize", Fjson_serialize, Sjson_serialize, 1, MANY, NULL, - doc: /* Return the JSON representation of OBJECT as a string. + doc: /* Return the JSON representation of OBJECT as a unibyte string. OBJECT is translated as follows: @@ -629,7 +619,7 @@ usage: (json-serialize OBJECT &rest ARGS) */) specpdl_ref count = SPECPDL_INDEX (); json_out_t jo; json_serialize (&jo, args[0], nargs - 1, args + 1); - return unbind_to (count, json_out_to_string (&jo)); + return unbind_to (count, make_unibyte_string (jo.buf, jo.size)); } DEFUN ("json-insert", Fjson_insert, Sjson_insert, 1, MANY, diff --git a/test/src/json-tests.el b/test/src/json-tests.el index ebac70fb1c7..1d7491a4593 100644 --- a/test/src/json-tests.el +++ b/test/src/json-tests.el @@ -36,7 +36,7 @@ (json "[null,false,true,0,123,-456,3.75,\"abc\uFFFFαβγ𝔸𝐁𝖢\\\"\\\\\"]") (json-bytes (encode-coding-string json 'utf-8))) - (should (equal (json-serialize lisp) json)) ; or `json-bytes'? + (should (equal (json-serialize lisp) json-bytes)) (with-temp-buffer ;; multibyte buffer (json-insert lisp) @@ -82,28 +82,29 @@ "\"abc\uFFFFαβγ𝔸𝐁𝖢\\\"\\\\\""))) (cl-destructuring-bind (lisp json) case (ert-info ((format "%S ↔ %S" lisp json)) - (should (equal (json-serialize lisp) json)) - (with-temp-buffer - (json-insert lisp) - (should (equal (buffer-string) json)) - (should (eobp))) - (with-temp-buffer - (set-buffer-multibyte nil) - (json-insert lisp) - (should (equal (buffer-string) (encode-coding-string json 'utf-8))) - (should (eobp))) - (should (equal (json-parse-string json) lisp)) - (with-temp-buffer - (insert json) - (goto-char 1) - (should (equal (json-parse-buffer) lisp)) - (should (eobp))) - (with-temp-buffer - (set-buffer-multibyte nil) - (insert (encode-coding-string json 'utf-8)) - (goto-char 1) - (should (equal (json-parse-buffer) lisp)) - (should (eobp))))))) + (let ((json-bytes (encode-coding-string json 'utf-8))) + (should (equal (json-serialize lisp) json-bytes)) + (with-temp-buffer + (json-insert lisp) + (should (equal (buffer-string) json)) + (should (eobp))) + (with-temp-buffer + (set-buffer-multibyte nil) + (json-insert lisp) + (should (equal (buffer-string) (encode-coding-string json 'utf-8))) + (should (eobp))) + (should (equal (json-parse-string json) lisp)) + (with-temp-buffer + (insert json) + (goto-char 1) + (should (equal (json-parse-buffer) lisp)) + (should (eobp))) + (with-temp-buffer + (set-buffer-multibyte nil) + (insert (encode-coding-string json 'utf-8)) + (goto-char 1) + (should (equal (json-parse-buffer) lisp)) + (should (eobp)))))))) (ert-deftest json-serialize/object () (let ((table (make-hash-table :test #'equal))) @@ -226,7 +227,8 @@ (should (equal (json-serialize ["foo"]) "[\"foo\"]")) (should (equal (json-serialize ["a\n\fb"]) "[\"a\\n\\fb\"]")) (should (equal (json-serialize ["\nasdфыв\u001f\u007ffgh\t"]) - "[\"\\nasdфыв\\u001F\u007ffgh\\t\"]")) + (encode-coding-string "[\"\\nasdфыв\\u001F\u007ffgh\\t\"]" + 'utf-8))) (should (equal (json-serialize ["a\0b"]) "[\"a\\u0000b\"]")) (should-error (json-serialize ["\xC3\x84"])) (should-error (json-serialize ["\u00C4\xC3\x84"]))) -- 2.39.2