aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMattias Engdegård2024-09-08 20:02:34 +0200
committerMattias Engdegård2024-09-08 20:02:34 +0200
commite55e2e1c6baebbd105f930fa553ec65c74a3000d (patch)
treec171c29f7bcfb8a4a52e74e641506aaf9a2b960d
parent89c99891b2b3ab087cd7e824cef391ef26800ab4 (diff)
downloademacs-e55e2e1c6baebbd105f930fa553ec65c74a3000d.tar.gz
emacs-e55e2e1c6baebbd105f930fa553ec65c74a3000d.zip
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.
-rw-r--r--doc/lispref/text.texi2
-rw-r--r--etc/NEWS7
-rw-r--r--src/json.c14
-rw-r--r--test/src/json-tests.el50
4 files changed, 36 insertions, 37 deletions
diff --git a/doc/lispref/text.texi b/doc/lispref/text.texi
index 278b53d7f65..df56433fd18 100644
--- a/doc/lispref/text.texi
+++ b/doc/lispref/text.texi
@@ -5844,7 +5844,7 @@ can be serialized to JSON@. Likewise, the parsing functions will
5844return any of the possible types described above. 5844return any of the possible types described above.
5845 5845
5846@defun json-serialize object &rest args 5846@defun json-serialize object &rest args
5847This function returns a new Lisp string which contains the JSON 5847This function returns a new Lisp unibyte string which contains the JSON
5848representation of @var{object}. The argument @var{args} is a list of 5848representation of @var{object}. The argument @var{args} is a list of
5849keyword/argument pairs. The following keywords are accepted: 5849keyword/argument pairs. The following keywords are accepted:
5850 5850
diff --git a/etc/NEWS b/etc/NEWS
index a61bdc4a7f3..239182427bb 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -3071,6 +3071,13 @@ entire SQL file.
3071 3071
3072** JSON 3072** JSON
3073 3073
3074+++
3075*** 'json-serialize' now always returns a unibyte string.
3076This is appropriate since it is an encoding operation. In the unlikely
3077event that a multibyte string is needed, the result can be decoded using
3078
3079 (decode-coding-string RESULT 'utf-8)
3080
3074--- 3081---
3075*** The parser keeps duplicated object keys in alist and plist output. 3082*** The parser keeps duplicated object keys in alist and plist output.
3076A JSON object such as '{"a":1,"a":2}' will now be translated into the 3083A JSON object such as '{"a":1,"a":2}' will now be translated into the
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)
559 wrong_type_argument (Qjson_value_p, obj); 559 wrong_type_argument (Qjson_value_p, obj);
560} 560}
561 561
562static Lisp_Object
563json_out_to_string (json_out_t *jo)
564{
565 /* FIXME: should this be a unibyte or multibyte string?
566 Right now we make a multibyte string for test compatibility,
567 but we are really encoding so unibyte would make more sense. */
568 ptrdiff_t nchars = jo->size - jo->chars_delta;
569 return make_multibyte_string (jo->buf, nchars, jo->size);
570}
571
572static void 562static void
573json_serialize (json_out_t *jo, Lisp_Object object, 563json_serialize (json_out_t *jo, Lisp_Object object,
574 ptrdiff_t nargs, Lisp_Object *args) 564 ptrdiff_t nargs, Lisp_Object *args)
@@ -596,7 +586,7 @@ json_serialize (json_out_t *jo, Lisp_Object object,
596 586
597DEFUN ("json-serialize", Fjson_serialize, Sjson_serialize, 1, MANY, 587DEFUN ("json-serialize", Fjson_serialize, Sjson_serialize, 1, MANY,
598 NULL, 588 NULL,
599 doc: /* Return the JSON representation of OBJECT as a string. 589 doc: /* Return the JSON representation of OBJECT as a unibyte string.
600 590
601OBJECT is translated as follows: 591OBJECT is translated as follows:
602 592
@@ -629,7 +619,7 @@ usage: (json-serialize OBJECT &rest ARGS) */)
629 specpdl_ref count = SPECPDL_INDEX (); 619 specpdl_ref count = SPECPDL_INDEX ();
630 json_out_t jo; 620 json_out_t jo;
631 json_serialize (&jo, args[0], nargs - 1, args + 1); 621 json_serialize (&jo, args[0], nargs - 1, args + 1);
632 return unbind_to (count, json_out_to_string (&jo)); 622 return unbind_to (count, make_unibyte_string (jo.buf, jo.size));
633} 623}
634 624
635DEFUN ("json-insert", Fjson_insert, Sjson_insert, 1, MANY, 625DEFUN ("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 @@
36 (json 36 (json
37 "[null,false,true,0,123,-456,3.75,\"abc\uFFFFαβγ𝔸𝐁𝖢\\\"\\\\\"]") 37 "[null,false,true,0,123,-456,3.75,\"abc\uFFFFαβγ𝔸𝐁𝖢\\\"\\\\\"]")
38 (json-bytes (encode-coding-string json 'utf-8))) 38 (json-bytes (encode-coding-string json 'utf-8)))
39 (should (equal (json-serialize lisp) json)) ; or `json-bytes'? 39 (should (equal (json-serialize lisp) json-bytes))
40 (with-temp-buffer 40 (with-temp-buffer
41 ;; multibyte buffer 41 ;; multibyte buffer
42 (json-insert lisp) 42 (json-insert lisp)
@@ -82,28 +82,29 @@
82 "\"abc\uFFFFαβγ𝔸𝐁𝖢\\\"\\\\\""))) 82 "\"abc\uFFFFαβγ𝔸𝐁𝖢\\\"\\\\\"")))
83 (cl-destructuring-bind (lisp json) case 83 (cl-destructuring-bind (lisp json) case
84 (ert-info ((format "%S ↔ %S" lisp json)) 84 (ert-info ((format "%S ↔ %S" lisp json))
85 (should (equal (json-serialize lisp) json)) 85 (let ((json-bytes (encode-coding-string json 'utf-8)))
86 (with-temp-buffer 86 (should (equal (json-serialize lisp) json-bytes))
87 (json-insert lisp) 87 (with-temp-buffer
88 (should (equal (buffer-string) json)) 88 (json-insert lisp)
89 (should (eobp))) 89 (should (equal (buffer-string) json))
90 (with-temp-buffer 90 (should (eobp)))
91 (set-buffer-multibyte nil) 91 (with-temp-buffer
92 (json-insert lisp) 92 (set-buffer-multibyte nil)
93 (should (equal (buffer-string) (encode-coding-string json 'utf-8))) 93 (json-insert lisp)
94 (should (eobp))) 94 (should (equal (buffer-string) (encode-coding-string json 'utf-8)))
95 (should (equal (json-parse-string json) lisp)) 95 (should (eobp)))
96 (with-temp-buffer 96 (should (equal (json-parse-string json) lisp))
97 (insert json) 97 (with-temp-buffer
98 (goto-char 1) 98 (insert json)
99 (should (equal (json-parse-buffer) lisp)) 99 (goto-char 1)
100 (should (eobp))) 100 (should (equal (json-parse-buffer) lisp))
101 (with-temp-buffer 101 (should (eobp)))
102 (set-buffer-multibyte nil) 102 (with-temp-buffer
103 (insert (encode-coding-string json 'utf-8)) 103 (set-buffer-multibyte nil)
104 (goto-char 1) 104 (insert (encode-coding-string json 'utf-8))
105 (should (equal (json-parse-buffer) lisp)) 105 (goto-char 1)
106 (should (eobp))))))) 106 (should (equal (json-parse-buffer) lisp))
107 (should (eobp))))))))
107 108
108(ert-deftest json-serialize/object () 109(ert-deftest json-serialize/object ()
109 (let ((table (make-hash-table :test #'equal))) 110 (let ((table (make-hash-table :test #'equal)))
@@ -226,7 +227,8 @@
226 (should (equal (json-serialize ["foo"]) "[\"foo\"]")) 227 (should (equal (json-serialize ["foo"]) "[\"foo\"]"))
227 (should (equal (json-serialize ["a\n\fb"]) "[\"a\\n\\fb\"]")) 228 (should (equal (json-serialize ["a\n\fb"]) "[\"a\\n\\fb\"]"))
228 (should (equal (json-serialize ["\nasdфыв\u001f\u007ffgh\t"]) 229 (should (equal (json-serialize ["\nasdфыв\u001f\u007ffgh\t"])
229 "[\"\\nasdфыв\\u001F\u007ffgh\\t\"]")) 230 (encode-coding-string "[\"\\nasdфыв\\u001F\u007ffgh\\t\"]"
231 'utf-8)))
230 (should (equal (json-serialize ["a\0b"]) "[\"a\\u0000b\"]")) 232 (should (equal (json-serialize ["a\0b"]) "[\"a\\u0000b\"]"))
231 (should-error (json-serialize ["\xC3\x84"])) 233 (should-error (json-serialize ["\xC3\x84"]))
232 (should-error (json-serialize ["\u00C4\xC3\x84"]))) 234 (should-error (json-serialize ["\u00C4\xC3\x84"])))