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 const UTF8 = const Utf8Codec(); | 7 const UTF8 = const Utf8Codec(); |
| 8 | 8 |
| 9 /** | 9 /** |
| 10 * A [Utf8Codec] encodes strings to utf-8 code units (bytes) and decodes | 10 * A [Utf8Codec] encodes strings to utf-8 code units (bytes) and decodes |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 51 | 51 |
| 52 /** | 52 /** |
| 53 * A [Utf8Encoder] converts strings to their UTF-8 code units (a list of | 53 * A [Utf8Encoder] converts strings to their UTF-8 code units (a list of |
| 54 * unsigned 8-bit integers). | 54 * unsigned 8-bit integers). |
| 55 */ | 55 */ |
| 56 class Utf8Encoder extends Converter<String, List<int>> { | 56 class Utf8Encoder extends Converter<String, List<int>> { |
| 57 /** | 57 /** |
| 58 * Converts [string] to its UTF-8 code units (a list of | 58 * Converts [string] to its UTF-8 code units (a list of |
| 59 * unsigned 8-bit integers). | 59 * unsigned 8-bit integers). |
| 60 */ | 60 */ |
| 61 List<int> convert(String string) => OLD_UTF_LIB.encodeUtf8(string); | 61 List<int> convert(String string) { |
| 62 // Create a new encoder with a length that is guaranteed to be big enough. | |
| 63 // A single code unit uses at most 3 bytes. Two code units at most 4. | |
| 64 _Utf8Encoder encoder = new _Utf8Encoder.withBufferSize(string.length * 3); | |
| 65 int endPosition = encoder._fillBuffer(string, 0, string.length); | |
| 66 assert(endPosition >= string.length - 1); | |
| 67 if (endPosition != string.length) { | |
| 68 int lastCodeUnit = string.codeUnitAt(string.length - 1); | |
| 69 assert(_isLeadSurrogate(lastCodeUnit)); | |
| 70 // We use a non-surrogate as `nextUnit` so that _writeSurrogate just | |
| 71 // writes the lead-surrogate. | |
| 72 bool wasCombined = encoder._writeSurrogate(lastCodeUnit, 0); | |
| 73 assert(!wasCombined); | |
| 74 } | |
| 75 return encoder._buffer.sublist(0, encoder._bufferIndex); | |
| 76 } | |
| 62 } | 77 } |
| 63 | 78 |
| 64 /** | 79 /** |
| 65 * A [Utf8Decoder] converts UTF-8 code units (lists of unsigned 8-bit integers) | 80 * This class encodes Strings to UTF-8 code units (unsigned 8 bit integers). |
| 81 */ | |
| 82 // TODO(floitsch): make this class public. | |
| 83 class _Utf8Encoder { | |
| 84 int _carry = 0; | |
| 85 int _bufferIndex = 0; | |
| 86 final Uint8List _buffer; | |
| 87 | |
| 88 static const _DEFAULT_BYTE_BUFFER_SIZE = 1024; | |
| 89 | |
| 90 _Utf8Encoder() : this.withBufferSize(_DEFAULT_BYTE_BUFFER_SIZE); | |
| 91 | |
| 92 _Utf8Encoder.withBufferSize(int bufferSize) | |
| 93 : _buffer = new Uint8List(bufferSize); | |
| 94 | |
| 95 /** | |
| 96 * Tries to combine the given [leadingSurrogate] with the [nextCodeUnit] and | |
| 97 * writes it to [_buffer]. | |
| 98 * | |
| 99 * Returns true if the [nextCodeUnit] was combined with the | |
| 100 * [leadingSurrogate]. If it wasn't then nextCodeUnit has not been written | |
| 101 * yet. | |
| 102 */ | |
| 103 bool _writeSurrogate(int leadingSurrogate, int nextCodeUnit) { | |
| 104 int byteIndex = _bufferIndex; | |
|
Søren Gjesse
2013/07/23 14:22:47
Why this local variable?
floitsch
2013/07/23 14:41:07
Initially I sent the byteIndex as argument. But it
| |
| 105 if (_isTailSurrogate(nextCodeUnit)) { | |
| 106 int rune = _combineSurrogatePair(leadingSurrogate, nextCodeUnit); | |
| 107 // If the rune is encoded with 2 code-units then it must be encoded | |
| 108 // with 4 bytes in UTF-8. | |
| 109 assert(rune > _THREE_BYTE_LIMIT); | |
| 110 assert(rune <= _FOUR_BYTE_LIMIT); | |
| 111 _buffer[byteIndex++] = 0xF0 | (rune >> 18); | |
| 112 _buffer[byteIndex++] = 0x80 | ((rune >> 12) & 0x3f); | |
| 113 _buffer[byteIndex++] = 0x80 | ((rune >> 6) & 0x3f); | |
| 114 _buffer[byteIndex++] = 0x80 | (rune & 0x3f); | |
| 115 _bufferIndex = byteIndex; | |
| 116 return true; | |
| 117 } else { | |
| 118 // TODO(floitsch): allow to throw on malformed strings. | |
| 119 // Encode the half-surrogate directly into UTF-8. This yields | |
| 120 // invalid UTF-8, but we started out with invalid UTF-16. | |
| 121 | |
| 122 // Surrogates are always encoded in 3 bytes in UTF-8. | |
| 123 _buffer[byteIndex++] = 0xE0 | (leadingSurrogate >> 12); | |
| 124 _buffer[byteIndex++] = 0x80 | ((leadingSurrogate >> 6) & 0x3f); | |
| 125 _buffer[byteIndex++] = 0x80 | (leadingSurrogate & 0x3f); | |
| 126 _bufferIndex = byteIndex; | |
| 127 return false; | |
| 128 } | |
| 129 } | |
| 130 | |
| 131 /** | |
| 132 * Fills the [_buffer] with as many characters as possible. | |
| 133 * | |
| 134 * Does not encode any trailing lead-surrogate. This must be done by the | |
| 135 * caller. | |
| 136 * | |
| 137 * Returns the position in the string. The returned index points to the | |
| 138 * first code unit that hasn't been encoded. | |
| 139 */ | |
| 140 int _fillBuffer(String str, int start, int end) { | |
| 141 if (start != end && _isLeadSurrogate(str.codeUnitAt(end - 1))) { | |
| 142 // Don't handle a trailing lead-surrogate in this loop. The caller has | |
| 143 // to deal with those. | |
| 144 end--; | |
| 145 } | |
| 146 int stringIndex; | |
| 147 for (stringIndex = start; stringIndex < end; stringIndex++) { | |
| 148 int codeUnit = str.codeUnitAt(stringIndex); | |
| 149 // ASCII has the same representation in UTF-8 and UTF-16. | |
| 150 if (codeUnit < _ONE_BYTE_LIMIT) { | |
| 151 if (_bufferIndex >= _buffer.length) break; | |
| 152 _buffer[_bufferIndex++] = codeUnit; | |
| 153 } else if (_isLeadSurrogate(codeUnit)) { | |
| 154 if (_bufferIndex + 3 >= _buffer.length) break; | |
| 155 // Note that it is safe to read the next code unit. We decremented | |
| 156 // [end] above when the last valid code unit was a leading surrogate. | |
| 157 int nextCodeUnit = str.codeUnitAt(stringIndex + 1); | |
| 158 bool wasCombined = _writeSurrogate(codeUnit, nextCodeUnit); | |
| 159 if (wasCombined) stringIndex++; | |
| 160 } else { | |
| 161 int rune = codeUnit; | |
| 162 if (rune <= _TWO_BYTE_LIMIT) { | |
| 163 if (_bufferIndex + 1 >= _buffer.length) break; | |
| 164 _buffer[_bufferIndex++] = 0xC0 | (rune >> 6); | |
| 165 _buffer[_bufferIndex++] = 0x80 | (rune & 0x3f); | |
| 166 } else { | |
| 167 assert(rune <= _THREE_BYTE_LIMIT); | |
| 168 if (_bufferIndex + 2 >= _buffer.length) break; | |
| 169 _buffer[_bufferIndex++] = 0xE0 | (rune >> 12); | |
| 170 _buffer[_bufferIndex++] = 0x80 | ((rune >> 6) & 0x3f); | |
| 171 _buffer[_bufferIndex++] = 0x80 | (rune & 0x3f); | |
| 172 } | |
| 173 } | |
| 174 } | |
| 175 return stringIndex; | |
| 176 } | |
| 177 } | |
| 178 | |
| 179 /** | |
| 180 * This class converts UTF-8 code units (lists of unsigned 8-bit integers) | |
| 66 * to a string. | 181 * to a string. |
| 67 */ | 182 */ |
| 68 class Utf8Decoder extends Converter<List<int>, String> { | 183 class Utf8Decoder extends Converter<List<int>, String> { |
| 69 final bool _allowMalformed; | 184 final bool _allowMalformed; |
| 70 | 185 |
| 71 /** | 186 /** |
| 72 * Instantiates a new [Utf8Decoder]. | 187 * Instantiates a new [Utf8Decoder]. |
| 73 * | 188 * |
| 74 * The optional [allowMalformed] argument defines how [convert] deals | 189 * The optional [allowMalformed] argument defines how [convert] deals |
| 75 * with invalid or unterminated character sequences. | 190 * with invalid or unterminated character sequences. |
| (...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 243 } | 358 } |
| 244 break loop; | 359 break loop; |
| 245 } | 360 } |
| 246 if (expectedUnits > 0) { | 361 if (expectedUnits > 0) { |
| 247 _value = value; | 362 _value = value; |
| 248 _expectedUnits = expectedUnits; | 363 _expectedUnits = expectedUnits; |
| 249 _extraUnits = extraUnits; | 364 _extraUnits = extraUnits; |
| 250 } | 365 } |
| 251 } | 366 } |
| 252 } | 367 } |
| OLD | NEW |