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

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

Issue 9462001: Unify most of our utf8 implementations. This takes the implementation (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: 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 | « utils/string_encoding/unicode_core.dart ('k') | utils/string_encoding/utf32.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 #library("utf16");
6 #import("unicode_core.dart");
7 #import("unicode.dart");
8
9 /**
10 * Decodes the UTF-16 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 [replacementCodepoint] to null to throw an IllegalArgumentException
14 * rather than replace the bad value. The default value for
15 * [replacementCodepoint] is U+FFFD.
16 */
17 IterableUtf16Decoder decodeUtf16AsIterable(List<int> bytes, [int offset = 0,
18 int length, int replacementCodepoint =
19 UNICODE_REPLACEMENT_CHARACTER_CODEPOINT]) {
20 return new IterableUtf16Decoder._(
21 () => new Utf16BytesToCodeUnitsDecoder(bytes, offset, length,
22 replacementCodepoint), replacementCodepoint);
23 }
24
25 /**
26 * Decodes the UTF-16BE bytes as an iterable. Thus, the consumer can only
27 * convert as much of the input as needed. This method strips a leading BOM by
28 * default, but can be overridden by setting the optional parameter [stripBom]
29 * to false. Set the [replacementCodepoint] to null to throw an
30 * IllegalArgumentException rather than replace the bad value. The default
31 * value for the [replacementCodepoint] is U+FFFD.
32 */
33 IterableUtf16Decoder decodeUtf16beAsIterable(List<int> bytes, [int offset = 0,
34 int length, bool stripBom = true, int replacementCodepoint =
35 UNICODE_REPLACEMENT_CHARACTER_CODEPOINT]) {
36 return new IterableUtf16Decoder._(
37 () => new Utf16beBytesToCodeUnitsDecoder(bytes, offset, length, stripBom,
38 replacementCodepoint), replacementCodepoint);
39 }
40
41 /**
42 * Decodes the UTF-16LE bytes as an iterable. Thus, the consumer can only
43 * convert as much of the input as needed. This method strips a leading BOM by
44 * default, but can be overridden by setting the optional parameter [stripBom]
45 * to false. Set the [replacementCodepoint] to null to throw an
46 * IllegalArgumentException rather than replace the bad value. The default
47 * value for the [replacementCodepoint] is U+FFFD.
48 */
49 IterableUtf16Decoder decodeUtf16leAsIterable(List<int> bytes, [int offset = 0,
50 int length, bool stripBom = true, int replacementCodepoint =
51 UNICODE_REPLACEMENT_CHARACTER_CODEPOINT]) {
52 return new IterableUtf16Decoder._(
53 () => new Utf16leBytesToCodeUnitsDecoder(bytes, offset, length, stripBom,
54 replacementCodepoint), replacementCodepoint);
55 }
56
57 /**
58 * Produce a String from a sequence of UTF-16 encoded bytes. This method always
59 * strips a leading BOM. Set the [replacementCodepoint] to null to throw an
60 * IllegalArgumentException rather than replace the bad value. The default
61 * value for the [replacementCodepoint] is U+FFFD.
62 */
63 String decodeUtf16(List<int> bytes, [int offset = 0, int length,
64 int replacementCodepoint = UNICODE_REPLACEMENT_CHARACTER_CODEPOINT]) {
65 Utf16BytesToCodeUnitsDecoder decoder = new Utf16BytesToCodeUnitsDecoder(bytes,
66 offset, length, replacementCodepoint);
67 List<int> codeunits = decoder.decodeRest();
68 // TODO is16BitCodeUnit() is used to work around a bug with frog/dartc
69 // (http://code.google.com/p/dart/issues/detail?id=1357). Consider
70 // removing after this issue is resolved.
71 if (is16BitCodeUnit()) {
72 return new String.fromCharCodes(codeunits);
73 } else {
74 return new String.fromCharCodes(
75 utf16CodeUnitsToCodepoints(codeunits, 0, null, replacementCodepoint));
76 }
77 }
78
79 /**
80 * Produce a String from a sequence of UTF-16BE encoded bytes. This method
81 * strips a leading BOM by default, but can be overridden by setting the
82 * optional parameter [stripBom] to false. Set the [replacementCodepoint] to
83 * null to throw an IllegalArgumentException rather than replace the bad value.
84 * The default value for the [replacementCodepoint] is U+FFFD.
85 */
86 String decodeUtf16be(List<int> bytes, [int offset = 0, int length,
87 bool stripBom = true,
88 int replacementCodepoint = UNICODE_REPLACEMENT_CHARACTER_CODEPOINT]) {
89 List<int> codeunits = (new Utf16beBytesToCodeUnitsDecoder(bytes, offset,
90 length, stripBom, replacementCodepoint)).decodeRest();
91 // TODO is16BitCodeUnit() is used to work around a bug with frog/dartc
92 // (http://code.google.com/p/dart/issues/detail?id=1357). Consider
93 // removing after this issue is resolved.
94 if (is16BitCodeUnit()) {
95 return new String.fromCharCodes(codeunits);
96 } else {
97 return new String.fromCharCodes(
98 utf16CodeUnitsToCodepoints(codeunits, 0, null, replacementCodepoint));
99 }
100 }
101
102 /**
103 * Produce a String from a sequence of UTF-16LE encoded bytes. This method
104 * strips a leading BOM by default, but can be overridden by setting the
105 * optional parameter [stripBom] to false. Set the [replacementCodepoint] to
106 * null to throw an IllegalArgumentException rather than replace the bad value.
107 * The default value for the [replacementCodepoint] is U+FFFD.
108 */
109 String decodeUtf16le(List<int> bytes, [int offset = 0, int length,
110 bool stripBom = true,
111 int replacementCodepoint = UNICODE_REPLACEMENT_CHARACTER_CODEPOINT]) {
112 List<int> codeunits = (new Utf16leBytesToCodeUnitsDecoder(bytes, offset,
113 length, stripBom, replacementCodepoint)).decodeRest();
114 // TODO is16BitCodeUnit() is used to work around a bug with frog/dartc
115 // (http://code.google.com/p/dart/issues/detail?id=1357). Consider
116 // removing after this issue is resolved.
117 if (is16BitCodeUnit()) {
118 return new String.fromCharCodes(codeunits);
119 } else {
120 return new String.fromCharCodes(
121 utf16CodeUnitsToCodepoints(codeunits, 0, null, replacementCodepoint));
122 }
123 }
124
125 /**
126 * Produce a list of UTF-16 encoded bytes. This method prefixes the resulting
127 * bytes with a big-endian byte-order-marker.
128 */
129 List<int> encodeUtf16(String str) =>
130 encodeUtf16be(str, true);
131
132 /**
133 * Produce a list of UTF-16BE encoded bytes. By default, this method produces
134 * UTF-16BE bytes with no BOM.
135 */
136 List<int> encodeUtf16be(String str, [bool writeBOM = false]) {
137 List<int> utf16CodeUnits = _stringToUtf16CodeUnits(str);
138 List<int> encoding =
139 new List<int>(2 * utf16CodeUnits.length + (writeBOM ? 2 : 0));
140 int i = 0;
141 if (writeBOM) {
142 encoding[i++] = UNICODE_UTF_BOM_HI;
143 encoding[i++] = UNICODE_UTF_BOM_LO;
144 }
145 for (int unit in utf16CodeUnits) {
146 encoding[i++] = (unit & UNICODE_BYTE_ONE_MASK) >> 8;
147 encoding[i++] = unit & UNICODE_BYTE_ZERO_MASK;
148 }
149 return encoding;
150 }
151
152 /**
153 * Produce a list of UTF-16LE encoded bytes. By default, this method produces
154 * UTF-16LE bytes with no BOM.
155 */
156 List<int> encodeUtf16le(String str, [bool writeBOM = false]) {
157 List<int> utf16CodeUnits = _stringToUtf16CodeUnits(str);
158 List<int> encoding =
159 new List<int>(2 * utf16CodeUnits.length + (writeBOM ? 2 : 0));
160 int i = 0;
161 if (writeBOM) {
162 encoding[i++] = UNICODE_UTF_BOM_LO;
163 encoding[i++] = UNICODE_UTF_BOM_HI;
164 }
165 for (int unit in utf16CodeUnits) {
166 encoding[i++] = unit & UNICODE_BYTE_ZERO_MASK;
167 encoding[i++] = (unit & UNICODE_BYTE_ONE_MASK) >> 8;
168 }
169 return encoding;
170 }
171
172 /**
173 * Identifies whether a List of bytes starts (based on offset) with a
174 * byte-order marker (BOM).
175 */
176 bool hasUtf16Bom(List<int> utf32EncodedBytes, [int offset = 0, int length]) {
177 return hasUtf16beBom(utf32EncodedBytes, offset, length) ||
178 hasUtf16leBom(utf32EncodedBytes, offset, length);
179 }
180
181 /**
182 * Identifies whether a List of bytes starts (based on offset) with a
183 * big-endian byte-order marker (BOM).
184 */
185 bool hasUtf16beBom(List<int> utf16EncodedBytes, [int offset = 0, int length]) {
186 int end = length != null ? offset + length : utf16EncodedBytes.length;
187 return (offset + 2) <= end &&
188 utf16EncodedBytes[offset] == UNICODE_UTF_BOM_HI &&
189 utf16EncodedBytes[offset + 1] == UNICODE_UTF_BOM_LO;
190 }
191
192 /**
193 * Identifies whether a List of bytes starts (based on offset) with a
194 * little-endian byte-order marker (BOM).
195 */
196 bool hasUtf16leBom(List<int> utf16EncodedBytes, [int offset = 0, int length]) {
197 int end = length != null ? offset + length : utf16EncodedBytes.length;
198 return (offset + 2) <= end &&
199 utf16EncodedBytes[offset] == UNICODE_UTF_BOM_LO &&
200 utf16EncodedBytes[offset + 1] == UNICODE_UTF_BOM_HI;
201 }
202
203 List<int> _stringToUtf16CodeUnits(String str) {
204 // TODO is16BitCodeUnit() is used to work around a bug with frog/dartc
205 // (http://code.google.com/p/dart/issues/detail?id=1357). Consider
206 // removing after this issue is resolved.
207 if (is16BitCodeUnit()) {
208 return str.charCodes();
209 } else {
210 return codepointsToUtf16CodeUnits(str.charCodes());
211 }
212 }
213
214 /**
215 * Return type of [decodeUtf16AsIterable] and variants. The Iterable type
216 * provides an iterator on demand and the iterator will only translate bytes
217 * as requested by the user of the iterator. (Note: results are not cached.)
218 */
219 class IterableUtf16Decoder implements Iterable<int> {
220 final Function codeunitsProvider;
221 final int replacementCodepoint;
222
223 IterableUtf16Decoder._(ListRangeIterator<int> this.codeunitsProvider(),
224 int this.replacementCodepoint);
225
226 Utf16CodeUnitDecoder iterator() =>
227 new Utf16CodeUnitDecoder.fromListRangeIterator(codeunitsProvider(),
228 replacementCodepoint);
229 }
230
231 /**
232 * Convert UTF-16 encoded bytes to UTF-16 code units by grouping 1-2 bytes
233 * to produce the code unit (0-(2^16)-1). Relies on BOM to determine
234 * endian-ness, and defaults to BE.
235 */
236 class Utf16BytesToCodeUnitsDecoder implements ListRangeIterator<int> {
237 final ListRangeIterator<int> utf16EncodedBytesIterator;
238 final int replacementCodepoint;
239
240 Utf16BytesToCodeUnitsDecoder._fromListRangeIterator(
241 ListRangeIterator<int> this.utf16EncodedBytesIterator,
242 int this.replacementCodepoint);
243
244 factory Utf16BytesToCodeUnitsDecoder(List<int> utf16EncodedBytes, [
245 int offset = 0, int length,
246 int replacementCodepoint = UNICODE_REPLACEMENT_CHARACTER_CODEPOINT]) {
247 if (length == null) {
248 length = utf16EncodedBytes.length - offset;
249 }
250 if (hasUtf16beBom(utf16EncodedBytes, offset, length)) {
251 return new Utf16beBytesToCodeUnitsDecoder(utf16EncodedBytes, offset + 2,
252 length - 2, false, replacementCodepoint);
253 } else if (hasUtf16leBom(utf16EncodedBytes, offset, length)) {
254 return new Utf16leBytesToCodeUnitsDecoder(utf16EncodedBytes, offset + 2,
255 length - 2, false, replacementCodepoint);
256 } else {
257 return new Utf16beBytesToCodeUnitsDecoder(utf16EncodedBytes, offset,
258 length, false, replacementCodepoint);
259 }
260 }
261
262 /**
263 * Provides a fast way to decode the rest of the source bytes in a single
264 * call. This method trades memory for improved speed in that it potentially
265 * over-allocates the List containing results.
266 */
267 List<int> decodeRest() {
268 List<int> codeunits = new List<int>(remaining);
269 int i = 0;
270 while (hasNext()) {
271 codeunits[i++] = next();
272 }
273 if (i == codeunits.length) {
274 return codeunits;
275 } else {
276 List<int> truncCodeunits = new List<int>(i);
277 truncCodeunits.setRange(0, i, codeunits);
278 return truncCodeunits;
279 }
280 }
281
282 bool hasNext() => utf16EncodedBytesIterator.hasNext();
283
284 int next() {
285 if (utf16EncodedBytesIterator.remaining < 2) {
286 utf16EncodedBytesIterator.next();
287 if (replacementCodepoint != null) {
288 return replacementCodepoint;
289 } else {
290 throw new IllegalArgumentException(
291 "Invalid UTF16 at ${utf16EncodedBytesIterator.position}");
292 }
293 } else {
294 return decode();
295 }
296 }
297
298 int get position() => utf16EncodedBytesIterator.position ~/ 2;
299
300 void backup([int by = 1]) {
301 utf16EncodedBytesIterator.backup(2 * by);
302 }
303
304 int get remaining() => (utf16EncodedBytesIterator.remaining + 1) ~/ 2;
305
306 void skip([int count = 1]) {
307 utf16EncodedBytesIterator.skip(2 * count);
308 }
309
310 abstract int decode();
311 }
312
313 /**
314 * Convert UTF-16BE encoded bytes to utf16 code units by grouping 1-2 bytes
315 * to produce the code unit (0-(2^16)-1).
316 */
317 class Utf16beBytesToCodeUnitsDecoder extends Utf16BytesToCodeUnitsDecoder {
318 Utf16beBytesToCodeUnitsDecoder(List<int> utf16EncodedBytes, [
319 int offset = 0, int length, bool stripBom = true,
320 int replacementCodepoint = UNICODE_REPLACEMENT_CHARACTER_CODEPOINT]) :
321 super._fromListRangeIterator((new ListRange(utf16EncodedBytes, offset,
322 length)).iterator(), replacementCodepoint) {
323 if (stripBom && hasUtf16beBom(utf16EncodedBytes, offset, length)) {
324 skip();
325 }
326 }
327
328 int decode() {
329 int hi = utf16EncodedBytesIterator.next();
330 int lo = utf16EncodedBytesIterator.next();
331 return (hi << 8) + lo;
332 }
333 }
334
335 /**
336 * Convert UTF-16LE encoded bytes to utf16 code units by grouping 1-2 bytes
337 * to produce the code unit (0-(2^16)-1).
338 */
339 class Utf16leBytesToCodeUnitsDecoder extends Utf16BytesToCodeUnitsDecoder {
340 Utf16leBytesToCodeUnitsDecoder(List<int> utf16EncodedBytes, [
341 int offset = 0, int length, bool stripBom = true,
342 int replacementCodepoint = UNICODE_REPLACEMENT_CHARACTER_CODEPOINT]) :
343 super._fromListRangeIterator((new ListRange(utf16EncodedBytes, offset,
344 length)).iterator(), replacementCodepoint) {
345 if (stripBom && hasUtf16leBom(utf16EncodedBytes, offset, length)) {
346 skip();
347 }
348 }
349
350 int decode() {
351 int lo = utf16EncodedBytesIterator.next();
352 int hi = utf16EncodedBytesIterator.next();
353 return (hi << 8) + lo;
354 }
355 }
OLDNEW
« no previous file with comments | « utils/string_encoding/unicode_core.dart ('k') | utils/string_encoding/utf32.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698