Files
EWF/library/kernel/json_string.e
jfiat d67e01eea6 Better support for special character and unicode (\n \r \" ... and \uXXXX where XXXX is an hexadecimal value)
Added features to JSON_STRING
  - make_json_from_string_32 (READABLE_STRING_32)
  - escaped_string_8: STRING_8
  - escaped_string_32: STRING_32
Added associated autotests
2012-01-13 17:26:23 +00:00

324 lines
7.2 KiB
Plaintext

note
description: "[
A JSON_STRING represent a string in JSON.
A string is a collection of zero or more Unicodes characters, wrapped in double
quotes, using blackslash espaces.
]"
author: "Javier Velilla"
date: "2008/08/24"
revision: "Revision 0.1"
license:"MIT (see http://www.opensource.org/licenses/mit-license.php)"
class
JSON_STRING
inherit
JSON_VALUE
redefine
is_equal
end
create
make_json,
make_json_from_string_32,
make_with_escaped_json
convert
make_json ({READABLE_STRING_8, STRING_8, IMMUTABLE_STRING_8})
feature {NONE} -- Initialization
make_json (an_item: READABLE_STRING_8)
-- Initialize.
require
item_not_void: an_item /= Void
do
make_with_escaped_json (escaped_json_string (an_item))
end
make_json_from_string_32 (an_item: READABLE_STRING_32)
-- Initialize.
require
item_not_void: an_item /= Void
do
make_with_escaped_json (escaped_json_string_32 (an_item))
end
make_with_escaped_json (an_item: READABLE_STRING_8)
-- Initialize with an_item already escaped
require
item_not_void: an_item /= Void
do
item := an_item
end
feature -- Access
item: STRING
-- Contents
unescaped_string: STRING_8
local
s: like item
i, n: INTEGER
c: CHARACTER
do
s := item
n := s.count
create Result.make (n)
from i := 1 until i > n loop
c := s[i]
if c = '\' then
if i < n then
inspect s[i+1]
when '\' then
Result.append_character ('\')
i := i + 2
when '%"' then
Result.append_character ('%"')
i := i + 2
when 'n' then
Result.append_character ('%N')
i := i + 2
when 'r' then
Result.append_character ('%R')
i := i + 2
when 'u' then
--| Leave unicode \uXXXX unescaped
Result.append_character ('\')
i := i + 1
else
Result.append_character ('\')
i := i + 1
end
else
Result.append_character ('\')
i := i + 1
end
else
Result.append_character (c)
i := i + 1
end
end
end
unescaped_string_32: STRING_32
local
s: like item
i, n: INTEGER
c: CHARACTER
hex: STRING
do
s := item
n := s.count
create Result.make (n)
from i := 1 until i > n loop
c := s[i]
if c = '\' then
if i < n then
inspect s[i+1]
when '\' then
Result.append_character ('\')
i := i + 2
when '%"' then
Result.append_character ('%"')
i := i + 2
when 'n' then
Result.append_character ('%N')
i := i + 2
when 'r' then
Result.append_character ('%R')
i := i + 2
when 'u' then
hex := s.substring (i+2, i+2+4 - 1)
if hex.count = 4 then
Result.append_code (hexadecimal_to_natural_32 (hex))
end
i := i + 2 + 4
else
Result.append_character ('\')
i := i + 1
end
else
Result.append_character ('\')
i := i + 1
end
else
Result.append_character (c.to_character_32)
i := i + 1
end
end
end
representation: STRING
do
Result := "%""
Result.append (item)
Result.append_character ('%"')
end
feature -- Visitor pattern
accept (a_visitor: JSON_VISITOR)
-- Accept `a_visitor'.
-- (Call `visit_json_string' procedure on `a_visitor'.)
do
a_visitor.visit_json_string (Current)
end
feature -- Comparison
is_equal (other: like Current): BOOLEAN
-- Is JSON_STRING made of same character sequence as `other'
-- (possibly with a different capacity)?
do
Result := item.is_equal (other.item)
end
feature -- Change Element
append (a_string: STRING)
-- Add an_item
require
a_string_not_void: a_string /= Void
do
item.append_string (a_string)
end
feature -- Status report
hash_code: INTEGER
-- Hash code value
do
Result := item.hash_code
end
feature -- Status report
debug_output: STRING
-- String that should be displayed in debugger to represent `Current'.
do
Result := item
end
feature {NONE} -- Implementation
is_hexadecimal (s: READABLE_STRING_8): BOOLEAN
do
Result := across s as scur all scur.item.is_hexa_digit end
end
hexadecimal_to_natural_32 (s: READABLE_STRING_8): NATURAL_32
-- Hexadecimal string `s' converted to NATURAL_32 value
require
s_not_void: s /= Void
is_hexadecimal: is_hexadecimal (s)
local
i, nb: INTEGER
char: CHARACTER
do
nb := s.count
if nb >= 2 and then s.item (2) = 'x' then
i := 3
else
i := 1
end
from
until
i > nb
loop
Result := Result * 16
char := s.item (i)
if char >= '0' and then char <= '9' then
Result := Result + (char |-| '0').to_natural_32
else
Result := Result + (char.lower |-| 'a' + 10).to_natural_32
end
i := i + 1
end
end
escaped_json_string (s: READABLE_STRING_8): STRING_8
-- JSON string with '"' and '\' characters escaped
require
s_not_void: s /= Void
local
i, n: INTEGER
c: CHARACTER_8
do
n := s.count
create Result.make (n + n // 10)
from i := 1 until i > n loop
c := s.item (i)
inspect c
when '%"' then Result.append_string ("\%"")
when '\' then Result.append_string ("\\")
when '%R' then Result.append_string ("\r")
when '%N' then Result.append_string ("\n")
else
Result.extend (c)
end
i := i + 1
end
end
escaped_json_string_32 (s: READABLE_STRING_32): STRING_8
-- JSON string with '"' and '\' characters and unicode escaped
require
s_not_void: s /= Void
local
i, j, n: INTEGER
uc: CHARACTER_32
c: CHARACTER_8
h: STRING_8
do
n := s.count
create Result.make (n + n // 10)
from i := 1 until i > n loop
uc := s.item (i)
if uc.is_character_8 then
c := uc.to_character_8
inspect c
when '%"' then Result.append_string ("\%"")
when '\' then Result.append_string ("\\")
when '%R' then Result.append_string ("\r")
when '%N' then Result.append_string ("\n")
else
Result.extend (c)
end
else
Result.append ("\u")
h := uc.code.to_hex_string
-- Remove first 0 and keep 4 hexa digit
from
j := 1
until
h.count = 4 or (j <= h.count and then h.item (j) /= '0')
loop
j := j + 1
end
h := h.substring (j, h.count)
from
until
h.count >= 4
loop
h.prepend_integer (0)
end
check h.count = 4 end
Result.append (h)
end
i := i + 1
end
end
invariant
value_not_void: item /= Void
end