Chromium Code Reviews| Index: utils/string_encoding/utf8_impl.dart |
| diff --git a/utils/string_encoding/utf8_impl.dart b/utils/string_encoding/utf8_impl.dart |
| index 213bb72ea4a1c62c888db9724f866441368ab686..59d4188fb926d722cacd2a0c23f700290710a463 100644 |
| --- a/utils/string_encoding/utf8_impl.dart |
| +++ b/utils/string_encoding/utf8_impl.dart |
| @@ -130,92 +130,109 @@ List<int> _utf8ToCodepoints( |
| Math.min(utf8EncodedBytes.length, offset + length) : |
| utf8EncodedBytes.length; |
| - void addReplacementCodepoint(void f(int v), int replacementCodepoint) { |
| - if(replacementCodepoint != null) { |
| - f(replacementCodepoint); |
| - } else { |
| - throw new IllegalArgumentException("Invalid encoding"); |
| - } |
| - } |
| - |
| - void apply(void f(int v)) { |
| + void decode(void f(int v)) { |
| int i = offset; |
| while (i < end) { |
| int value = utf8EncodedBytes[i++]; |
| - if (value >= 0) { |
| - if (value <= _UTF8_ONE_BYTE_MAX) { |
| - f(value); |
| - } else if (value < _UTF8_FIRST_BYTE_OF_TWO_BASE) { |
| - addReplacementCodepoint(f, replacementCodepoint); |
| - continue; |
| + if (value < 0) { |
| + f(null); |
| + continue; |
| + } |
| + |
| + if (value <= _UTF8_ONE_BYTE_MAX) { |
| + f(value); |
| + } else if (value < _UTF8_FIRST_BYTE_OF_TWO_BASE) { |
| + f(null); |
| + continue; |
| + } else { |
| + int additionalBytes = 0; |
| + if (value < _UTF8_FIRST_BYTE_OF_THREE_BASE) { |
| + value -= _UTF8_FIRST_BYTE_OF_TWO_BASE; |
| + additionalBytes = 1; |
| + } else if (value < _UTF8_FIRST_BYTE_OF_FOUR_BASE) { |
| + value -= _UTF8_FIRST_BYTE_OF_THREE_BASE; |
| + additionalBytes = 2; |
| + } else if (value < _UTF8_FIRST_BYTE_OF_FIVE_BASE) { |
| + value -= _UTF8_FIRST_BYTE_OF_FOUR_BASE; |
| + additionalBytes = 3; |
| + } else if (value < _UTF8_FIRST_BYTE_OF_SIX_BASE) { |
| + value -= _UTF8_FIRST_BYTE_OF_FIVE_BASE; |
| + additionalBytes = 4; |
| + } else if (value < _UTF8_FIRST_BYTE_BOUND_EXCL) { |
| + value -= _UTF8_FIRST_BYTE_OF_SIX_BASE; |
| + additionalBytes = 5; |
| } else { |
| - int additionalBytes = 0; |
| - if (value < _UTF8_FIRST_BYTE_OF_THREE_BASE) { |
| - value -= _UTF8_FIRST_BYTE_OF_TWO_BASE; |
| - additionalBytes = 1; |
| - } else if (value < _UTF8_FIRST_BYTE_OF_FOUR_BASE) { |
| - value -= _UTF8_FIRST_BYTE_OF_THREE_BASE; |
| - additionalBytes = 2; |
| - } else if (value < _UTF8_FIRST_BYTE_OF_FIVE_BASE) { |
| - value -= _UTF8_FIRST_BYTE_OF_FOUR_BASE; |
| - additionalBytes = 3; |
| - } else if (value < _UTF8_FIRST_BYTE_OF_SIX_BASE) { |
| - value -= _UTF8_FIRST_BYTE_OF_FIVE_BASE; |
| - additionalBytes = 4; |
| - } else if (value < _UTF8_FIRST_BYTE_BOUND_EXCL) { |
| - value -= _UTF8_FIRST_BYTE_OF_SIX_BASE; |
| - additionalBytes = 5; |
| + f(null); |
| + continue; |
| + } |
| + int j = 0; |
| + while (j < additionalBytes && i < end) { |
| + int nextValue = utf8EncodedBytes[i++]; |
| + if (nextValue > _UTF8_ONE_BYTE_MAX && |
| + nextValue < _UTF8_FIRST_BYTE_OF_TWO_BASE) { |
| + value = (value << 6) | (nextValue & _UTF8_LO_SIX_BIT_MASK); |
| } else { |
| - addReplacementCodepoint(f, replacementCodepoint); |
| - continue; |
| - } |
| - int j = 0; |
| - while (j < additionalBytes && i < end) { |
| - int nextValue = utf8EncodedBytes[i++]; |
| - if (nextValue > _UTF8_ONE_BYTE_MAX && |
| - nextValue < _UTF8_FIRST_BYTE_OF_TWO_BASE) { |
| - value = (value << 6) | (nextValue & _UTF8_LO_SIX_BIT_MASK); |
| - } else { |
| - // if sequence-starting code unit, reposition cursor to start here |
| - if (nextValue >= _UTF8_FIRST_BYTE_OF_TWO_BASE) { |
| - i--; |
| - } |
| - break; |
| + // if sequence-starting code unit, reposition cursor to start here |
| + if (nextValue >= _UTF8_FIRST_BYTE_OF_TWO_BASE) { |
| + i--; |
| } |
| - j++; |
| + break; |
| } |
| - if (j == additionalBytes && ( |
| - value < UNICODE_UTF16_RESERVED_LO || |
| - value > UNICODE_UTF16_RESERVED_HI)) { |
| - if ((additionalBytes == 1 && value > _UTF8_ONE_BYTE_MAX) || |
| - (additionalBytes == 2 && value > _UTF8_TWO_BYTE_MAX) || |
| - (additionalBytes == 3 && value > _UTF8_THREE_BYTE_MAX && |
| - value <= UNICODE_VALID_RANGE_MAX)) { |
| - f(value); |
| - } else { |
| - addReplacementCodepoint(f, replacementCodepoint); |
| - } |
| + j++; |
| + } |
| + if (j == additionalBytes && ( |
| + value < UNICODE_UTF16_RESERVED_LO || |
| + value > UNICODE_UTF16_RESERVED_HI)) { |
| + if ((additionalBytes == 1 && value > _UTF8_ONE_BYTE_MAX) || |
| + (additionalBytes == 2 && value > _UTF8_TWO_BYTE_MAX) || |
| + (additionalBytes == 3 && value > _UTF8_THREE_BYTE_MAX && |
| + value <= UNICODE_VALID_RANGE_MAX)) { |
| + f(value); |
| } else { |
| - addReplacementCodepoint(f, replacementCodepoint); |
| - continue; |
| + f(null); |
| } |
| + } else { |
| + f(null); |
| + continue; |
| } |
| - } else { |
| - addReplacementCodepoint(f, replacementCodepoint); |
| - continue; |
| } |
| } |
| } |
| + // First pass through data to 1) size the output buffer and 2) check for |
| + // special case optimization where A) the length stays the same and B) |
| + // no special replacement characters are used. If these criteria are met |
| + // we can just copy input to the output. |
| int codepointBufferLength = 0; |
| - apply(void _(int value) { |
| + bool hasReplacements = false; |
| + decode(void _(int value) { |
| codepointBufferLength++; |
| + if (value == null) { |
| + hasReplacements = true; |
| + } |
| }); |
| + // If the string calls for replacements, but we the method is called |
|
Søren Gjesse
2012/02/06 22:13:29
ditto.
dcarlson
2012/02/13 16:37:51
Done.
|
| + // with replacementCodepoint explicitly set to null, then throw an exception. |
| + if (hasReplacements && replacementCodepoint == null) { |
| + throw new IllegalArgumentException("Invalid encoding"); |
| + } |
| + |
| + int _length = end - offset; |
| List<int> codepointBuffer = new List<int>(codepointBufferLength); |
| - int i = 0; |
| - apply(void _(int value) { |
| - codepointBuffer[i++] = value; |
| - }); |
| + if (_length == codepointBufferLength && !hasReplacements) { |
| + codepointBuffer.setRange(0, _length, utf8EncodedBytes, offset); |
| + } else { |
| + int i = 0; |
| + decode( |
| + void _(int value) { |
| + if (value != null) { |
| + codepointBuffer[i++] = value; |
| + } else { |
| + codepointBuffer[i++] = replacementCodepoint; |
| + } |
| + } |
| + ); |
| + } |
| return codepointBuffer; |
| } |