OLD | NEW |
(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 // part of dart.async; |
| 6 |
| 7 abstract class _StringDecoder extends _StreamTransformer<List<int>, String> { |
| 8 |
| 9 handleData(List<int> bytes, StreamSink<String> sink) { |
| 10 var data = _carry; |
| 11 data.addAll(bytes); |
| 12 _carry = []; |
| 13 var buffer = new StringBuffer(); |
| 14 int pos = 0; |
| 15 while (pos < data.length) { |
| 16 int currentPos = pos; |
| 17 int getNext() { |
| 18 if (pos < data.length) { |
| 19 return data[pos++]; |
| 20 } |
| 21 return -1; |
| 22 } |
| 23 _chars = []; |
| 24 if (_processByte(data[pos++], getNext)) { |
| 25 _chars.forEach(buffer.addCharCode); |
| 26 } else { |
| 27 _carry = data.getRange(currentPos, data.length - currentPos); |
| 28 break; |
| 29 } |
| 30 } |
| 31 sink.add(buffer.toString()); |
| 32 } |
| 33 |
| 34 void handleDone(StreamSink<String> sink) { |
| 35 if (!_carry.isEmpty) { |
| 36 sink.signalError(new AsyncError( |
| 37 new StateError("Unhandled tailing utf8 chars"))); |
| 38 } |
| 39 sink.close(); |
| 40 } |
| 41 |
| 42 bool _processByte(int byte, int getNext()); |
| 43 |
| 44 void addChar(int char) { |
| 45 _chars.add(char); |
| 46 } |
| 47 |
| 48 List<int> _carry = []; |
| 49 List<int> _chars; |
| 50 } |
| 51 |
| 52 /** |
| 53 * StringTransformer class that decodes a utf8 encoded bytes. |
| 54 */ |
| 55 class Utf8DecoderTransformer extends _StringDecoder { |
| 56 bool _processByte(int byte, int getNext()) { |
| 57 int value = byte & 0xFF; |
| 58 if ((value & 0x80) == 0x80) { |
| 59 int additionalBytes; |
| 60 if ((value & 0xe0) == 0xc0) { // 110xxxxx |
| 61 value = value & 0x1F; |
| 62 additionalBytes = 1; |
| 63 } else if ((value & 0xf0) == 0xe0) { // 1110xxxx |
| 64 value = value & 0x0F; |
| 65 additionalBytes = 2; |
| 66 } else { // 11110xxx |
| 67 value = value & 0x07; |
| 68 additionalBytes = 3; |
| 69 } |
| 70 for (int i = 0; i < additionalBytes; i++) { |
| 71 int next = getNext(); |
| 72 if (next < 0) return false; |
| 73 value = value << 6 | (next & 0x3F); |
| 74 } |
| 75 } |
| 76 addChar(value); |
| 77 return true; |
| 78 } |
| 79 } |
| 80 |
| 81 |
| 82 abstract class _StringEncoder extends _StreamTransformer<String, List<int>> { |
| 83 handleData(String string, StreamSink<List<int>> sink) { |
| 84 sink.add(_processString(string)); |
| 85 } |
| 86 |
| 87 List<int> _processString(String string); |
| 88 } |
| 89 |
| 90 /** |
| 91 * StringTransformer class that utf8 encodes a string. |
| 92 */ |
| 93 class Utf8EncoderTransformer extends _StringEncoder { |
| 94 List<int> _processString(String string) { |
| 95 var bytes = []; |
| 96 int pos = 0; |
| 97 int length = string.length; |
| 98 for (int i = 0; i < length; i++) { |
| 99 int additionalBytes; |
| 100 int charCode = string.charCodeAt(i); |
| 101 if (charCode <= 0x007F) { |
| 102 additionalBytes = 0; |
| 103 bytes.add(charCode); |
| 104 } else if (charCode <= 0x07FF) { |
| 105 // 110xxxxx (xxxxx is top 5 bits). |
| 106 bytes.add(((charCode >> 6) & 0x1F) | 0xC0); |
| 107 additionalBytes = 1; |
| 108 } else if (charCode <= 0xFFFF) { |
| 109 // 1110xxxx (xxxx is top 4 bits) |
| 110 bytes.add(((charCode >> 12) & 0x0F)| 0xE0); |
| 111 additionalBytes = 2; |
| 112 } else { |
| 113 // 11110xxx (xxx is top 3 bits) |
| 114 bytes.add(((charCode >> 18) & 0x07) | 0xF0); |
| 115 additionalBytes = 3; |
| 116 } |
| 117 for (int i = additionalBytes; i > 0; i--) { |
| 118 // 10xxxxxx (xxxxxx is next 6 bits from the top). |
| 119 bytes.add(((charCode >> (6 * (i - 1))) & 0x3F) | 0x80); |
| 120 } |
| 121 pos += additionalBytes + 1; |
| 122 } |
| 123 return bytes; |
| 124 } |
| 125 } |
| 126 |
| 127 |
OLD | NEW |