[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
master 617debf6739 2/2: Fix json-insert unibyte buffer bug (bug#70007)
From: |
Mattias Engdegård |
Subject: |
master 617debf6739 2/2: Fix json-insert unibyte buffer bug (bug#70007) |
Date: |
Tue, 2 Apr 2024 13:17:01 -0400 (EDT) |
branch: master
commit 617debf67392946b4b42fdf364c69da6f094a840
Author: Mattias Engdegård <mattiase@acm.org>
Commit: Mattias Engdegård <mattiase@acm.org>
Fix json-insert unibyte buffer bug (bug#70007)
Previously, a unibyte target buffer could be put in an incorrect state
if json-insert was used to insert non-ASCII characters.
* src/json.c (Fjson_insert): Simplify. Don't attempt to decode the data
being inserted: it is guaranteed to be correct UTF-8 and is correct for
both unibyte and multibyte buffers.
* test/src/json-tests.el (json-serialize/roundtrip)
(json-serialize/roundtrip-scalars): Extend tests.
---
src/json.c | 50 +++++++++++---------------------------------------
test/src/json-tests.el | 43 +++++++++++++++++++++++++++++++++++--------
2 files changed, 46 insertions(+), 47 deletions(-)
diff --git a/src/json.c b/src/json.c
index 0b4414956ee..45dcdde98ea 100644
--- a/src/json.c
+++ b/src/json.c
@@ -646,8 +646,6 @@ usage: (json-insert OBJECT &rest ARGS) */)
json_out_t jo;
json_serialize (&jo, args[0], nargs - 1, args + 1);
- /* FIXME: All the work below just to insert a string into a buffer? */
-
prepare_to_modify_buffer (PT, PT, NULL);
move_gap_both (PT, PT_BYTE);
if (GAP_SIZE < jo.size)
@@ -657,48 +655,22 @@ usage: (json-insert OBJECT &rest ARGS) */)
/* No need to keep allocation beyond this point. */
unbind_to (count, Qnil);
- ptrdiff_t inserted = 0;
+ bool ub_buffer = NILP (BVAR (current_buffer, enable_multibyte_characters));
ptrdiff_t inserted_bytes = jo.size;
+ ptrdiff_t inserted = ub_buffer ? jo.size : jo.size - jo.chars_delta;
+ eassert (inserted > 0);
- /* If required, decode the stuff we've read into the gap. */
- struct coding_system coding;
- /* JSON strings are UTF-8 encoded strings. */
- setup_coding_system (Qutf_8_unix, &coding);
- coding.dst_multibyte = !NILP (BVAR (current_buffer,
- enable_multibyte_characters));
- if (CODING_MAY_REQUIRE_DECODING (&coding))
- {
- /* Now we have all the new bytes at the beginning of the gap,
- but `decode_coding_gap` needs them at the end of the gap, so
- we need to move them. */
- memmove (GAP_END_ADDR - inserted_bytes, GPT_ADDR, inserted_bytes);
- decode_coding_gap (&coding, inserted_bytes);
- inserted = coding.produced_char;
- }
- else
- {
- /* Make the inserted text part of the buffer, as unibyte text. */
- eassert (NILP (BVAR (current_buffer, enable_multibyte_characters)));
- insert_from_gap_1 (inserted_bytes, inserted_bytes, false);
-
- /* The target buffer is unibyte, so we don't need to decode. */
- invalidate_buffer_caches (current_buffer,
- PT, PT + inserted_bytes);
- adjust_after_insert (PT, PT_BYTE,
- PT + inserted_bytes,
- PT_BYTE + inserted_bytes,
- inserted_bytes);
- inserted = inserted_bytes;
- }
+ insert_from_gap_1 (inserted, inserted_bytes, false);
+ invalidate_buffer_caches (current_buffer, PT, PT + inserted);
+ adjust_after_insert (PT, PT_BYTE, PT + inserted, PT_BYTE + inserted_bytes,
+ inserted);
/* Call after-change hooks. */
signal_after_change (PT, 0, inserted);
- if (inserted > 0)
- {
- update_compositions (PT, PT, CHECK_BORDER);
- /* Move point to after the inserted text. */
- SET_PT_BOTH (PT + inserted, PT_BYTE + inserted_bytes);
- }
+
+ update_compositions (PT, PT, CHECK_BORDER);
+ /* Move point to after the inserted text. */
+ SET_PT_BOTH (PT + inserted, PT_BYTE + inserted_bytes);
return Qnil;
}
diff --git a/test/src/json-tests.el b/test/src/json-tests.el
index 8b730ef8c90..ebac70fb1c7 100644
--- a/test/src/json-tests.el
+++ b/test/src/json-tests.el
@@ -27,28 +27,44 @@
(require 'map)
(require 'subr-x)
-(declare-function json-serialize "json.c" (object &rest args))
-(declare-function json-insert "json.c" (object &rest args))
-(declare-function json-parse-string "json.c" (string &rest args))
-(declare-function json-parse-buffer "json.c" (&rest args))
-
(define-error 'json-tests--error "JSON test error")
(ert-deftest json-serialize/roundtrip ()
;; The noncharacter U+FFFF should be passed through,
;; cf. https://www.unicode.org/faq/private_use.html#noncharacters.
- (let ((lisp [:null :false t 0 123 -456 3.75 "abc\uFFFFαβγ𝔸𝐁𝖢\"\\"])
- (json "[null,false,true,0,123,-456,3.75,\"abc\uFFFFαβγ𝔸𝐁𝖢\\\"\\\\\"]"))
- (should (equal (json-serialize lisp) json))
+ (let* ((lisp [:null :false t 0 123 -456 3.75 "abc\uFFFFαβγ𝔸𝐁𝖢\"\\"])
+ (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'?
(with-temp-buffer
+ ;; multibyte buffer
(json-insert lisp)
(should (equal (buffer-string) json))
+ (should (equal (point) (1+ (length json))))
+ (should (eobp)))
+ (with-temp-buffer
+ ;; unibyte buffer
+ (set-buffer-multibyte nil)
+ (json-insert lisp)
+ (should (equal (buffer-string) json-bytes))
+ (should (equal (point) (1+ (length json-bytes))))
(should (eobp)))
(should (equal (json-parse-string json) lisp))
(with-temp-buffer
+ ;; multibyte buffer
(insert json)
(goto-char 1)
(should (equal (json-parse-buffer) lisp))
+ (should (equal (point) (1+ (length json))))
+ (should (eobp)))
+ (with-temp-buffer
+ ;; unibyte buffer
+ (set-buffer-multibyte nil)
+ (insert json-bytes)
+ (goto-char 1)
+ (should (equal (json-parse-buffer) lisp))
+ (should (equal (point) (1+ (length json-bytes))))
(should (eobp)))))
(ert-deftest json-serialize/roundtrip-scalars ()
@@ -71,11 +87,22 @@
(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 ()