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

Side by Side Diff: sdk/lib/_internal/compiler/implementation/scanner/utf8_bytes_scanner.dart

Issue 137343002: Handle BOMs in dart2js. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Minor comment update. Created 6 years, 11 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
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 scanner; 5 part of scanner;
6 6
7 /** 7 /**
8 * Scanner that reads from a UTF-8 encoded list of bytes and creates tokens 8 * Scanner that reads from a UTF-8 encoded list of bytes and creates tokens
9 * that points to substrings. 9 * that points to substrings.
10 */ 10 */
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
62 * string text of the source file is decoded. 62 * string text of the source file is decoded.
63 * 63 *
64 * The list of UTF-8 bytes [file.slowUtf8Bytes()] is expected to return an 64 * The list of UTF-8 bytes [file.slowUtf8Bytes()] is expected to return an
65 * array whose last element is '0' to signal the end of the file. If this 65 * array whose last element is '0' to signal the end of the file. If this
66 * is not the case, the entire array is copied before scanning. 66 * is not the case, the entire array is copied before scanning.
67 */ 67 */
68 Utf8BytesScanner(SourceFile file, {bool includeComments: false}) 68 Utf8BytesScanner(SourceFile file, {bool includeComments: false})
69 : bytes = file.slowUtf8Bytes(), 69 : bytes = file.slowUtf8Bytes(),
70 super(file, includeComments) { 70 super(file, includeComments) {
71 ensureZeroTermination(); 71 ensureZeroTermination();
72 // Skip a leading BOM.
73 if (_containsBomAt(0)) byteOffset += 3;
72 } 74 }
73 75
74 /** 76 /**
75 * Creates a new Utf8BytesScanner from a list of UTF-8 bytes. 77 * Creates a new Utf8BytesScanner from a list of UTF-8 bytes.
76 * 78 *
77 * The last element of the list is expected to be '0' to signal the end of 79 * The last element of the list is expected to be '0' to signal the end of
78 * the file. If this is not the case, the entire array is copied before 80 * the file. If this is not the case, the entire array is copied before
79 * scanning. 81 * scanning.
80 */ 82 */
81 Utf8BytesScanner.fromBytes(this.bytes, {bool includeComments: false}) 83 Utf8BytesScanner.fromBytes(this.bytes, {bool includeComments: false})
82 : super(null, includeComments) { 84 : super(null, includeComments) {
83 ensureZeroTermination(); 85 ensureZeroTermination();
84 } 86 }
85 87
86 void ensureZeroTermination() { 88 void ensureZeroTermination() {
87 if (bytes.isEmpty || bytes[bytes.length - 1] != 0) { 89 if (bytes.isEmpty || bytes[bytes.length - 1] != 0) {
88 // TODO(lry): abort instead of copying the array, or warn? 90 // TODO(lry): abort instead of copying the array, or warn?
89 var newBytes = new Uint8List(bytes.length + 1); 91 var newBytes = new Uint8List(bytes.length + 1);
90 for (int i = 0; i < bytes.length; i++) { 92 for (int i = 0; i < bytes.length; i++) {
91 newBytes[i] = bytes[i]; 93 newBytes[i] = bytes[i];
92 } 94 }
93 newBytes[bytes.length] = 0; 95 newBytes[bytes.length] = 0;
94 bytes = newBytes; 96 bytes = newBytes;
95 } 97 }
96 } 98 }
97 99
100 bool _containsBomAt(int offset) {
101 const BOM_UTF8 = const [0xEF, 0xBB, 0xBF];
102
103 assert(() {
ahe 2014/01/15 13:15:38 I would probably add a unit test for this instead
floitsch 2014/01/15 13:44:46 There is already a test. Removing the assert.
104 // Verify that BOM_UTF8 corresponds to the UTF-8 BOM character.
105 // The UTF-8 decoder strips leading BOMs. Add another character in front.
106 List<int> prefixedBom = [0x20]..addAll(BOM_UTF8);
107 String decoded = UTF8.decode(prefixedBom);
108 return decoded.codeUnitAt(1) == UNICODE_BOM_CHARACTER_RUNE;
109 });
110
111 return offset + 3 < bytes.length &&
112 bytes[offset] == BOM_UTF8[0] &&
113 bytes[offset + 1] == BOM_UTF8[1] &&
114 bytes[offset + 2] == BOM_UTF8[2];
115 }
116
98 int advance() => bytes[++byteOffset]; 117 int advance() => bytes[++byteOffset];
99 118
100 int peek() => bytes[byteOffset + 1]; 119 int peek() => bytes[byteOffset + 1];
101 120
102 /** 121 /**
103 * Returns the unicode code point starting at the byte offset [startOffset] 122 * Returns the unicode code point starting at the byte offset [startOffset]
104 * with the byte [nextByte]. If [advance] is true the current [byteOffset] 123 * with the byte [nextByte]. If [advance] is true the current [byteOffset]
105 * is advanced to the last byte of the code point. 124 * is advanced to the last byte of the code point.
106 */ 125 */
107 int nextCodePoint(int startOffset, int nextByte, bool advance) { 126 int nextCodePoint(int startOffset, int nextByte, bool advance) {
108 // The number of 1s in the first byte indicate the number of bytes, at 127 // The number of 1s in the first byte indicate the number of bytes, at
109 // least 2. 128 // least 2.
110 int numBytes = 2; 129 int numBytes = 2;
111 int bit = 0x20; 130 int bit = 0x20;
112 while ((nextByte & bit) != 0) { 131 while ((nextByte & bit) != 0) {
113 numBytes++; 132 numBytes++;
114 bit >>= 1; 133 bit >>= 1;
115 } 134 }
116 int end = startOffset + numBytes; 135 int end = startOffset + numBytes;
117 if (advance) { 136 if (advance) {
118 byteOffset = end - 1; 137 byteOffset = end - 1;
119 } 138 }
120 // TODO(lry): measurably slow, decode creates first a Utf8Decoder and a 139 // TODO(lry): measurably slow, decode creates first a Utf8Decoder and a
121 // _Utf8Decoder instance. Also the sublist is eagerly allocated. 140 // _Utf8Decoder instance. Also the sublist is eagerly allocated.
122 String codePoint = UTF8.decode(bytes.sublist(startOffset, end)); 141 String codePoint = UTF8.decode(bytes.sublist(startOffset, end));
142 if (codePoint.length == 0) {
143 // The UTF-8 decoder discards leading BOM characters.
144 // TODO(floitsch): don't just assume that removed characters were the
145 // BOM.
146 assert(_containsBomAt(startOffset));
147 codePoint = "\u{FEFF}";
ahe 2014/01/14 14:23:59 Can you use UNICODE_BOM_CHARACTER_RUNE somehow?
floitsch 2014/01/14 18:37:58 I don't think so. I don't want to recreate a strin
ahe 2014/01/15 13:15:38 I would expect that it is extremely rare if a file
floitsch 2014/01/15 13:44:46 I will allocate a new string. I prefer keeping the
ahe 2014/01/15 13:54:23 Yes. Keep the assert on line 146. That assert test
floitsch 2014/01/15 14:51:39 I see. As you say: there shouldn't be many BOMs in
148 }
123 if (codePoint.length == 1) { 149 if (codePoint.length == 1) {
124 if (advance) { 150 if (advance) {
125 utf8Slack += (numBytes - 1); 151 utf8Slack += (numBytes - 1);
126 scanSlack = numBytes - 1; 152 scanSlack = numBytes - 1;
127 scanSlackOffset = byteOffset; 153 scanSlackOffset = byteOffset;
128 } 154 }
129 return codePoint.codeUnitAt(0); 155 return codePoint.codeUnitAt(0);
130 } else if (codePoint.length == 2) { 156 } else if (codePoint.length == 2) {
131 if (advance) { 157 if (advance) {
132 utf8Slack += (numBytes - 2); 158 utf8Slack += (numBytes - 2);
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
186 212
187 void appendSubstringToken(PrecedenceInfo info, int start, bool asciiOnly, 213 void appendSubstringToken(PrecedenceInfo info, int start, bool asciiOnly,
188 [int extraOffset = 0]) { 214 [int extraOffset = 0]) {
189 tail.next = new StringToken.fromUtf8Bytes( 215 tail.next = new StringToken.fromUtf8Bytes(
190 info, bytes, start, byteOffset + extraOffset, asciiOnly, tokenStart); 216 info, bytes, start, byteOffset + extraOffset, asciiOnly, tokenStart);
191 tail = tail.next; 217 tail = tail.next;
192 } 218 }
193 219
194 bool atEndOfFile() => byteOffset >= bytes.length - 1; 220 bool atEndOfFile() => byteOffset >= bytes.length - 1;
195 } 221 }
OLDNEW
« no previous file with comments | « sdk/lib/_internal/compiler/implementation/scanner/scannerlib.dart ('k') | tests/language/language.status » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698