emacs-diffs
[Top][All Lists]
Advanced

[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 ()



reply via email to

[Prev in Thread] Current Thread [Next in Thread]