137 lines
3.9 KiB
Java
137 lines
3.9 KiB
Java
|
|
package org.oscim.utils;
|
|
|
|
/*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed with
|
|
* this work for additional information regarding copyright ownership.
|
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
|
* (the "License"); you may not use this file except in compliance with
|
|
* the License. You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
// modified new String so that it reuses temporary buffer instead of reallocation
|
|
// when guess for size was incorrect.
|
|
public class UTF8Decoder {
|
|
private static final char REPLACEMENT_CHAR = (char) 0xfffd;
|
|
|
|
char[] mBuffer;
|
|
int mBufferSize = 0;
|
|
|
|
public String decode(byte[] data, int offset, int byteCount) {
|
|
if ((offset | byteCount) < 0 || byteCount > data.length - offset) {
|
|
throw new IllegalArgumentException("Brrr " + data.length
|
|
+ " " + offset + " " + byteCount);
|
|
}
|
|
|
|
byte[] d = data;
|
|
char[] v;
|
|
|
|
if (mBufferSize < byteCount)
|
|
v = mBuffer = new char[byteCount];
|
|
else
|
|
v = mBuffer;
|
|
|
|
int idx = offset;
|
|
int last = offset + byteCount;
|
|
int s = 0;
|
|
outer: while (idx < last) {
|
|
byte b0 = d[idx++];
|
|
if ((b0 & 0x80) == 0) {
|
|
// 0xxxxxxx
|
|
// Range: U-00000000 - U-0000007F
|
|
int val = b0 & 0xff;
|
|
v[s++] = (char) val;
|
|
} else if (((b0 & 0xe0) == 0xc0) || ((b0 & 0xf0) == 0xe0) ||
|
|
((b0 & 0xf8) == 0xf0) || ((b0 & 0xfc) == 0xf8) || ((b0 & 0xfe) == 0xfc)) {
|
|
int utfCount = 1;
|
|
if ((b0 & 0xf0) == 0xe0)
|
|
utfCount = 2;
|
|
else if ((b0 & 0xf8) == 0xf0)
|
|
utfCount = 3;
|
|
else if ((b0 & 0xfc) == 0xf8)
|
|
utfCount = 4;
|
|
else if ((b0 & 0xfe) == 0xfc)
|
|
utfCount = 5;
|
|
|
|
// 110xxxxx (10xxxxxx)+
|
|
// Range: U-00000080 - U-000007FF (count == 1)
|
|
// Range: U-00000800 - U-0000FFFF (count == 2)
|
|
// Range: U-00010000 - U-001FFFFF (count == 3)
|
|
// Range: U-00200000 - U-03FFFFFF (count == 4)
|
|
// Range: U-04000000 - U-7FFFFFFF (count == 5)
|
|
|
|
if (idx + utfCount > last) {
|
|
v[s++] = REPLACEMENT_CHAR;
|
|
break;
|
|
}
|
|
|
|
// Extract usable bits from b0
|
|
int val = b0 & (0x1f >> (utfCount - 1));
|
|
for (int i = 0; i < utfCount; i++) {
|
|
byte b = d[idx++];
|
|
if ((b & 0xC0) != 0x80) {
|
|
v[s++] = REPLACEMENT_CHAR;
|
|
idx--; // Put the input char back
|
|
continue outer;
|
|
}
|
|
// Push new bits in from the right side
|
|
val <<= 6;
|
|
val |= b & 0x3f;
|
|
}
|
|
|
|
// Note: Java allows overlong char
|
|
// specifications To disallow, check that val
|
|
// is greater than or equal to the minimum
|
|
// value for each count:
|
|
//
|
|
// count min value
|
|
// ----- ----------
|
|
// 1 0x80
|
|
// 2 0x800
|
|
// 3 0x10000
|
|
// 4 0x200000
|
|
// 5 0x4000000
|
|
|
|
// Allow surrogate values (0xD800 - 0xDFFF) to
|
|
// be specified using 3-byte UTF values only
|
|
if ((utfCount != 2) && (val >= 0xD800) && (val <= 0xDFFF)) {
|
|
v[s++] = REPLACEMENT_CHAR;
|
|
continue;
|
|
}
|
|
|
|
// Reject chars greater than the Unicode maximum of U+10FFFF.
|
|
if (val > 0x10FFFF) {
|
|
v[s++] = REPLACEMENT_CHAR;
|
|
continue;
|
|
}
|
|
|
|
// Encode chars from U+10000 up as surrogate pairs
|
|
if (val < 0x10000) {
|
|
v[s++] = (char) val;
|
|
} else {
|
|
int x = val & 0xffff;
|
|
int u = (val >> 16) & 0x1f;
|
|
int w = (u - 1) & 0xffff;
|
|
int hi = 0xd800 | (w << 6) | (x >> 10);
|
|
int lo = 0xdc00 | (x & 0x3ff);
|
|
v[s++] = (char) hi;
|
|
v[s++] = (char) lo;
|
|
}
|
|
} else {
|
|
// Illegal values 0x8*, 0x9*, 0xa*, 0xb*, 0xfd-0xff
|
|
v[s++] = REPLACEMENT_CHAR;
|
|
}
|
|
}
|
|
return new String(v, 0, s);
|
|
}
|
|
}
|