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

Side by Side Diff: utils/string_encoding/utf32.dart

Issue 9410001: restructure string decoding to support iterable use and include benchmarks for UTF-8 decoding. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: "stop using introduced variable _length. Improve docs. Created 8 years, 10 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 | « utils/string_encoding/utf16.dart ('k') | utils/string_encoding/utf8_impl.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) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, 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("utf32"); 5 #library("utf32");
6 #import("unicode_core.dart"); 6 #import("unicode_core.dart");
7 #import("unicode.dart"); 7 #import("unicode.dart");
8 8
9 /** 9 /**
10 * Decodes the UTF-32 bytes as an iterable. Thus, the consumer can only convert
11 * as much of the input as needed. Determines the byte order from the BOM,
12 * or uses big-endian as a default. This method always strips a leading BOM.
13 * Set the replacementCharacter to null to throw an IllegalArgumentException
14 * rather than replace the bad value.
15 */
16 IterableUtf32Decoder decodeUtf32AsIterable(List<int> bytes, [
17 int offset = 0, int length,
18 int replacementCodepoint = UNICODE_REPLACEMENT_CHARACTER_CODEPOINT]) {
19 return new IterableUtf32Decoder._(
20 () => new Utf32BytesDecoder(bytes, offset, length, replacementCodepoint));
21 }
22
23 /**
24 * Decodes the UTF-32BE bytes as an iterable. Thus, the consumer can only conver t
25 * as much of the input as needed. This method strips a leading BOM by default,
26 * but can be overridden by setting the optional parameter [stripBom] to false.
27 * Set the replacementCharacter to null to throw an IllegalArgumentException
28 * rather than replace the bad value.
29 */
30 IterableUtf32Decoder decodeUtf32beAsIterable(List<int> bytes, [
31 int offset = 0, int length, bool stripBom = true,
32 int replacementCodepoint = UNICODE_REPLACEMENT_CHARACTER_CODEPOINT]) {
33 return new IterableUtf32Decoder._(
34 () => new Utf32beBytesDecoder(bytes, offset, length, stripBom,
35 replacementCodepoint));
36 }
37
38 /**
39 * Decodes the UTF-32LE bytes as an iterable. Thus, the consumer can only conver t
40 * as much of the input as needed. This method strips a leading BOM by default,
41 * but can be overridden by setting the optional parameter [stripBom] to false.
42 * Set the replacementCharacter to null to throw an IllegalArgumentException
43 * rather than replace the bad value.
44 */
45 IterableUtf32Decoder decodeUtf32leAsIterable(List<int> bytes, [
46 int offset = 0, int length, bool stripBom = true,
47 int replacementCodepoint = UNICODE_REPLACEMENT_CHARACTER_CODEPOINT]) {
48 return new IterableUtf32Decoder._(
49 () => new Utf32leBytesDecoder(bytes, offset, length, stripBom,
50 replacementCodepoint));
51 }
52
53 /**
10 * Produce a String from a sequence of UTF-32 encoded bytes. The parameters 54 * Produce a String from a sequence of UTF-32 encoded bytes. The parameters
11 * allow an offset into a list of bytes (as int), limiting the length of the 55 * allow an offset into a list of bytes (as int), limiting the length of the
12 * values be decoded and the ability of override the default Unicode 56 * values be decoded and the ability of override the default Unicode
13 * replacement character. Set the replacementCharacter to null to throw an 57 * replacement character. Set the replacementCharacter to null to throw an
14 * IllegalArgumentException rather than replace the bad value. 58 * IllegalArgumentException rather than replace the bad value.
15 */ 59 */
16 String decodeFromUtf32(List<int> bytes, [int offset = 0, int length, 60 String decodeUtf32(List<int> bytes, [int offset = 0, int length,
17 int replacementCodepoint = UNICODE_REPLACEMENT_CHARACTER_CODEPOINT]) => 61 int replacementCodepoint = UNICODE_REPLACEMENT_CHARACTER_CODEPOINT]) {
18 codepointsToString(_utf32ToCodePoints(bytes, offset, length, 62 return codepointsToString((new Utf32BytesDecoder(bytes, offset, length,
19 replacementCodepoint)); 63 replacementCodepoint)).decodeRest());
20 64 }
21 /** 65 /**
22 * Produce a String from a sequence of UTF-32BE encoded bytes. The parameters 66 * Produce a String from a sequence of UTF-32BE encoded bytes. The parameters
23 * allow an offset into a list of bytes (as int), limiting the length of the 67 * allow an offset into a list of bytes (as int), limiting the length of the
24 * values be decoded and the ability of override the default Unicode 68 * values be decoded and the ability of override the default Unicode
25 * replacement character. Set the replacementCharacter to null to throw an 69 * replacement character. Set the replacementCharacter to null to throw an
26 * IllegalArgumentException rather than replace the bad value. 70 * IllegalArgumentException rather than replace the bad value.
27 */ 71 */
28 String decodeFromUtf32be( 72 String decodeUtf32be(
29 List<int> bytes, [int offset = 0, int length, bool stripBom = true, 73 List<int> bytes, [int offset = 0, int length, bool stripBom = true,
30 int replacementCodepoint = UNICODE_REPLACEMENT_CHARACTER_CODEPOINT]) => 74 int replacementCodepoint = UNICODE_REPLACEMENT_CHARACTER_CODEPOINT]) =>
31 codepointsToString(_utf32beToCodePoints(bytes, offset, length, stripBom, 75 codepointsToString((new Utf32beBytesDecoder(bytes, offset, length, stripBom,
32 replacementCodepoint)); 76 replacementCodepoint)).decodeRest());
33 77
34 /** 78 /**
35 * Produce a String from a sequence of UTF-32LE encoded bytes. The parameters 79 * Produce a String from a sequence of UTF-32LE encoded bytes. The parameters
36 * allow an offset into a list of bytes (as int), limiting the length of the 80 * allow an offset into a list of bytes (as int), limiting the length of the
37 * values be decoded and the ability of override the default Unicode 81 * values be decoded and the ability of override the default Unicode
38 * replacement character. Set the replacementCharacter to null to throw an 82 * replacement character. Set the replacementCharacter to null to throw an
39 * IllegalArgumentException rather than replace the bad value. 83 * IllegalArgumentException rather than replace the bad value.
40 */ 84 */
41 String decodeFromUtf32le( 85 String decodeUtf32le(
42 List<int> bytes, [int offset = 0, int length, bool stripBom = true, 86 List<int> bytes, [int offset = 0, int length, bool stripBom = true,
43 int replacementCodepoint = UNICODE_REPLACEMENT_CHARACTER_CODEPOINT]) => 87 int replacementCodepoint = UNICODE_REPLACEMENT_CHARACTER_CODEPOINT]) =>
44 codepointsToString(_utf32leToCodePoints(bytes, offset, length, stripBom, 88 codepointsToString((new Utf32leBytesDecoder(bytes, offset, length, stripBom,
45 replacementCodepoint)); 89 replacementCodepoint)).decodeRest());
46 90
47 /** 91 /**
48 * Produce a sequence of UTF-32 encoded bytes. 92 * Produce a list of UTF-32 encoded bytes. This method prefixes the resulting
93 * bytes with a big-endian byte-order-marker.
49 */ 94 */
50 List<int> encodeAsUtf32(String str) => 95 List<int> encodeUtf32(String str) =>
51 encodeAsUtf32be(str, true); 96 encodeUtf32be(str, true);
52 97
53 /** 98 /**
54 * Produce a sequence of UTF-32BE encoded bytes. 99 * Produce a list of UTF-32BE encoded bytes. By default, this method produces
100 * UTF-32BE bytes with no BOM.
55 */ 101 */
56 List<int> encodeAsUtf32be(String str, [bool writeBOM = false]) { 102 List<int> encodeUtf32be(String str, [bool writeBOM = false]) {
57 List<int> utf32CodeUnits = stringToCodepoints(str); 103 List<int> utf32CodeUnits = stringToCodepoints(str);
58 List<int> encoding = new List<int>(4 * utf32CodeUnits.length + 104 List<int> encoding = new List<int>(4 * utf32CodeUnits.length +
59 (writeBOM ? 4 : 0)); 105 (writeBOM ? 4 : 0));
60 int i = 0; 106 int i = 0;
61 if (writeBOM) { 107 if (writeBOM) {
62 encoding[i++] = 0; 108 encoding[i++] = 0;
63 encoding[i++] = 0; 109 encoding[i++] = 0;
64 encoding[i++] = UNICODE_UTF_BOM_HI; 110 encoding[i++] = UNICODE_UTF_BOM_HI;
65 encoding[i++] = UNICODE_UTF_BOM_LO; 111 encoding[i++] = UNICODE_UTF_BOM_LO;
66 } 112 }
67 for (int unit in utf32CodeUnits) { 113 for (int unit in utf32CodeUnits) {
68 encoding[i++] = (unit >> 24) & UNICODE_BYTE_ZERO_MASK; 114 encoding[i++] = (unit >> 24) & UNICODE_BYTE_ZERO_MASK;
69 encoding[i++] = (unit >> 16) & UNICODE_BYTE_ZERO_MASK; 115 encoding[i++] = (unit >> 16) & UNICODE_BYTE_ZERO_MASK;
70 encoding[i++] = (unit >> 8) & UNICODE_BYTE_ZERO_MASK; 116 encoding[i++] = (unit >> 8) & UNICODE_BYTE_ZERO_MASK;
71 encoding[i++] = unit & UNICODE_BYTE_ZERO_MASK; 117 encoding[i++] = unit & UNICODE_BYTE_ZERO_MASK;
72 } 118 }
73 return encoding; 119 return encoding;
74 } 120 }
75 121
76 /** 122 /**
77 * Produce a sequence of UTF-32LE encoded bytes. 123 * Produce a list of UTF-32LE encoded bytes. By default, this method produces
124 * UTF-32BE bytes with no BOM.
78 */ 125 */
79 List<int> encodeAsUtf32le(String str, [bool writeBOM = false]) { 126 List<int> encodeUtf32le(String str, [bool writeBOM = false]) {
80 List<int> utf32CodeUnits = stringToCodepoints(str); 127 List<int> utf32CodeUnits = stringToCodepoints(str);
81 List<int> encoding = new List<int>(4 * utf32CodeUnits.length + 128 List<int> encoding = new List<int>(4 * utf32CodeUnits.length +
82 (writeBOM ? 4 : 0)); 129 (writeBOM ? 4 : 0));
83 int i = 0; 130 int i = 0;
84 if (writeBOM) { 131 if (writeBOM) {
85 encoding[i++] = UNICODE_UTF_BOM_LO; 132 encoding[i++] = UNICODE_UTF_BOM_LO;
86 encoding[i++] = UNICODE_UTF_BOM_HI; 133 encoding[i++] = UNICODE_UTF_BOM_HI;
87 encoding[i++] = 0; 134 encoding[i++] = 0;
88 encoding[i++] = 0; 135 encoding[i++] = 0;
89 } 136 }
90 for (int unit in utf32CodeUnits) { 137 for (int unit in utf32CodeUnits) {
91 encoding[i++] = unit & UNICODE_BYTE_ZERO_MASK; 138 encoding[i++] = unit & UNICODE_BYTE_ZERO_MASK;
92 encoding[i++] = (unit >> 8) & UNICODE_BYTE_ZERO_MASK; 139 encoding[i++] = (unit >> 8) & UNICODE_BYTE_ZERO_MASK;
93 encoding[i++] = (unit >> 16) & UNICODE_BYTE_ZERO_MASK; 140 encoding[i++] = (unit >> 16) & UNICODE_BYTE_ZERO_MASK;
94 encoding[i++] = (unit >> 24) & UNICODE_BYTE_ZERO_MASK; 141 encoding[i++] = (unit >> 24) & UNICODE_BYTE_ZERO_MASK;
95 } 142 }
96 return encoding; 143 return encoding;
97 } 144 }
98 145
146 /**
147 * Identifies whether a List of bytes starts (based on offset) with a
148 * byte-order marker (BOM).
149 */
99 bool hasUtf32Bom( 150 bool hasUtf32Bom(
100 List<int> utf32EncodedBytes, [int offset = 0, int length]) { 151 List<int> utf32EncodedBytes, [int offset = 0, int length]) {
101 return hasUtf32beBom(utf32EncodedBytes, offset, length) || 152 return hasUtf32beBom(utf32EncodedBytes, offset, length) ||
102 hasUtf32leBom(utf32EncodedBytes, offset, length); 153 hasUtf32leBom(utf32EncodedBytes, offset, length);
103 } 154 }
104 155
156 /**
157 * Identifies whether a List of bytes starts (based on offset) with a
158 * big-endian byte-order marker (BOM).
159 */
105 bool hasUtf32beBom(List<int> utf32EncodedBytes, [int offset = 0, int length]) { 160 bool hasUtf32beBom(List<int> utf32EncodedBytes, [int offset = 0, int length]) {
106 if (!(offset >= 0)) { 161 int end = length != null ? offset + length : utf32EncodedBytes.length;
107 throw new IllegalArgumentException("offset");
108 }
109
110 if (!(length == null || length >= 0)) {
111 throw new IllegalArgumentException("length");
112 }
113
114 int end = length != null ?
115 Math.min(utf32EncodedBytes.length, offset + length) :
116 utf32EncodedBytes.length;
117
118 return (offset + 4) <= end && 162 return (offset + 4) <= end &&
119 utf32EncodedBytes[offset] == 0 && 163 utf32EncodedBytes[offset] == 0 && utf32EncodedBytes[offset + 1] == 0 &&
120 utf32EncodedBytes[offset + 1] == 0 &&
121 utf32EncodedBytes[offset + 2] == UNICODE_UTF_BOM_HI && 164 utf32EncodedBytes[offset + 2] == UNICODE_UTF_BOM_HI &&
122 utf32EncodedBytes[offset + 3] == UNICODE_UTF_BOM_LO; 165 utf32EncodedBytes[offset + 3] == UNICODE_UTF_BOM_LO;
123 } 166 }
124 167
168 /**
169 * Identifies whether a List of bytes starts (based on offset) with a
170 * little-endian byte-order marker (BOM).
171 */
125 bool hasUtf32leBom(List<int> utf32EncodedBytes, [int offset = 0, int length]) { 172 bool hasUtf32leBom(List<int> utf32EncodedBytes, [int offset = 0, int length]) {
126 if (!(offset >= 0)) { 173 int end = length != null ? offset + length : utf32EncodedBytes.length;
127 throw new IllegalArgumentException("offset");
128 }
129
130 if (!(length == null || length >= 0)) {
131 throw new IllegalArgumentException("length");
132 }
133
134 int end = length != null ?
135 Math.min(utf32EncodedBytes.length, offset + length) :
136 utf32EncodedBytes.length;
137
138 return (offset + 4) <= end && 174 return (offset + 4) <= end &&
139 utf32EncodedBytes[offset] == UNICODE_UTF_BOM_LO && 175 utf32EncodedBytes[offset] == UNICODE_UTF_BOM_LO &&
140 utf32EncodedBytes[offset + 1] == UNICODE_UTF_BOM_HI && 176 utf32EncodedBytes[offset + 1] == UNICODE_UTF_BOM_HI &&
141 utf32EncodedBytes[offset + 2] == 0 && 177 utf32EncodedBytes[offset + 2] == 0 && utf32EncodedBytes[offset + 3] == 0;
142 utf32EncodedBytes[offset + 3] == 0;
143 } 178 }
144 179
145 void _addReplacementCodepoint(List<int> codepointBuffer, int offset, 180 /**
146 int replacementCodepoint) { 181 * Return type of [decodeUtf32AsIterable] and variants. The Iterable type
147 if(replacementCodepoint != null) { 182 * provides an iterator on demand and the iterator will only translate bytes
148 codepointBuffer[offset] = replacementCodepoint; 183 * as requested by the user of the iterator. (Note: results are not cached.)
149 } else { 184 */
150 throw new IllegalArgumentException("Invalid encoding"); 185 class IterableUtf32Decoder implements Iterable<int> {
186 final Function codeunitsProvider;
187
188 IterableUtf32Decoder._(Function this.codeunitsProvider);
189
190 Utf32BytesDecoder iterator() => codeunitsProvider();
191 }
192
193 /**
194 * Abstrace parent class converts encoded bytes to codepoints.
195 */
196 class Utf32BytesDecoder implements ListRangeIterator<int> {
197 final ListRangeIterator<int> utf32EncodedBytesIterator;
198 final int replacementCodepoint;
199
200 Utf32BytesDecoder._fromListRangeIterator(
201 ListRangeIterator<int> this.utf32EncodedBytesIterator,
202 int this.replacementCodepoint);
203
204 factory Utf32BytesDecoder(List<int> utf32EncodedBytes, [
205 int offset = 0, int length,
206 int replacementCodepoint = UNICODE_REPLACEMENT_CHARACTER_CODEPOINT]) {
207 if (length == null) {
208 length = utf32EncodedBytes.length - offset;
209 }
210 if (hasUtf32beBom(utf32EncodedBytes, offset, length)) {
211 return new Utf32beBytesDecoder(utf32EncodedBytes, offset + 4, length - 4,
212 false, replacementCodepoint);
213 } else if (hasUtf32leBom(utf32EncodedBytes, offset, length)) {
214 return new Utf32leBytesDecoder(utf32EncodedBytes, offset + 4, length - 4,
215 false, replacementCodepoint);
216 } else {
217 return new Utf32beBytesDecoder(utf32EncodedBytes, offset, length, false,
218 replacementCodepoint);
219 }
220 }
221
222 List<int> decodeRest() {
223 List<int> codeunits = new List<int>(remaining);
224 int i = 0;
225 while (hasNext()) {
226 codeunits[i++] = next();
227 }
228 return codeunits;
229 }
230
231 bool hasNext() => utf32EncodedBytesIterator.hasNext();
232
233 int next() {
234 if (utf32EncodedBytesIterator.remaining < 4) {
235 utf32EncodedBytesIterator.skip(utf32EncodedBytesIterator.remaining);
236 if (replacementCodepoint != null) {
237 return replacementCodepoint;
238 } else {
239 throw new IllegalArgumentException(
240 "Invalid UTF32 at ${utf32EncodedBytesIterator.position}");
241 }
242 } else {
243 int codepoint = decode();
244 if (_validCodepoint(codepoint)) {
245 return codepoint;
246 } else if (replacementCodepoint != null) {
247 return replacementCodepoint;
248 } else {
249 throw new IllegalArgumentException(
250 "Invalid UTF32 at ${utf32EncodedBytesIterator.position}");
251 }
252 }
253 }
254
255 int get position() => utf32EncodedBytesIterator.position ~/ 4;
256
257 void backup([int by = 1]) {
258 utf32EncodedBytesIterator.backup(4 * by);
259 }
260
261 int get remaining() => (utf32EncodedBytesIterator.remaining + 3) ~/ 4;
262
263 void skip([int count = 1]) {
264 utf32EncodedBytesIterator.skip(4 * count);
265 }
266
267 abstract int decode();
268 }
269
270 /**
271 * Convert UTF-32BE encoded bytes to codepoints by grouping 4 bytes
272 * to produce the unicode codepoint.
273 */
274 class Utf32beBytesDecoder extends Utf32BytesDecoder {
275 Utf32beBytesDecoder(List<int> utf32EncodedBytes, [int offset = 0,
276 int length, bool stripBom = true,
277 int replacementCodepoint = UNICODE_REPLACEMENT_CHARACTER_CODEPOINT]) :
278 super._fromListRangeIterator((new ListRange(utf32EncodedBytes, offset,
279 length)).iterator(), replacementCodepoint) {
280 if (stripBom && hasUtf32beBom(utf32EncodedBytes, offset, length)) {
281 skip();
282 }
283 }
284
285 int decode() {
286 int value = utf32EncodedBytesIterator.next();
287 value = (value << 8) + utf32EncodedBytesIterator.next();
288 value = (value << 8) + utf32EncodedBytesIterator.next();
289 value = (value << 8) + utf32EncodedBytesIterator.next();
290 return value;
151 } 291 }
152 } 292 }
153 293
154 int _sizeCodepoints(int utf32BytesLength) =>
155 ((utf32BytesLength)/4).ceil().toInt();
156
157 /** 294 /**
158 * Joins groups of 4 bytes (0-255) UTF-32BE to produce single code points. 295 * Convert UTF-32BE encoded bytes to codepoints by grouping 4 bytes
296 * to produce the unicode codepoint.
159 */ 297 */
160 List<int> _utf32beToCodePoints( 298 class Utf32leBytesDecoder extends Utf32BytesDecoder {
161 List<int> utf32beEncodedBytes, [int offset = 0, int length, 299 Utf32leBytesDecoder(List<int> utf32EncodedBytes, [int offset = 0,
162 bool stripBom = true, 300 int length, bool stripBom = true,
163 int replacementCodepoint = UNICODE_REPLACEMENT_CHARACTER_CODEPOINT]) { 301 int replacementCodepoint = UNICODE_REPLACEMENT_CHARACTER_CODEPOINT]) :
164 if (!(offset >= 0)) { 302 super._fromListRangeIterator((new ListRange(utf32EncodedBytes, offset,
165 throw new IllegalArgumentException("offset"); 303 length)).iterator(), replacementCodepoint) {
304 if (stripBom && hasUtf32leBom(utf32EncodedBytes, offset, length)) {
305 skip();
306 }
166 } 307 }
167 308
168 if (!(length == null || length >= 0)) { 309 int decode() {
169 throw new IllegalArgumentException("length"); 310 int value = (utf32EncodedBytesIterator.next());
170 } 311 value += (utf32EncodedBytesIterator.next() << 8);
171 312 value += (utf32EncodedBytesIterator.next() << 16);
172 int end = length != null ? 313 value += (utf32EncodedBytesIterator.next() << 24);
173 Math.min(utf32beEncodedBytes.length, offset + length) : 314 return value;
174 utf32beEncodedBytes.length;
175
176 int i = (stripBom && hasUtf32beBom(utf32beEncodedBytes, offset, length)) ?
177 offset + 4 : offset;
178 int lastIndex = end - 3;
179 List<int> codepoints = new List<int>(_sizeCodepoints(end - i));
180 int j = 0;
181 while (i < lastIndex) {
182 int value = utf32beEncodedBytes[i++];
183 value = (value << 8) + utf32beEncodedBytes[i++];
184 value = (value << 8) + utf32beEncodedBytes[i++];
185 value = (value << 8) + utf32beEncodedBytes[i++];
186 if (_validCodepoint(value)) {
187 codepoints[j++] = value;
188 } else {
189 _addReplacementCodepoint(codepoints, j++, replacementCodepoint);
190 }
191 }
192 while (j < codepoints.length) {
193 _addReplacementCodepoint(codepoints, j++, replacementCodepoint);
194 }
195 return codepoints;
196 }
197
198 /**
199 * Joins groups of 4 bytes (0-255) UTF-32LE to produce single code points.
200 */
201 List<int> _utf32leToCodePoints(
202 List<int> utf32leEncodedBytes, [int offset = 0, int length,
203 bool stripBom = true,
204 int replacementCodepoint = UNICODE_REPLACEMENT_CHARACTER_CODEPOINT]) {
205 if (!(offset >= 0)) {
206 throw new IllegalArgumentException("offset");
207 }
208
209 if (!(length == null || length >= 0)) {
210 throw new IllegalArgumentException("length");
211 }
212
213 int end = length != null ?
214 Math.min(utf32leEncodedBytes.length, offset + length) :
215 utf32leEncodedBytes.length;
216
217 int i = (stripBom && hasUtf32leBom(utf32leEncodedBytes, offset, length)) ?
218 offset + 4 : offset;
219 int lastIndex = end - 3;
220 List<int> codepoints = new List<int>(_sizeCodepoints(end - i));
221 int j = 0;
222 while (i < lastIndex) {
223 int value = utf32leEncodedBytes[i+3];
224 value = (value << 8) + utf32leEncodedBytes[i+2];
225 value = (value << 8) + utf32leEncodedBytes[i+1];
226 value = (value << 8) + utf32leEncodedBytes[i];
227 i += 4;
228 if (_validCodepoint(value)) {
229 codepoints[j++] = value;
230 } else {
231 _addReplacementCodepoint(codepoints, j++, replacementCodepoint);
232 }
233 }
234 while (j < codepoints.length) {
235 _addReplacementCodepoint(codepoints, j++, replacementCodepoint);
236 }
237 return codepoints;
238 }
239
240 /**
241 * Joins groups of 4 bytes (0-255) UTF-32 to produce single code points.
242 */
243 List<int> _utf32ToCodePoints(List<int> utf32EncodedBytes, [int offset = 0,
244 int length,
245 int replacementCodepoint = UNICODE_REPLACEMENT_CHARACTER_CODEPOINT]) {
246 if (!(offset >= 0)) {
247 throw new IllegalArgumentException("offset");
248 }
249
250 if (!(length == null || length >= 0)) {
251 throw new IllegalArgumentException("length");
252 }
253
254 int end = length != null ?
255 Math.min(utf32EncodedBytes.length, offset + length) :
256 utf32EncodedBytes.length;
257
258 if (hasUtf32beBom(utf32EncodedBytes, offset, length)) {
259 return _utf32beToCodePoints(utf32EncodedBytes, offset + 4,
260 end - (offset + 4), false);
261 } else if (hasUtf32leBom(utf32EncodedBytes, offset, length)) {
262 return _utf32leToCodePoints(utf32EncodedBytes, offset + 4,
263 end - (offset + 4), false);
264 } else {
265 return _utf32beToCodePoints(utf32EncodedBytes, offset, end - offset);
266 } 315 }
267 } 316 }
268 317
269 bool _validCodepoint(int codepoint) { 318 bool _validCodepoint(int codepoint) {
270 return (codepoint >= 0 && codepoint < UNICODE_UTF16_RESERVED_LO) || 319 return (codepoint >= 0 && codepoint < UNICODE_UTF16_RESERVED_LO) ||
271 (codepoint > UNICODE_UTF16_RESERVED_HI && 320 (codepoint > UNICODE_UTF16_RESERVED_HI &&
272 codepoint < UNICODE_VALID_RANGE_MAX); 321 codepoint < UNICODE_VALID_RANGE_MAX);
273 } 322 }
OLDNEW
« no previous file with comments | « utils/string_encoding/utf16.dart ('k') | utils/string_encoding/utf8_impl.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698