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

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

Issue 22875034: Add ASCII encoding to lib/convert. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Address review comments Created 7 years, 4 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/convert_sources.gypi ('k') | tests/lib/convert/ascii_test.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) 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 /** 7 /**
8 * An instance of the default implementation of the [Latin1Codec]. 8 * An instance of the default implementation of the [Latin1Codec].
9 * 9 *
10 * This instance provides a convenient access to the most common ISO Latin 1 10 * This instance provides a convenient access to the most common ISO Latin 1
11 * use cases. 11 * use cases.
12 * 12 *
13 * Examples: 13 * Examples:
14 * 14 *
15 * var encoded = LATIN1.encode("blåbærgrød"); 15 * var encoded = LATIN1.encode("blåbærgrød");
16 * var decoded = LATIN1.decode([0x62, 0x6c, 0xe5, 0x62, 0xe6, 16 * var decoded = LATIN1.decode([0x62, 0x6c, 0xe5, 0x62, 0xe6,
17 * 0x72, 0x67, 0x72, 0xf8, 0x64]); 17 * 0x72, 0x67, 0x72, 0xf8, 0x64]);
18 */ 18 */
19 const LATIN1 = const Latin1Codec(); 19 const LATIN1 = const Latin1Codec();
20 20
21 const int _LATIN1_MASK = 0xFF;
22
21 /** 23 /**
22 * A [LatinCodec] encodes strings to ISO Latin-1 (aka ISO-8859-1) bytes 24 * A [LatinCodec] encodes strings to ISO Latin-1 (aka ISO-8859-1) bytes
23 * and decodes Latin-1 bytes to strings. 25 * and decodes Latin-1 bytes to strings.
24 */ 26 */
25 class Latin1Codec extends _Encoding { 27 class Latin1Codec extends _Encoding {
26 final bool _allowInvalid; 28 final bool _allowInvalid;
27 /** 29 /**
28 * Instantiates a new [Latin1Codec]. 30 * Instantiates a new [Latin1Codec].
29 * 31 *
30 * If [allowInvalid] is true, the [decode] method and the converter 32 * If [allowInvalid] is true, the [decode] method and the converter
(...skipping 27 matching lines...) Expand all
58 Converter<String, List<int>> get encoder => const Latin1Encoder(); 60 Converter<String, List<int>> get encoder => const Latin1Encoder();
59 61
60 Converter<List<int>, String> get decoder => 62 Converter<List<int>, String> get decoder =>
61 _allowInvalid ? const Latin1Decoder(allowInvalid: true) 63 _allowInvalid ? const Latin1Decoder(allowInvalid: true)
62 : const Latin1Decoder(allowInvalid: false); 64 : const Latin1Decoder(allowInvalid: false);
63 } 65 }
64 66
65 /** 67 /**
66 * This class converts strings of only ISO Latin-1 characters to bytes. 68 * This class converts strings of only ISO Latin-1 characters to bytes.
67 */ 69 */
68 class Latin1Encoder extends Converter<String, List<int>> { 70 class Latin1Encoder extends _UnicodeSubsetEncoder {
69 const Latin1Encoder(); 71 const Latin1Encoder() : super(_LATIN1_MASK);
70
71 /**
72 * Converts [string] to its Latin-1 bytes (a list of
73 * unsigned 8-bit integers).
74 */
75 List<int> convert(String string) {
76 // TODO(11971): Use Uint8List when possible.
77 List result = new List<int>(string.length);
78 for (int i = 0; i < string.length; i++) {
79 var codeUnit = string.codeUnitAt(i);
80 if ((codeUnit & ~0xFF) != 0) {
81 throw new ArgumentError("String contains non-Latin-1 characters.");
82 }
83 result[i] = codeUnit;
84 }
85 return result;
86 }
87
88 /**
89 * Starts a chunked conversion.
90 *
91 * The converter works more efficiently if the given [sink] is a
92 * [ByteConversionSink].
93 */
94 StringConversionSink startChunkedConversion(
95 ChunkedConversionSink<List<int>> sink) {
96 if (sink is! ByteConversionSink) {
97 sink = new ByteConversionSink.from(sink);
98 }
99 return new _Latin1EncoderSink(sink);
100 }
101
102 // Override the base-class' bind, to provide a better type.
103 Stream<List<int>> bind(Stream<String> stream) => super.bind(stream);
104 }
105
106 /**
107 * This class encodes chunked strings to bytes (unsigned 8-bit
108 * integers).
109 */
110 class _Latin1EncoderSink extends StringConversionSinkBase {
111 static const _DEFAULT_BYTE_BUFFER_SIZE = 1024;
112 final ByteConversionSink _sink;
113
114 // TODO(11971): Use Uint8List when available.
115 List<int> _buffer = new List<int>(_DEFAULT_BYTE_BUFFER_SIZE);
116 int _bufferIndex = 0;
117
118 _Latin1EncoderSink(this._sink);
119
120 void close() {
121 if (_bufferIndex > 0) {
122 _sink.addSlice(_buffer, 0, _bufferIndex, true);
123 } else {
124 _sink.close();
125 }
126 }
127
128 void addSlice(String source, int start, int end, bool isLast) {
129 if (start < 0 || start > source.length) {
130 throw new RangeError.range(start, 0, source.length);
131 }
132 if (end < start || end > source.length) {
133 throw new RangeError.range(end, start, source.length);
134 }
135 for (int i = start; i < end; i++) {
136 int codeUnit = source.codeUnitAt(i);
137 if ((codeUnit & ~0xFF) != 0) {
138 throw new ArgumentError("Source contains non-Latin-1 characters.");
139 }
140 _buffer[_bufferIndex] = codeUnit;
141 _bufferIndex++;
142 if (_bufferIndex == _buffer.length) {
143 _sink.addSlice(_buffer, 0, _bufferIndex, false);
144 _bufferIndex = 0;
145 }
146 }
147 if (isLast) close();
148 }
149 } 72 }
150 73
151 /** 74 /**
152 * This class converts Latin-1 bytes (lists of unsigned 8-bit integers) 75 * This class converts Latin-1 bytes (lists of unsigned 8-bit integers)
153 * to a string. 76 * to a string.
154 */ 77 */
155 class Latin1Decoder extends Converter<List<int>, String> { 78 class Latin1Decoder extends _UnicodeSubsetDecoder {
156 final bool _allowInvalid;
157
158 /** 79 /**
159 * Instantiates a new [Latin1Decoder]. 80 * Instantiates a new [Latin1Decoder].
160 * 81 *
161 * The optional [allowInvalid] argument defines how [convert] deals 82 * The optional [allowInvalid] argument defines how [convert] deals
162 * with invalid bytes. 83 * with invalid bytes.
163 * 84 *
164 * If it is `true`, [convert] replaces invalid bytes with the Unicode 85 * If it is `true`, [convert] replaces invalid bytes with the Unicode
165 * Replacement character `U+FFFD` (�). 86 * Replacement character `U+FFFD` (�).
166 * Otherwise it throws a [FormatException]. 87 * Otherwise it throws a [FormatException].
167 */ 88 */
168 const Latin1Decoder({ bool allowInvalid: false }) 89 const Latin1Decoder({ bool allowInvalid: false })
169 : this._allowInvalid = allowInvalid; 90 : super(allowInvalid, _LATIN1_MASK);
170
171 /**
172 * Converts the Latin=1 [bytes] (a list of unsigned 8-bit integers) to the
173 * corresponding string.
174 */
175 String convert(List<int> bytes) {
176 for (int i = 0; i < bytes.length; i++) {
177 int byte = bytes[i];
178 if ((byte & ~0xFF) != 0) {
179 if (!_allowInvalid) {
180 throw new FormatException("Non-byte in byte list");
181 }
182 return _convertInvalid(bytes);
183 }
184 }
185 return new String.fromCharCodes(bytes);
186 }
187
188 String _convertInvalid(List<int> bytes) {
189 StringBuffer buffer = new StringBuffer();
190 for (int i = 0; i < bytes.length; i++) {
191 int value = bytes[i];
192 if ((value & ~0xFF) != 0) value = 0xFFFD;
193 buffer.writeCharCode(value);
194 }
195 return buffer.toString();
196 }
197 91
198 /** 92 /**
199 * Starts a chunked conversion. 93 * Starts a chunked conversion.
200 * 94 *
201 * The converter works more efficiently if the given [sink] is a 95 * The converter works more efficiently if the given [sink] is a
202 * [StringConversionSink]. 96 * [StringConversionSink].
203 */ 97 */
204 ByteConversionSink startChunkedConversion( 98 ByteConversionSink startChunkedConversion(
205 ChunkedConversionSink<String> sink) { 99 ChunkedConversionSink<String> sink) {
206 StringConversionSink stringSink; 100 StringConversionSink stringSink;
207 if (sink is StringConversionSink) { 101 if (sink is StringConversionSink) {
208 stringSink = sink; 102 stringSink = sink;
209 } else { 103 } else {
210 stringSink = new StringConversionSink.from(sink); 104 stringSink = new StringConversionSink.from(sink);
211 } 105 }
212 // TODO(lrn): Use stringSink.asUtf16Sink() if it becomes available. 106 // TODO(lrn): Use stringSink.asUtf16Sink() if it becomes available.
213 return new _Latin1DecoderSink(_allowInvalid, stringSink); 107 return new _Latin1DecoderSink(_allowInvalid, stringSink);
214 } 108 }
215
216 // Override the base-class's bind, to provide a better type.
217 Stream<String> bind(Stream<List<int>> stream) => super.bind(stream);
218 } 109 }
219 110
220 class _Latin1DecoderSink extends ByteConversionSinkBase { 111 class _Latin1DecoderSink extends ByteConversionSinkBase {
221 final bool _allowInvalid; 112 final bool _allowInvalid;
222 StringConversionSink _sink; 113 StringConversionSink _sink;
223 _Latin1DecoderSink(this._allowInvalid, this._sink); 114 _Latin1DecoderSink(this._allowInvalid, this._sink);
224 115
225 void close() { 116 void close() {
226 _sink.close(); 117 _sink.close();
227 } 118 }
(...skipping 12 matching lines...) Expand all
240 } 131 }
241 132
242 void addSlice(List<int> source, int start, int end, bool isLast) { 133 void addSlice(List<int> source, int start, int end, bool isLast) {
243 if (start < 0 || start > source.length) { 134 if (start < 0 || start > source.length) {
244 throw new RangeError.range(start, 0, source.length); 135 throw new RangeError.range(start, 0, source.length);
245 } 136 }
246 if (end < start || end > source.length) { 137 if (end < start || end > source.length) {
247 throw new RangeError.range(end, start, source.length); 138 throw new RangeError.range(end, start, source.length);
248 } 139 }
249 for (int i = start; i < end; i++) { 140 for (int i = start; i < end; i++) {
250 if ((source[i] & ~0xFF) != 0) { 141 if ((source[i] & ~_LATIN1_MASK) != 0) {
251 if (_allowInvalid) { 142 if (_allowInvalid) {
252 if (i > start) _addSliceToSink(source, start, i, false); 143 if (i > start) _addSliceToSink(source, start, i, false);
253 // Add UTF-8 encoding of U+FFFD. 144 // Add UTF-8 encoding of U+FFFD.
254 _addSliceToSink(const[0xFFFD], 0, 1, false); 145 _addSliceToSink(const[0xFFFD], 0, 1, false);
255 start = i + 1; 146 start = i + 1;
256 } else { 147 } else {
257 throw new FormatException("Source contains non-Latin-1 characters."); 148 throw new FormatException("Source contains non-Latin-1 characters.");
258 } 149 }
259 } 150 }
260 } 151 }
261 if (start < end) { 152 if (start < end) {
262 _addSliceToSink(source, start, end, isLast); 153 _addSliceToSink(source, start, end, isLast);
263 } else if (isLast) { 154 } else if (isLast) {
264 close(); 155 close();
265 } 156 }
266 } 157 }
267 } 158 }
OLDNEW
« no previous file with comments | « sdk/lib/convert/convert_sources.gypi ('k') | tests/lib/convert/ascii_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698