Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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 part of dart.convert; | 5 part of dart.convert; |
| 6 | 6 |
| 7 /** The Unicode Replacement character `U+FFFD` (�). */ | 7 /** The Unicode Replacement character `U+FFFD` (�). */ |
| 8 const int UNICODE_REPLACEMENT_CHARACTER_RUNE = 0xFFFD; | 8 const int UNICODE_REPLACEMENT_CHARACTER_RUNE = 0xFFFD; |
| 9 | 9 |
| 10 /** The Unicode Byte Order Marker (BOM) character `U+FEFF`. */ | 10 /** The Unicode Byte Order Marker (BOM) character `U+FEFF`. */ |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 59 * `U+FFFD` (�). Otherwise it throws a [FormatException]. | 59 * `U+FFFD` (�). Otherwise it throws a [FormatException]. |
| 60 * | 60 * |
| 61 * If [allowMalformed] is not given, it defaults to the `allowMalformed` that | 61 * If [allowMalformed] is not given, it defaults to the `allowMalformed` that |
| 62 * was used to instantiate `this`. | 62 * was used to instantiate `this`. |
| 63 */ | 63 */ |
| 64 String decode(List<int> codeUnits, { bool allowMalformed }) { | 64 String decode(List<int> codeUnits, { bool allowMalformed }) { |
| 65 if (allowMalformed == null) allowMalformed = _allowMalformed; | 65 if (allowMalformed == null) allowMalformed = _allowMalformed; |
| 66 return new Utf8Decoder(allowMalformed: allowMalformed).convert(codeUnits); | 66 return new Utf8Decoder(allowMalformed: allowMalformed).convert(codeUnits); |
| 67 } | 67 } |
| 68 | 68 |
| 69 Converter<String, List<int>> get encoder => new Utf8Encoder(); | 69 Utf8Encoder get encoder => new Utf8Encoder(); |
| 70 Converter<List<int>, String> get decoder { | 70 Utf8Decoder get decoder { |
| 71 return new Utf8Decoder(allowMalformed: _allowMalformed); | 71 return new Utf8Decoder(allowMalformed: _allowMalformed); |
| 72 } | 72 } |
| 73 } | 73 } |
| 74 | 74 |
| 75 /** | 75 /** |
| 76 * This class converts strings to their UTF-8 code units (a list of | 76 * This class converts strings to their UTF-8 code units (a list of |
| 77 * unsigned 8-bit integers). | 77 * unsigned 8-bit integers). |
| 78 */ | 78 */ |
| 79 class Utf8Encoder extends Converter<String, List<int>> { | 79 class Utf8Encoder extends Converter<String, List<int>> { |
| 80 | 80 |
| 81 const Utf8Encoder(); | 81 const Utf8Encoder(); |
| 82 | 82 |
| 83 /** | 83 /** |
| 84 * Converts [string] to its UTF-8 code units (a list of | 84 * Converts [string] to its UTF-8 code units (a list of |
| 85 * unsigned 8-bit integers). | 85 * unsigned 8-bit integers). |
| 86 * | |
| 87 * If [start] and [end] are provided, only the substring | |
| 88 * `string.substring(start, end)` is converted. | |
| 86 */ | 89 */ |
| 87 List<int> convert(String string) { | 90 List<int> convert(String string, [int start = 0, int end]) { |
|
Søren Gjesse
2014/11/19 13:53:28
Should these be named arguments? Otherwise we are
| |
| 91 int stringLength = string.length; | |
| 92 if (start < 0 || start > stringLength) { | |
| 93 throw new RangeError.range(start, 0, stringLength, "start"); | |
| 94 } | |
| 95 if (end == null) { | |
| 96 end = stringLength; | |
| 97 } else if (end < start || end > stringLength) { | |
| 98 throw new RangeError.range(end, start, stringLength, "end"); | |
| 99 } | |
| 100 int length = end - start; | |
| 101 if (length == 0) return new Uint8List(0); | |
| 88 // Create a new encoder with a length that is guaranteed to be big enough. | 102 // Create a new encoder with a length that is guaranteed to be big enough. |
| 89 // A single code unit uses at most 3 bytes. Two code units at most 4. | 103 // A single code unit uses at most 3 bytes, a surrogate pair at most 4. |
| 90 _Utf8Encoder encoder = new _Utf8Encoder.withBufferSize(string.length * 3); | 104 _Utf8Encoder encoder = new _Utf8Encoder.withBufferSize(length * 3); |
| 91 int endPosition = encoder._fillBuffer(string, 0, string.length); | 105 int endPosition = encoder._fillBuffer(string, start, end); |
| 92 assert(endPosition >= string.length - 1); | 106 assert(endPosition >= end - 1); |
| 93 if (endPosition != string.length) { | 107 if (endPosition != end) { |
| 94 int lastCodeUnit = string.codeUnitAt(string.length - 1); | 108 // Encoding skipped the last code unit. |
| 109 // That can only happen if the last code unit is a leadsurrogate. | |
| 110 // Force encoding of the lead surrogate by itself. | |
| 111 int lastCodeUnit = string.codeUnitAt(end - 1); | |
| 95 assert(_isLeadSurrogate(lastCodeUnit)); | 112 assert(_isLeadSurrogate(lastCodeUnit)); |
| 96 // We use a non-surrogate as `nextUnit` so that _writeSurrogate just | 113 // We use a non-surrogate as `nextUnit` so that _writeSurrogate just |
| 97 // writes the lead-surrogate. | 114 // writes the lead-surrogate. |
| 98 bool wasCombined = encoder._writeSurrogate(lastCodeUnit, 0); | 115 bool wasCombined = encoder._writeSurrogate(lastCodeUnit, 0); |
| 99 assert(!wasCombined); | 116 assert(!wasCombined); |
| 100 } | 117 } |
| 101 return encoder._buffer.sublist(0, encoder._bufferIndex); | 118 return encoder._buffer.sublist(0, encoder._bufferIndex); |
| 102 } | 119 } |
| 103 | 120 |
| 104 /** | 121 /** |
| (...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 306 * sequences with the Unicode Replacement character `U+FFFD` (�). Otherwise | 323 * sequences with the Unicode Replacement character `U+FFFD` (�). Otherwise |
| 307 * it throws a [FormatException]. | 324 * it throws a [FormatException]. |
| 308 */ | 325 */ |
| 309 const Utf8Decoder({ bool allowMalformed: false }) | 326 const Utf8Decoder({ bool allowMalformed: false }) |
| 310 : this._allowMalformed = allowMalformed; | 327 : this._allowMalformed = allowMalformed; |
| 311 | 328 |
| 312 /** | 329 /** |
| 313 * Converts the UTF-8 [codeUnits] (a list of unsigned 8-bit integers) to the | 330 * Converts the UTF-8 [codeUnits] (a list of unsigned 8-bit integers) to the |
| 314 * corresponding string. | 331 * corresponding string. |
| 315 * | 332 * |
| 333 * Uses the code units from [start] to, but no including, [end]. | |
| 334 * If [end] is omitted, it defaults to `codeUnits.length`. | |
|
Søren Gjesse
2014/11/19 13:53:28
Maybe add some more information on invalid encodin
| |
| 335 * | |
| 316 * If the [codeUnits] start with a leading [UNICODE_BOM_CHARACTER_RUNE] this | 336 * If the [codeUnits] start with a leading [UNICODE_BOM_CHARACTER_RUNE] this |
| 317 * character is discarded. | 337 * character is discarded. |
| 318 */ | 338 */ |
| 319 String convert(List<int> codeUnits) { | 339 String convert(List<int> codeUnits, [int start = 0, int end]) { |
| 340 int length = codeUnits.length; | |
| 341 if (start < 0 || start > length) { | |
| 342 throw new RangeError.range(start, 0, length, "start"); | |
| 343 } | |
| 344 if (end == null) { | |
| 345 end = length; | |
| 346 } else if (end < start || end > length) { | |
| 347 throw new RangeError.range(end, start, length, "end"); | |
| 348 } | |
| 320 StringBuffer buffer = new StringBuffer(); | 349 StringBuffer buffer = new StringBuffer(); |
| 321 _Utf8Decoder decoder = new _Utf8Decoder(buffer, _allowMalformed); | 350 _Utf8Decoder decoder = new _Utf8Decoder(buffer, _allowMalformed); |
| 322 decoder.convert(codeUnits, 0, codeUnits.length); | 351 decoder.convert(codeUnits, start, end); |
| 323 decoder.close(); | 352 decoder.close(); |
| 324 return buffer.toString(); | 353 return buffer.toString(); |
| 325 } | 354 } |
| 326 | 355 |
| 327 /** | 356 /** |
| 328 * Starts a chunked conversion. | 357 * Starts a chunked conversion. |
| 329 * | 358 * |
| 330 * The converter works more efficiently if the given [sink] is a | 359 * The converter works more efficiently if the given [sink] is a |
| 331 * [StringConversionSink]. | 360 * [StringConversionSink]. |
| 332 */ | 361 */ |
| (...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 538 } | 567 } |
| 539 break loop; | 568 break loop; |
| 540 } | 569 } |
| 541 if (expectedUnits > 0) { | 570 if (expectedUnits > 0) { |
| 542 _value = value; | 571 _value = value; |
| 543 _expectedUnits = expectedUnits; | 572 _expectedUnits = expectedUnits; |
| 544 _extraUnits = extraUnits; | 573 _extraUnits = extraUnits; |
| 545 } | 574 } |
| 546 } | 575 } |
| 547 } | 576 } |
| OLD | NEW |