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

Side by Side Diff: sdk/lib/convert/utf.dart

Issue 17580014: dart:convert library. Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Update Created 7 years, 5 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 | « sdk/lib/convert/string_converter.dart ('k') | sdk/lib/json/json.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) 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
3 // BSD-style license that can be found in the LICENSE file.
4
5 part of dart.convert;
6
7 // UTF-8 constants.
8 const int _ONE_BYTE_LIMIT = 0x7f; // 7 bytes
9 const int _TWO_BYTE_LIMIT = 0x7ff; // 11 bytes
10 const int _THREE_BYTE_LIMIT = 0xffff; // 16 bytes
11 const int _FOUR_BYTE_LIMIT = 0x10ffff; // 21 bytes, truncated to Unicode max.
12
13 // UTF-16 constants.
14 const int _SURROGATE_MASK = 0xF800;
15 const int _SURROGATE_TAG_MASK = 0xFC00;
16 const int _SURROGATE_VALUE_MASK = 0x3FF;
17 const int _LEAD_SURROGATE_MIN = 0xD800;
18 const int _TAIL_SURROGATE_MIN = 0xDC00;
19
20 bool _isSurrogate(int codeUnit) =>
21 (codeUnit & _SURROGATE_MASK) == _LEAD_SURROGATE_MIN;
22 bool _isLeadSurrogate(int codeUnit) =>
23 (codeUnit & _SURROGATE_TAG_MASK) == _LEAD_SURROGATE_MIN;
24 bool _isTailSurrogate(int codeUnit) =>
25 (codeUnit & _SURROGATE_TAG_MASK) == _TAIL_SURROGATE_MIN;
26 int _combineSurrogatePair(int lead, int tail) =>
27 0x10000 | ((lead & _SURROGATE_VALUE_MASK) << 10)
28 | (tail & _SURROGATE_VALUE_MASK);
29
30
31 class _Utf8EncoderToken { const _Utf8EncoderToken(); }
32
33 class Utf8Encoder extends Converter<String, List<int>> {
34 fuse(Converter other) => other.fuseInput(this);
35 fuseInput(Converter other) => new FusedConverter(other, this);
36
37 Object get id => const _Utf8EncoderToken();
38
39 ChunkedConversionSink startChunkedConversion(ChunkedConversionSink sink) {
40 return new _Utf8EncoderSink(outputInterface.adapt(sink));
41 }
42
43 ChunkedConversionInterface get inputInterface =>
44 StringConversionSink.INTERFACE;
45 ChunkedConversionInterface get outputInterface =>
46 ByteConversionSink.INTERFACE;
47 }
48
49 class _Utf8DecoderToken { const _Utf8DecoderToken(); }
50
51 class Utf8Decoder extends Converter<List<int>, String> {
52 String convert(List<int> input) {
53 Utf8Handler handler = new Utf8Handler();
54 String result = handler.convert(input, 0, input.length);
55 if (handler.hasPartialInput) {
56 throw new ArgumentError("Incomplete UTF8 sequence");
57 }
58 return result;
59 }
60
61 fuse(Converter other) => other.fuseInput(this);
62 fuseInput(Converter other) => new FusedConverter(other, this);
63
64 Object get id => const _Utf8DecoderToken();
65
66 ChunkedConversionSink startChunkedConversion(ChunkedConversionSink sink) {
67 return new _Utf8DecoderSink(outputInterface.adapt(sink));
68 }
69
70 ChunkedConversionInterface get inputInterface =>
71 ByteConversionSink.INTERFACE;
72 ChunkedConversionInterface get outputInterface =>
73 StringConversionSink.INTERFACE;
74
75 }
76
77 class _Utf8DecoderSink extends ByteConversionSinkBase {
78 StringConversionSink _sink;
79 _Utf8DecoderSink(this._sink);
80
81 void addChunk(List<int> input, int start, int end, bool isLast) {
82 _sink.addUtf8(input, start, end, isLast);
83 }
84
85 void add(List<int> input) {
86 _sink.addUtf8(input, 0, input.length, false);
87 }
88
89 void close() => _sink.close();
90 }
91
92 class _Utf8EncoderSink extends StringConversionSinkBase {
93 ByteConversionSink _sink;
94 _Utf8EncoderSink(this._sink);
95
96 void add(String str) => addString(str, false);
97
98 void addString(String str, bool isLast) {
99 // TODO(floitsch): Use an iterator that works directly with codeUnits.
100 _sink.iterateBytes(new _Utf8EncoderIterator(str.runes.iterator), isLast);
101 }
102
103 void addRunes(List<int> runes, int start, int end, bool isLast) {
104 Iterator iterator;
105 if (start == 0 && end == runes.length) {
106 iterator = runes.iterator;
107 } else {
108 iterator = runes.getRange(start, end).iterator;
109 }
110 _sink.iterateBytes(new _Utf8EncoderIterator(iterator), isLast);
111 }
112
113 void addUtf8(List<int> utf8Units, int start, int end, bool isLast) {
114 _sink.addChunk(utf8Units, start, end, isLast);
115 }
116
117 void addAscii(List<int> codeUnits, int start, int end, bool isLast) {
118 _sink.addChunk(codeUnits, start, end, isLast);
119 }
120
121 void iterateCodeUnits(StringIterator iterator, bool isLast) {
122 _sink.iterateBytes(new _StringIteratorWrapper(iterator.asUtf8()), isLast);
123 }
124
125 void iterateRunes(StringIterator iterator, bool isLast) {
126 _sink.iterateBytes(new _StringIteratorWrapper(iterator.asUtf8()), isLast);
127 }
128
129 void iterateUtf8(StringIterator iterator, bool isLast) {
130 _sink.iterateBytes(new _StringIteratorWrapper(iterator), isLast);
131 }
132
133 void iterateIsoLatin1(StringIterator iterator, bool isLast) {
134 _sink.iterateBytes(new _StringIteratorWrapper(iterator), isLast);
135 }
136
137 void iterateAscii(StringIterator iterator, bool isLast) {
138 _sink.iterateBytes(new _StringIteratorWrapper(iterator), isLast);
139 }
140 }
141
142 class _StringIteratorWrapper implements ByteIterator {
143 StringIterator _iterator;
144
145 _StringIteratorWrapper(StringIterator this._iterator);
146
147 int get current => _iterator.current;
148 bool moveNext() => _iterator.moveNext();
149 int fill(List<int> list, int startIndex, int endIndex) =>
150 _iterator.fill(list, startIndex, endIndex);
151
152 List<int> convertToByteList() {
153 List<int> list = new Uint8List(32);
154 int startIndex = 0;
155 do {
156 int filled = fill(list, startIndex, list.length);
157 if (filled < list.length) {
158 List<int> result = new Uint8List(filled);
159 result.setRange(0, filled, list);
160 return result;
161 }
162 // Double in size.
163 List<int> biggerList = new Uint8List(list.length * 2);
164 biggerList.setRange(0, list.length, list);
165 startIndex = list.length;
166 list = biggerList;
167 } while(true);
168 }
169 }
170
171 class _Utf8EncoderIterator implements ByteIterator {
172 List<int> _carry;
173 final Iterator _runeIterator;
174 int _carryPos = 0;
175 int _current;
176
177 _Utf8EncoderIterator(this._runeIterator);
178
179 void _addRune(int rune) {
180 assert(rune > _ONE_BYTE_LIMIT);
181 if (_carry == null) {
182 _carry = new List<int>(3);
183 }
184 _carryPos = 0;
185 if (rune <= _TWO_BYTE_LIMIT) {
186 _carry[_carryPos++] = 0x80 | (rune & 0x3f);
187 _current = 0xC0 | (rune >> 6);
188 } else if (rune <= _THREE_BYTE_LIMIT) {
189 _carry[_carryPos++] = 0x80 | (rune & 0x3f);
190 _carry[_carryPos++] = 0x80 | ((rune >> 6) & 0x3f);
191 _current = 0xE0 | (rune >> 12);
192 } else {
193 assert(rune <= _FOUR_BYTE_LIMIT);
194 _carry[_carryPos++] = 0x80 | (rune & 0x3f);
195 _carry[_carryPos++] = 0x80 | ((rune >> 6) & 0x3f);
196 _carry[_carryPos++] = 0x80 | ((rune >> 12) & 0x3f);
197 _current = 0xF0 | (rune >> 18);
198 }
199 }
200
201 bool moveNext() {
202 if (_carryPos > 0) {
203 _carryPos--;
204 _current = _carry[_carryPos];
205 return true;
206 }
207 bool hasNext = _runeIterator.moveNext();
208 if (!hasNext) {
209 _current = null;
210 return false;
211 }
212 int rune = _runeIterator.current;
213 if (rune < _ONE_BYTE_LIMIT) {
214 _current = rune;
215 } else {
216 _addRune(rune);
217 }
218 return true;
219 }
220
221 int get current => _current;
222
223 int fill(List<int> list, int startIndex, int endIndex) {
224 int i = startIndex;
225 while (i < endIndex && _carryPos > 0) {
226 _carryPos--;
227 list[i++] = _carry[_carryPos];
228 }
229 while (i < endIndex - 4 && _runeIterator.moveNext()) {
230 int rune = _runeIterator.current;
231 if (rune < _ONE_BYTE_LIMIT) {
232 list[i++] = rune;
233 } else if (rune <= _TWO_BYTE_LIMIT) {
234 list[i++] = 0xC0 | (rune >> 6);
235 list[i++] = 0x80 | (rune & 0x3f);
236 } else if (rune <= _THREE_BYTE_LIMIT) {
237 list[i++] = 0xE0 | (rune >> 12);
238 list[i++] = 0x80 | ((rune >> 6) & 0x3f);
239 list[i++] = 0x80 | (rune & 0x3f);
240 } else {
241 assert(rune <= _FOUR_BYTE_LIMIT);
242 list[i++] = 0xF0 | (rune >> 18);
243 list[i++] = 0x80 | ((rune >> 12) & 0x3f);
244 list[i++] = 0x80 | ((rune >> 6) & 0x3f);
245 list[i++] = 0x80 | (rune & 0x3f);
246 }
247 }
248 while (i < endIndex && _runeIterator.moveNext()) {
249 int rune = _runeIterator.current;
250 if (rune < _ONE_BYTE_LIMIT) {
251 list[i++] = rune;
252 continue;
253 }
254 if (rune <= _TWO_BYTE_LIMIT) {
255 if (i + 2 <= endIndex) {
256 list[i++] = 0xC0 | (rune >> 6);
257 list[i++] = 0x80 | (rune & 0x3f);
258 continue;
259 }
260 } else if (rune <= _THREE_BYTE_LIMIT) {
261 if (i + 3 <= endIndex) {
262 list[i++] = 0xE0 | (rune >> 12);
263 list[i++] = 0x80 | ((rune >> 6) & 0x3f);
264 list[i++] = 0x80 | (rune & 0x3f);
265 continue;
266 }
267 } else {
268 assert(rune <= _FOUR_BYTE_LIMIT);
269 if (i + 4 <= endIndex) {
270 list[i++] = 0xF0 | (rune >> 18);
271 list[i++] = 0x80 | ((rune >> 12) & 0x3f);
272 list[i++] = 0x80 | ((rune >> 6) & 0x3f);
273 list[i++] = 0x80 | (rune & 0x3f);
274 continue;
275 }
276 }
277 // We don't have enough space to fill the list.
278 // Store the remainder in the carry.
279 _addRune(rune);
280 while (i < endIndex) {
281 _carryPos--;
282 list[i++] = _carry[_carryPos];
283 }
284 }
285 return i;
286 }
287
288 List<int> convertToByteList() {
289 List<int> list = new Uint8List(32);
290 int startIndex = 0;
291 do {
292 int filled = fill(list, startIndex, list.length);
293 if (filled < list.length) {
294 List<int> result = new Uint8List(filled);
295 result.setRange(0, filled, list);
296 return result;
297 }
298 // Double in size.
299 List<int> biggerList = new Uint8List(list.length * 2);
300 biggerList.setRange(0, list.length, list);
301 startIndex = list.length;
302 list = biggerList;
303 } while(true);
304 }
305 }
OLDNEW
« no previous file with comments | « sdk/lib/convert/string_converter.dart ('k') | sdk/lib/json/json.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698