|
1 | 1 | import "stdlib/ascii.jou" |
2 | 2 | import "stdlib/assert.jou" |
| 3 | +import "stdlib/intnative.jou" |
3 | 4 | import "stdlib/list.jou" |
4 | 5 | import "stdlib/mem.jou" |
5 | 6 | import "stdlib/str.jou" |
@@ -85,7 +86,7 @@ class JSONBuilder: |
85 | 86 |
|
86 | 87 | self.add_comma_if_needed() |
87 | 88 | self.new_line() |
88 | | - self.add_string_to_output(key) |
| 89 | + self.add_string_to_output(key, strlen(key)) |
89 | 90 | self.output.append(':') |
90 | 91 | if self.pretty_print != 0: |
91 | 92 | self.output.append(' ') |
@@ -127,49 +128,55 @@ class JSONBuilder: |
127 | 128 | self.output.extend_from_ptr("false", 5) |
128 | 129 |
|
129 | 130 | @public |
130 | | - def string(self, s: byte*) -> None: |
| 131 | + def string_with_len(self, s: byte*, len: intnative) -> None: |
131 | 132 | if s == NULL: |
132 | 133 | self.null() |
133 | 134 | else: |
| 135 | + assert len >= 0 |
134 | 136 | self.before_a_value() |
135 | | - self.add_string_to_output(s) |
| 137 | + self.add_string_to_output(s, len) |
| 138 | + |
| 139 | + @public |
| 140 | + def string(self, s: byte*) -> None: |
| 141 | + self.string_with_len(s, 0 if s == NULL else strlen(s)) |
136 | 142 |
|
137 | 143 | # This method is used for .string() and .key() methods. |
138 | | - def add_string_to_output(self, s: byte*) -> None: |
| 144 | + def add_string_to_output(self, s: byte*, len: intnative) -> None: |
139 | 145 | self.output.append('"') |
140 | | - while *s != '\0': |
141 | | - match *s: |
| 146 | + i: intnative = 0 |
| 147 | + while i < len: |
| 148 | + match s[i]: |
142 | 149 | case '\n': |
143 | 150 | self.output.extend_from_ptr("\\n", 2) |
144 | | - s++ |
| 151 | + i++ |
145 | 152 | case '\t': |
146 | 153 | self.output.extend_from_ptr("\\t", 2) |
147 | | - s++ |
| 154 | + i++ |
148 | 155 | case '\r': |
149 | 156 | self.output.extend_from_ptr("\\r", 2) |
150 | | - s++ |
| 157 | + i++ |
151 | 158 | case '"' | '\\': |
152 | 159 | self.output.append('\\') |
153 | | - self.output.append(*s++) |
| 160 | + self.output.append(s[i++]) |
154 | 161 | case _: |
155 | | - if is_ascii_printable(*s): |
156 | | - self.output.append(*s++) |
157 | | - elif *s < 128: |
| 162 | + if is_ascii_printable(s[i]): |
| 163 | + self.output.append(s[i++]) |
| 164 | + elif s[i] < 128: |
158 | 165 | # unprintable ASCII character, do these carefully |
159 | 166 | buf: byte[16] |
160 | | - sprintf(buf, "\\u00%02x", *s++) |
| 167 | + sprintf(buf, "\\u00%02x", s[i++]) |
161 | 168 | self.output.extend_from_ptr(buf, strlen(buf)) |
162 | | - elif starts_with(s, "\xe2\x80\xa8"): |
| 169 | + elif len-i >= 3 and starts_with(&s[i], "\xe2\x80\xa8"): |
163 | 170 | # Unicode character U+2028, placing it directly into JSON may cause problems |
164 | 171 | self.output.extend_from_ptr("\\u2028", 6) |
165 | | - s = &s[3] |
166 | | - elif starts_with(s, "\xe2\x80\xa9"): |
| 172 | + i += 3 |
| 173 | + elif len-i >= 3 and starts_with(&s[i], "\xe2\x80\xa9"): |
167 | 174 | # Unicode character U+2029, placing it directly into JSON may cause problems |
168 | 175 | self.output.extend_from_ptr("\\u2029", 6) |
169 | | - s = &s[3] |
| 176 | + i += 3 |
170 | 177 | else: |
171 | 178 | # part of a non-ASCII character in UTF-8, output it as is |
172 | | - self.output.append(*s++) |
| 179 | + self.output.append(s[i++]) |
173 | 180 | self.output.append('"') |
174 | 181 |
|
175 | 182 | @public |
|
0 commit comments