Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(170)

Side by Side Diff: lib/json/json.dart

Issue 9465023: Fix escaping in JSON.stringify and add unit test (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Fix a stray LINE_FEED reference Created 8 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | tests/utils/src/JsonTest.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #library("json"); 5 #library("json");
6 6
7 // Pure Dart implementation of JSON protocol. 7 // Pure Dart implementation of JSON protocol.
8 8
9 /** 9 /**
10 * Utility class to parse JSON and serialize objects to JSON. 10 * Utility class to parse JSON and serialize objects to JSON.
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after
107 } 107 }
108 } 108 }
109 109
110 typedef bool Predicate(int c); 110 typedef bool Predicate(int c);
111 111
112 class JsonTokenizer { 112 class JsonTokenizer {
113 static final int BACKSPACE = 8; // '\b'.charCodeAt(0) 113 static final int BACKSPACE = 8; // '\b'.charCodeAt(0)
114 static final int TAB = 9; // '\t'.charCodeAt(0) 114 static final int TAB = 9; // '\t'.charCodeAt(0)
115 static final int NEW_LINE = 10; // '\n'.charCodeAt(0) 115 static final int NEW_LINE = 10; // '\n'.charCodeAt(0)
116 static final int FORM_FEED = 12; // '\f'.charCodeAt(0) 116 static final int FORM_FEED = 12; // '\f'.charCodeAt(0)
117 static final int LINE_FEED = 13; // '\r'.charCodeAt(0) 117 static final int CARRIAGE_RETURN = 13; // '\r'.charCodeAt(0)
118 static final int SPACE = 32; // ' '.charCodeAt(0) 118 static final int SPACE = 32; // ' '.charCodeAt(0)
119 static final int QUOTE = 34; // '"'.charCodeAt(0) 119 static final int QUOTE = 34; // '"'.charCodeAt(0)
120 static final int PLUS = 43; // '+'.charCodeAt(0) 120 static final int PLUS = 43; // '+'.charCodeAt(0)
121 static final int COMMA = 44; // ','.charCodeAt(0) 121 static final int COMMA = 44; // ','.charCodeAt(0)
122 static final int MINUS = 45; // '-'.charCodeAt(0) 122 static final int MINUS = 45; // '-'.charCodeAt(0)
123 static final int DOT = 46; // '.'.charCodeAt(0) 123 static final int DOT = 46; // '.'.charCodeAt(0)
124 static final int SLASH = 47; // '/'.charCodeAt(0) 124 static final int SLASH = 47; // '/'.charCodeAt(0)
125 static final int ZERO = 48; // '0'.charCodeAt(0) 125 static final int ZERO = 48; // '0'.charCodeAt(0)
126 static final int NINE = 57; // '9'.charCodeAt(0) 126 static final int NINE = 57; // '9'.charCodeAt(0)
127 static final int COLON = 58; // ':'.charCodeAt(0) 127 static final int COLON = 58; // ':'.charCodeAt(0)
128 static final int A_BIG = 65; // 'A'.charCodeAt(0) 128 static final int A_BIG = 65; // 'A'.charCodeAt(0)
129 static final int E_BIG = 69; // 'E'.charCodeAt(0) 129 static final int E_BIG = 69; // 'E'.charCodeAt(0)
130 static final int Z_BIG = 90; // 'Z'.charCodeAt(0) 130 static final int Z_BIG = 90; // 'Z'.charCodeAt(0)
131 static final int LBRACKET = 91; // '['.charCodeAt(0) 131 static final int LBRACKET = 91; // '['.charCodeAt(0)
132 static final int BACKSLASH = 92; // '\\'.charCodeAt(0) 132 static final int BACKSLASH = 92; // '\\'.charCodeAt(0)
133 static final int RBRACKET = 93; // ']'.charCodeAt(0) 133 static final int RBRACKET = 93; // ']'.charCodeAt(0)
134 static final int A_SMALL = 97; // 'a'.charCodeAt(0) 134 static final int A_SMALL = 97; // 'a'.charCodeAt(0)
135 static final int B_SMALL = 98; // 'b'.charCodeAt(0) 135 static final int B_SMALL = 98; // 'b'.charCodeAt(0)
136 static final int E_SMALL = 101; // 'e'.charCodeAt(0) 136 static final int E_SMALL = 101; // 'e'.charCodeAt(0)
137 static final int F_SMALL = 102; // 'f'.charCodeAt(0)
137 static final int N_SMALL = 110; // 'n'.charCodeAt(0) 138 static final int N_SMALL = 110; // 'n'.charCodeAt(0)
138 static final int R_SMALL = 114; // 'r'.charCodeAt(0) 139 static final int R_SMALL = 114; // 'r'.charCodeAt(0)
140 static final int T_SMALL = 116; // 't'.charCodeAt(0)
141 static final int U_SMALL = 117; // 'u'.charCodeAt(0)
139 static final int Z_SMALL = 122; // 'z'.charCodeAt(0) 142 static final int Z_SMALL = 122; // 'z'.charCodeAt(0)
140 static final int LBRACE = 123; // '{'.charCodeAt(0) 143 static final int LBRACE = 123; // '{'.charCodeAt(0)
141 static final int RBRACE = 125; // '}'.charCodeAt(0) 144 static final int RBRACE = 125; // '}'.charCodeAt(0)
142 145
143 JsonTokenizer(String s) : _s = s + ' ', _pos = 0, _len = s.length + 1 {} 146 JsonTokenizer(String s) : _s = s + ' ', _pos = 0, _len = s.length + 1 {}
144 147
145 /** 148 /**
146 * Fetches next token or [:null:] if the stream has been exhausted. 149 * Fetches next token or [:null:] if the stream has been exhausted.
147 */ 150 */
148 JsonToken next() { 151 JsonToken next() {
(...skipping 30 matching lines...) Expand all
179 case '/': 182 case '/':
180 c = SLASH; 183 c = SLASH;
181 break; 184 break;
182 case 'b': 185 case 'b':
183 c = BACKSPACE; 186 c = BACKSPACE;
184 break; 187 break;
185 case 'n': 188 case 'n':
186 c = NEW_LINE; 189 c = NEW_LINE;
187 break; 190 break;
188 case 'r': 191 case 'r':
189 c = LINE_FEED; 192 c = CARRIAGE_RETURN;
190 break; 193 break;
191 case 'f': 194 case 'f':
192 c = FORM_FEED; 195 c = FORM_FEED;
193 break; 196 break;
194 case 't': 197 case 't':
195 c = TAB; 198 c = TAB;
196 break; 199 break;
197 case 'u': 200 case 'u':
198 if (_pos + 5 > _len) { 201 if (_pos + 5 > _len) {
199 throw 'Invalid unicode esacape sequence: \\' + 202 throw 'Invalid unicode esacape sequence: \\' +
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after
328 while (_pos < _len && predicate(_s.charCodeAt(_pos))) { 331 while (_pos < _len && predicate(_s.charCodeAt(_pos))) {
329 _pos++; 332 _pos++;
330 } 333 }
331 if (_pos == _len) { 334 if (_pos == _len) {
332 throw errorMsg; 335 throw errorMsg;
333 } 336 }
334 } 337 }
335 338
336 // TODO other kind of whitespace. 339 // TODO other kind of whitespace.
337 static bool isWhitespace(int c) { 340 static bool isWhitespace(int c) {
338 return c == SPACE || c == TAB || c == NEW_LINE || c == LINE_FEED; 341 return c == SPACE || c == TAB || c == NEW_LINE || c == CARRIAGE_RETURN;
339 } 342 }
340 static bool isDigit(int c) { 343 static bool isDigit(int c) {
341 return (ZERO <= c) && (c <= NINE); 344 return (ZERO <= c) && (c <= NINE);
342 } 345 }
343 static bool isLetter(int c) { 346 static bool isLetter(int c) {
344 return ((A_SMALL <= c) && (c <= Z_SMALL)) || ((A_BIG <= c) && (c <= Z_BIG)) ; 347 return ((A_SMALL <= c) && (c <= Z_SMALL)) || ((A_BIG <= c) && (c <= Z_BIG)) ;
345 } 348 }
346 } 349 }
347 350
348 class JsonParser { 351 class JsonParser {
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after
486 return x.toString(); 489 return x.toString();
487 490
488 case x is double: 491 case x is double:
489 return x.toString(); 492 return x.toString();
490 493
491 default: 494 default:
492 return x.toDouble().toString(); 495 return x.toDouble().toString();
493 } 496 }
494 } 497 }
495 498
496 // TODO: add others. 499 // ('0' + x) or ('a' + x - 10)
497 static bool _needsEscape(int charCode) { 500 static int _hexDigit(int x) => x < 10 ? 48 + x : 87 + x;
498 return JsonTokenizer.QUOTE == charCode || JsonTokenizer.BACKSLASH == charCod e
499 || JsonTokenizer.NEW_LINE == charCode || JsonTokenizer.LINE_FEED == charCo de;
500 }
501 501
502 static void _escape(StringBuffer sb, String s) { 502 static void _escape(StringBuffer sb, String s) {
503 // TODO: support \u code points.
504 // TODO: use writeCodePoint when implemented.
505 // TODO: use for each if implemented.
506 final int length = s.length; 503 final int length = s.length;
507 bool needsEscape = false; 504 bool needsEscape = false;
508 final charCodes = new List<int>(); 505 final charCodes = new List<int>();
509 for (int i = 0; i < length; i++) { 506 for (int i = 0; i < length; i++) {
510 int charCode = s.charCodeAt(i); 507 int charCode = s.charCodeAt(i);
511 if (_needsEscape(charCode)) { 508 if (charCode < 32) {
509 needsEscape = true;
512 charCodes.add(JsonTokenizer.BACKSLASH); 510 charCodes.add(JsonTokenizer.BACKSLASH);
511 switch (charCode) {
512 case JsonTokenizer.BACKSPACE:
513 charCodes.add(JsonTokenizer.B_SMALL);
514 break;
515 case JsonTokenizer.TAB:
516 charCodes.add(JsonTokenizer.T_SMALL);
517 break;
518 case JsonTokenizer.NEW_LINE:
519 charCodes.add(JsonTokenizer.N_SMALL);
520 break;
521 case JsonTokenizer.FORM_FEED:
522 charCodes.add(JsonTokenizer.F_SMALL);
523 break;
524 case JsonTokenizer.CARRIAGE_RETURN:
525 charCodes.add(JsonTokenizer.R_SMALL);
526 break;
527 default:
528 charCodes.add(JsonTokenizer.U_SMALL);
529 charCodes.add(_hexDigit((charCode >> 12) & 0xf));
530 charCodes.add(_hexDigit((charCode >> 8) & 0xf));
531 charCodes.add(_hexDigit((charCode >> 4) & 0xf));
532 charCodes.add(_hexDigit(charCode & 0xf));
533 break;
534 }
535 } else if (charCode == JsonTokenizer.QUOTE ||
536 charCode == JsonTokenizer.BACKSLASH) {
513 needsEscape = true; 537 needsEscape = true;
514 538 charCodes.add(JsonTokenizer.BACKSLASH);
515 if (JsonTokenizer.NEW_LINE == charCode) { 539 charCodes.add(charCode);
516 charCode = JsonTokenizer.N_SMALL; 540 } else {
517 } else if (JsonTokenizer.LINE_FEED == charCode) { 541 charCodes.add(charCode);
518 charCode = JsonTokenizer.R_SMALL;
519 }
520 } 542 }
521 charCodes.add(charCode);
522 } 543 }
523 sb.add(needsEscape ? new String.fromCharCodes(charCodes) : s); 544 sb.add(needsEscape ? new String.fromCharCodes(charCodes) : s);
524 } 545 }
525 546
526 void _checkCycle(final object) { 547 void _checkCycle(final object) {
527 // TODO: use Iterables. 548 // TODO: use Iterables.
528 for (int i = 0; i < _seen.length; i++) { 549 for (int i = 0; i < _seen.length; i++) {
529 if (_seen[i] === object) { 550 if (_seen[i] === object) {
530 throw 'Cyclic structure'; 551 throw 'Cyclic structure';
531 } 552 }
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
592 }); 613 });
593 _sb.add('}'); 614 _sb.add('}');
594 _seen.removeLast(); 615 _seen.removeLast();
595 return; 616 return;
596 617
597 default: 618 default:
598 throw const JsonUnsupportedObjectType(); 619 throw const JsonUnsupportedObjectType();
599 } 620 }
600 } 621 }
601 } 622 }
OLDNEW
« no previous file with comments | « no previous file | tests/utils/src/JsonTest.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698