X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/41306318777a942420bc4feadbfacf662ea179dc..76f2d766ad6691eae6ae4006264f59724cc73a23:/lisp/json.el diff --git a/lisp/json.el b/lisp/json.el index aaa7bb0c49..eaf8596a6d 100644 --- a/lisp/json.el +++ b/lisp/json.el @@ -1,6 +1,6 @@ ;;; json.el --- JavaScript Object Notation parser / generator -;; Copyright (C) 2006-2013 Free Software Foundation, Inc. +;; Copyright (C) 2006-2015 Free Software Foundation, Inc. ;; Author: Edward O'Connor ;; Version: 1.4 @@ -52,13 +52,6 @@ ;;; Code: - -;; Compatibility code - -(defalias 'json-encode-char0 'encode-char) -(defalias 'json-decode-char0 'decode-char) - - ;; Parameters (defvar json-object-type 'alist @@ -126,9 +119,10 @@ without indentation.") (mapconcat 'identity strings separator)) (defun json-alist-p (list) - "Non-null if and only if LIST is an alist." + "Non-null if and only if LIST is an alist with simple keys." (while (consp list) - (setq list (if (consp (car list)) + (setq list (if (and (consp (car list)) + (atom (caar list))) (cdr list) 'not-alist))) (null list)) @@ -165,7 +159,7 @@ without indentation.") "Advance past the character at point, returning it." (let ((char (json-peek))) (if (eq char :json-eof) - (signal 'end-of-file nil) + (signal 'json-end-of-file nil) (json-advance) char))) @@ -185,6 +179,8 @@ without indentation.") (define-error 'json-string-format "Bad string format" 'json-error) (define-error 'json-key-format "Bad JSON object key" 'json-error) (define-error 'json-object-format "Bad JSON object" 'json-error) +(define-error 'json-end-of-file "End of file while parsing JSON" + '(end-of-file json-error)) @@ -262,7 +258,6 @@ representation will be parsed correctly." (defvar json-special-chars '((?\" . ?\") (?\\ . ?\\) - (?/ . ?/) (?b . ?\b) (?f . ?\f) (?n . ?\n) @@ -284,7 +279,7 @@ representation will be parsed correctly." ((looking-at "[0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f]") (let ((hex (match-string 0))) (json-advance 4) - (json-decode-char0 'ucs (string-to-number hex 16)))) + (string-to-number hex 16))) (t (signal 'json-string-escape (list (point))))))) @@ -310,24 +305,29 @@ representation will be parsed correctly." ;; String encoding -(defun json-encode-char (char) - "Encode CHAR as a JSON string." - (setq char (json-encode-char0 char 'ucs)) - (let ((control-char (car (rassoc char json-special-chars)))) - (cond - ;; Special JSON character (\n, \r, etc.). - (control-char - (format "\\%c" control-char)) - ;; ASCIIish printable character. - ((and (> char 31) (< char 127)) - (format "%c" char)) - ;; Fallback: UCS code point in \uNNNN form. - (t - (format "\\u%04x" char))))) - (defun json-encode-string (string) "Return a JSON representation of STRING." - (format "\"%s\"" (mapconcat 'json-encode-char string ""))) + ;; Reimplement the meat of `replace-regexp-in-string', for + ;; performance (bug#20154). + (let ((l (length string)) + (start 0) + res mb) + ;; Only escape quotation mark, backslash and the control + ;; characters U+0000 to U+001F (RFC 4627, ECMA-404). + (while (setq mb (string-match "[\"\\[:cntrl:]]" string start)) + (let* ((c (aref string mb)) + (special (rassq c json-special-chars))) + (push (substring string start mb) res) + (push (if special + ;; Special JSON character (\n, \r, etc.). + (string ?\\ (car special)) + ;; Fallback: UCS code point in \uNNNN form. + (format "\\u%04x" c)) + res) + (setq start (1+ mb)))) + (push (substring string start l) res) + (push "\"" res) + (apply #'concat "\"" (nreverse res)))) (defun json-encode-key (object) "Return a JSON representation of OBJECT. @@ -553,7 +553,7 @@ Advances point just past JSON object." (if (functionp (car record)) (apply (car record) (cdr record)) (signal 'json-readtable-error record))) - (signal 'end-of-file nil)))) + (signal 'json-end-of-file nil)))) ;; Syntactic sugar for the reader