| ... | ... | @@ -2163,45 +2163,51 @@ fn outputUnicodeEscape( |
| 2163 | 2163 | } |
| 2164 | 2164 | } |
| 2165 | 2165 | |
| 2166 | | fn outputJsonString(value: []const u8, options: StringifyOptions, out_stream: anytype) !void { |
| 2167 | | try out_stream.writeByte('\"'); |
| 2166 | /// Write `string` to `writer` as a JSON encoded string. |
| 2167 | pub fn encodeJsonString(string: []const u8, options: StringifyOptions, writer: anytype) !void { |
| 2168 | try writer.writeByte('\"'); |
| 2169 | try encodeJsonStringChars(string, options, writer); |
| 2170 | try writer.writeByte('\"'); |
| 2171 | } |
| 2172 | |
| 2173 | /// Write `chars` to `writer` as JSON encoded string characters. |
| 2174 | pub fn encodeJsonStringChars(chars: []const u8, options: StringifyOptions, writer: anytype) !void { |
| 2168 | 2175 | var i: usize = 0; |
| 2169 | | while (i < value.len) : (i += 1) { |
| 2170 | | switch (value[i]) { |
| 2176 | while (i < chars.len) : (i += 1) { |
| 2177 | switch (chars[i]) { |
| 2171 | 2178 | // normal ascii character |
| 2172 | | 0x20...0x21, 0x23...0x2E, 0x30...0x5B, 0x5D...0x7F => |c| try out_stream.writeByte(c), |
| 2179 | 0x20...0x21, 0x23...0x2E, 0x30...0x5B, 0x5D...0x7F => |c| try writer.writeByte(c), |
| 2173 | 2180 | // only 2 characters that *must* be escaped |
| 2174 | | '\\' => try out_stream.writeAll("\\\\"), |
| 2175 | | '\"' => try out_stream.writeAll("\\\""), |
| 2181 | '\\' => try writer.writeAll("\\\\"), |
| 2182 | '\"' => try writer.writeAll("\\\""), |
| 2176 | 2183 | // solidus is optional to escape |
| 2177 | 2184 | '/' => { |
| 2178 | 2185 | if (options.string.String.escape_solidus) { |
| 2179 | | try out_stream.writeAll("\\/"); |
| 2186 | try writer.writeAll("\\/"); |
| 2180 | 2187 | } else { |
| 2181 | | try out_stream.writeByte('/'); |
| 2188 | try writer.writeByte('/'); |
| 2182 | 2189 | } |
| 2183 | 2190 | }, |
| 2184 | 2191 | // control characters with short escapes |
| 2185 | 2192 | // TODO: option to switch between unicode and 'short' forms? |
| 2186 | | 0x8 => try out_stream.writeAll("\\b"), |
| 2187 | | 0xC => try out_stream.writeAll("\\f"), |
| 2188 | | '\n' => try out_stream.writeAll("\\n"), |
| 2189 | | '\r' => try out_stream.writeAll("\\r"), |
| 2190 | | '\t' => try out_stream.writeAll("\\t"), |
| 2193 | 0x8 => try writer.writeAll("\\b"), |
| 2194 | 0xC => try writer.writeAll("\\f"), |
| 2195 | '\n' => try writer.writeAll("\\n"), |
| 2196 | '\r' => try writer.writeAll("\\r"), |
| 2197 | '\t' => try writer.writeAll("\\t"), |
| 2191 | 2198 | else => { |
| 2192 | | const ulen = std.unicode.utf8ByteSequenceLength(value[i]) catch unreachable; |
| 2199 | const ulen = std.unicode.utf8ByteSequenceLength(chars[i]) catch unreachable; |
| 2193 | 2200 | // control characters (only things left with 1 byte length) should always be printed as unicode escapes |
| 2194 | 2201 | if (ulen == 1 or options.string.String.escape_unicode) { |
| 2195 | | const codepoint = std.unicode.utf8Decode(value[i .. i + ulen]) catch unreachable; |
| 2196 | | try outputUnicodeEscape(codepoint, out_stream); |
| 2202 | const codepoint = std.unicode.utf8Decode(chars[i .. i + ulen]) catch unreachable; |
| 2203 | try outputUnicodeEscape(codepoint, writer); |
| 2197 | 2204 | } else { |
| 2198 | | try out_stream.writeAll(value[i .. i + ulen]); |
| 2205 | try writer.writeAll(chars[i .. i + ulen]); |
| 2199 | 2206 | } |
| 2200 | 2207 | i += ulen - 1; |
| 2201 | 2208 | }, |
| 2202 | 2209 | } |
| 2203 | 2210 | } |
| 2204 | | try out_stream.writeByte('\"'); |
| 2205 | 2211 | } |
| 2206 | 2212 | |
| 2207 | 2213 | pub fn stringify( |
| ... | ... | @@ -2288,7 +2294,7 @@ pub fn stringify( |
| 2288 | 2294 | if (child_options.whitespace) |child_whitespace| { |
| 2289 | 2295 | try child_whitespace.outputIndent(out_stream); |
| 2290 | 2296 | } |
| 2291 | | try outputJsonString(Field.name, options, out_stream); |
| 2297 | try encodeJsonString(Field.name, options, out_stream); |
| 2292 | 2298 | try out_stream.writeByte(':'); |
| 2293 | 2299 | if (child_options.whitespace) |child_whitespace| { |
| 2294 | 2300 | if (child_whitespace.separator) { |
| ... | ... | @@ -2321,7 +2327,7 @@ pub fn stringify( |
| 2321 | 2327 | // TODO: .Many when there is a sentinel (waiting for https://github.com/ziglang/zig/pull/3972) |
| 2322 | 2328 | .Slice => { |
| 2323 | 2329 | if (ptr_info.child == u8 and options.string == .String and std.unicode.utf8ValidateSlice(value)) { |
| 2324 | | try outputJsonString(value, options, out_stream); |
| 2330 | try encodeJsonString(value, options, out_stream); |
| 2325 | 2331 | return; |
| 2326 | 2332 | } |
| 2327 | 2333 | |