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

Side by Side Diff: utils/string_encoding/utf32.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/utf16.dart ('k') | utils/string_encoding/utf8.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("utf32");
6 #import("unicode_core.dart");
7 #import("unicode.dart");
8
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 /**
54 * Produce a String from a sequence of UTF-32 encoded bytes. The parameters
55 * allow an offset into a list of bytes (as int), limiting the length of the
56 * values be decoded and the ability of override the default Unicode
57 * replacement character. Set the replacementCharacter to null to throw an
58 * IllegalArgumentException rather than replace the bad value.
59 */
60 String decodeUtf32(List<int> bytes, [int offset = 0, int length,
61 int replacementCodepoint = UNICODE_REPLACEMENT_CHARACTER_CODEPOINT]) {
62 return codepointsToString((new Utf32BytesDecoder(bytes, offset, length,
63 replacementCodepoint)).decodeRest());
64 }
65 /**
66 * Produce a String from a sequence of UTF-32BE encoded bytes. The parameters
67 * allow an offset into a list of bytes (as int), limiting the length of the
68 * values be decoded and the ability of override the default Unicode
69 * replacement character. Set the replacementCharacter to null to throw an
70 * IllegalArgumentException rather than replace the bad value.
71 */
72 String decodeUtf32be(
73 List<int> bytes, [int offset = 0, int length, bool stripBom = true,
74 int replacementCodepoint = UNICODE_REPLACEMENT_CHARACTER_CODEPOINT]) =>
75 codepointsToString((new Utf32beBytesDecoder(bytes, offset, length, stripBom,
76 replacementCodepoint)).decodeRest());
77
78 /**
79 * Produce a String from a sequence of UTF-32LE encoded bytes. The parameters
80 * allow an offset into a list of bytes (as int), limiting the length of the
81 * values be decoded and the ability of override the default Unicode
82 * replacement character. Set the replacementCharacter to null to throw an
83 * IllegalArgumentException rather than replace the bad value.
84 */
85 String decodeUtf32le(
86 List<int> bytes, [int offset = 0, int length, bool stripBom = true,
87 int replacementCodepoint = UNICODE_REPLACEMENT_CHARACTER_CODEPOINT]) =>
88 codepointsToString((new Utf32leBytesDecoder(bytes, offset, length, stripBom,
89 replacementCodepoint)).decodeRest());
90
91 /**
92 * Produce a list of UTF-32 encoded bytes. This method prefixes the resulting
93 * bytes with a big-endian byte-order-marker.
94 */
95 List<int> encodeUtf32(String str) =>
96 encodeUtf32be(str, true);
97
98 /**
99 * Produce a list of UTF-32BE encoded bytes. By default, this method produces
100 * UTF-32BE bytes with no BOM.
101 */
102 List<int> encodeUtf32be(String str, [bool writeBOM = false]) {
103 List<int> utf32CodeUnits = stringToCodepoints(str);
104 List<int> encoding = new List<int>(4 * utf32CodeUnits.length +
105 (writeBOM ? 4 : 0));
106 int i = 0;
107 if (writeBOM) {
108 encoding[i++] = 0;
109 encoding[i++] = 0;
110 encoding[i++] = UNICODE_UTF_BOM_HI;
111 encoding[i++] = UNICODE_UTF_BOM_LO;
112 }
113 for (int unit in utf32CodeUnits) {
114 encoding[i++] = (unit >> 24) & UNICODE_BYTE_ZERO_MASK;
115 encoding[i++] = (unit >> 16) & UNICODE_BYTE_ZERO_MASK;
116 encoding[i++] = (unit >> 8) & UNICODE_BYTE_ZERO_MASK;
117 encoding[i++] = unit & UNICODE_BYTE_ZERO_MASK;
118 }
119 return encoding;
120 }
121
122 /**
123 * Produce a list of UTF-32LE encoded bytes. By default, this method produces
124 * UTF-32BE bytes with no BOM.
125 */
126 List<int> encodeUtf32le(String str, [bool writeBOM = false]) {
127 List<int> utf32CodeUnits = stringToCodepoints(str);
128 List<int> encoding = new List<int>(4 * utf32CodeUnits.length +
129 (writeBOM ? 4 : 0));
130 int i = 0;
131 if (writeBOM) {
132 encoding[i++] = UNICODE_UTF_BOM_LO;
133 encoding[i++] = UNICODE_UTF_BOM_HI;
134 encoding[i++] = 0;
135 encoding[i++] = 0;
136 }
137 for (int unit in utf32CodeUnits) {
138 encoding[i++] = unit & UNICODE_BYTE_ZERO_MASK;
139 encoding[i++] = (unit >> 8) & UNICODE_BYTE_ZERO_MASK;
140 encoding[i++] = (unit >> 16) & UNICODE_BYTE_ZERO_MASK;
141 encoding[i++] = (unit >> 24) & UNICODE_BYTE_ZERO_MASK;
142 }
143 return encoding;
144 }
145
146 /**
147 * Identifies whether a List of bytes starts (based on offset) with a
148 * byte-order marker (BOM).
149 */
150 bool hasUtf32Bom(
151 List<int> utf32EncodedBytes, [int offset = 0, int length]) {
152 return hasUtf32beBom(utf32EncodedBytes, offset, length) ||
153 hasUtf32leBom(utf32EncodedBytes, offset, length);
154 }
155
156 /**
157 * Identifies whether a List of bytes starts (based on offset) with a
158 * big-endian byte-order marker (BOM).
159 */
160 bool hasUtf32beBom(List<int> utf32EncodedBytes, [int offset = 0, int length]) {
161 int end = length != null ? offset + length : utf32EncodedBytes.length;
162 return (offset + 4) <= end &&
163 utf32EncodedBytes[offset] == 0 && utf32EncodedBytes[offset + 1] == 0 &&
164 utf32EncodedBytes[offset + 2] == UNICODE_UTF_BOM_HI &&
165 utf32EncodedBytes[offset + 3] == UNICODE_UTF_BOM_LO;
166 }
167
168 /**
169 * Identifies whether a List of bytes starts (based on offset) with a
170 * little-endian byte-order marker (BOM).
171 */
172 bool hasUtf32leBom(List<int> utf32EncodedBytes, [int offset = 0, int length]) {
173 int end = length != null ? offset + length : utf32EncodedBytes.length;
174 return (offset + 4) <= end &&
175 utf32EncodedBytes[offset] == UNICODE_UTF_BOM_LO &&
176 utf32EncodedBytes[offset + 1] == UNICODE_UTF_BOM_HI &&
177 utf32EncodedBytes[offset + 2] == 0 && utf32EncodedBytes[offset + 3] == 0;
178 }
179
180 /**
181 * Return type of [decodeUtf32AsIterable] and variants. The Iterable type
182 * provides an iterator on demand and the iterator will only translate bytes
183 * as requested by the user of the iterator. (Note: results are not cached.)
184 */
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;
291 }
292 }
293
294 /**
295 * Convert UTF-32BE encoded bytes to codepoints by grouping 4 bytes
296 * to produce the unicode codepoint.
297 */
298 class Utf32leBytesDecoder extends Utf32BytesDecoder {
299 Utf32leBytesDecoder(List<int> utf32EncodedBytes, [int offset = 0,
300 int length, bool stripBom = true,
301 int replacementCodepoint = UNICODE_REPLACEMENT_CHARACTER_CODEPOINT]) :
302 super._fromListRangeIterator((new ListRange(utf32EncodedBytes, offset,
303 length)).iterator(), replacementCodepoint) {
304 if (stripBom && hasUtf32leBom(utf32EncodedBytes, offset, length)) {
305 skip();
306 }
307 }
308
309 int decode() {
310 int value = (utf32EncodedBytesIterator.next());
311 value += (utf32EncodedBytesIterator.next() << 8);
312 value += (utf32EncodedBytesIterator.next() << 16);
313 value += (utf32EncodedBytesIterator.next() << 24);
314 return value;
315 }
316 }
317
318 bool _validCodepoint(int codepoint) {
319 return (codepoint >= 0 && codepoint < UNICODE_UTF16_RESERVED_LO) ||
320 (codepoint > UNICODE_UTF16_RESERVED_HI &&
321 codepoint < UNICODE_VALID_RANGE_MAX);
322 }
OLDNEW
« no previous file with comments | « utils/string_encoding/utf16.dart ('k') | utils/string_encoding/utf8.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698