/* * Copyright 1999-2017 Alibaba Group. * * Licensed 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. */ package com.alibaba.fastjson.util; import java.io.Closeable; import java.io.InputStream; import java.io.Reader; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.CharacterCodingException; import java.nio.charset.Charset; import java.nio.charset.CharsetDecoder; import java.nio.charset.CoderResult; import java.nio.charset.MalformedInputException; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.Arrays; import java.util.Properties; import com.alibaba.fastjson.JSONException; /** * @author wenshao[szujobs@hotmail.com] */ public class IOUtils { public final static String FASTJSON_PROPERTIES ="fastjson.properties"; public final static String FASTJSON_COMPATIBLEWITHJAVABEAN="fastjson.compatibleWithJavaBean"; public final static String FASTJSON_COMPATIBLEWITHFIELDNAME="fastjson.compatibleWithFieldName"; public final static Properties DEFAULT_PROPERTIES =new Properties(); public final static Charset UTF8 = Charset.forName("UTF-8"); public final static char[] DIGITS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; public final static boolean[] firstIdentifierFlags = new boolean[256]; static { for (char c = 0; c < firstIdentifierFlags.length; ++c) { if (c >= 'A' && c <= 'Z') { firstIdentifierFlags[c] = true; } else if (c >= 'a' && c <= 'z') { firstIdentifierFlags[c] = true; } else if (c == '_') { firstIdentifierFlags[c] = true; } } } public final static boolean[] identifierFlags = new boolean[256]; static { for (char c = 0; c < identifierFlags.length; ++c) { if (c >= 'A' && c <= 'Z') { identifierFlags[c] = true; } else if (c >= 'a' && c <= 'z') { identifierFlags[c] = true; } else if (c == '_') { identifierFlags[c] = true; } else if (c >= '0' && c <= '9') { identifierFlags[c] = true; } } } static { try { loadPropertiesFromFile(); } catch (Throwable e) { //skip } } public static String getStringProperty(String name) { String prop = null; try { prop = System.getProperty(name); } catch (SecurityException e) { //skip } return (prop == null) ? DEFAULT_PROPERTIES.getProperty(name) : prop; } public static void loadPropertiesFromFile(){ InputStream imputStream = AccessController.doPrivileged(new PrivilegedAction<InputStream>() { public InputStream run() { ClassLoader cl = Thread.currentThread().getContextClassLoader(); if (cl != null) { return cl.getResourceAsStream(FASTJSON_PROPERTIES); } else { return ClassLoader.getSystemResourceAsStream(FASTJSON_PROPERTIES); } } }); if (null != imputStream) { try { DEFAULT_PROPERTIES.load(imputStream); imputStream.close(); } catch (java.io.IOException e) { // skip } } } public final static byte[] specicalFlags_doubleQuotes = new byte[161]; public final static byte[] specicalFlags_singleQuotes = new byte[161]; public final static boolean[] specicalFlags_doubleQuotesFlags = new boolean[161]; public final static boolean[] specicalFlags_singleQuotesFlags = new boolean[161]; public final static char[] replaceChars = new char[93]; static { specicalFlags_doubleQuotes['\0'] = 4; specicalFlags_doubleQuotes['\1'] = 4; specicalFlags_doubleQuotes['\2'] = 4; specicalFlags_doubleQuotes['\3'] = 4; specicalFlags_doubleQuotes['\4'] = 4; specicalFlags_doubleQuotes['\5'] = 4; specicalFlags_doubleQuotes['\6'] = 4; specicalFlags_doubleQuotes['\7'] = 4; specicalFlags_doubleQuotes['\b'] = 1; // 8 specicalFlags_doubleQuotes['\t'] = 1; // 9 specicalFlags_doubleQuotes['\n'] = 1; // 10 specicalFlags_doubleQuotes['\u000B'] = 4; // 11 specicalFlags_doubleQuotes['\f'] = 1; // 12 specicalFlags_doubleQuotes['\r'] = 1; // 13 specicalFlags_doubleQuotes['\"'] = 1; // 34 specicalFlags_doubleQuotes['\\'] = 1; // 92 specicalFlags_singleQuotes['\0'] = 4; specicalFlags_singleQuotes['\1'] = 4; specicalFlags_singleQuotes['\2'] = 4; specicalFlags_singleQuotes['\3'] = 4; specicalFlags_singleQuotes['\4'] = 4; specicalFlags_singleQuotes['\5'] = 4; specicalFlags_singleQuotes['\6'] = 4; specicalFlags_singleQuotes['\7'] = 4; specicalFlags_singleQuotes['\b'] = 1; // 8 specicalFlags_singleQuotes['\t'] = 1; // 9 specicalFlags_singleQuotes['\n'] = 1; // 10 specicalFlags_singleQuotes['\u000B'] = 4; // 11 specicalFlags_singleQuotes['\f'] = 1; // 12 specicalFlags_singleQuotes['\r'] = 1; // 13 specicalFlags_singleQuotes['\\'] = 1; // 92 specicalFlags_singleQuotes['\''] = 1; // 39 for (int i = 14; i <= 31; ++i) { specicalFlags_doubleQuotes[i] = 4; specicalFlags_singleQuotes[i] = 4; } for (int i = 127; i < 160; ++i) { specicalFlags_doubleQuotes[i] = 4; specicalFlags_singleQuotes[i] = 4; } for (int i = 0; i < 161; ++i) { specicalFlags_doubleQuotesFlags[i] = specicalFlags_doubleQuotes[i] != 0; specicalFlags_singleQuotesFlags[i] = specicalFlags_singleQuotes[i] != 0; } replaceChars['\0'] = '0'; replaceChars['\1'] = '1'; replaceChars['\2'] = '2'; replaceChars['\3'] = '3'; replaceChars['\4'] = '4'; replaceChars['\5'] = '5'; replaceChars['\6'] = '6'; replaceChars['\7'] = '7'; replaceChars['\b'] = 'b'; // 8 replaceChars['\t'] = 't'; // 9 replaceChars['\n'] = 'n'; // 10 replaceChars['\u000B'] = 'v'; // 11 replaceChars['\f'] = 'f'; // 12 replaceChars['\r'] = 'r'; // 13 replaceChars['\"'] = '"'; // 34 replaceChars['\''] = '\''; // 39 replaceChars['/'] = '/'; // 47 replaceChars['\\'] = '\\'; // 92 } public final static char[] ASCII_CHARS = { '0', '0', '0', '1', '0', '2', '0', '3', '0', '4', '0', '5', '0', '6', '0', '7', '0', '8', '0', '9', '0', 'A', '0', 'B', '0', 'C', '0', 'D', '0', 'E', '0', 'F', '1', '0', '1', '1', '1', '2', '1', '3', '1', '4', '1', '5', '1', '6', '1', '7', '1', '8', '1', '9', '1', 'A', '1', 'B', '1', 'C', '1', 'D', '1', 'E', '1', 'F', '2', '0', '2', '1', '2', '2', '2', '3', '2', '4', '2', '5', '2', '6', '2', '7', '2', '8', '2', '9', '2', 'A', '2', 'B', '2', 'C', '2', 'D', '2', 'E', '2', 'F', }; public static void close(Closeable x) { if (x != null) { try { x.close(); } catch (Exception e) { // skip } } } // Requires positive x public static int stringSize(long x) { long p = 10; for (int i = 1; i < 19; i++) { if (x < p) return i; p = 10 * p; } return 19; } public static void getChars(long i, int index, char[] buf) { long q; int r; int charPos = index; char sign = 0; if (i < 0) { sign = '-'; i = -i; } // Get 2 digits/iteration using longs until quotient fits into an int while (i > Integer.MAX_VALUE) { q = i / 100; // really: r = i - (q * 100); r = (int) (i - ((q << 6) + (q << 5) + (q << 2))); i = q; buf[--charPos] = DigitOnes[r]; buf[--charPos] = DigitTens[r]; } // Get 2 digits/iteration using ints int q2; int i2 = (int) i; while (i2 >= 65536) { q2 = i2 / 100; // really: r = i2 - (q * 100); r = i2 - ((q2 << 6) + (q2 << 5) + (q2 << 2)); i2 = q2; buf[--charPos] = DigitOnes[r]; buf[--charPos] = DigitTens[r]; } // Fall thru to fast mode for smaller numbers // assert(i2 <= 65536, i2); for (;;) { q2 = (i2 * 52429) >>> (16 + 3); r = i2 - ((q2 << 3) + (q2 << 1)); // r = i2-(q2*10) ... buf[--charPos] = digits[r]; i2 = q2; if (i2 == 0) break; } if (sign != 0) { buf[--charPos] = sign; } } /** * Places characters representing the integer i into the character array buf. The characters are placed into the * buffer backwards starting with the least significant digit at the specified index (exclusive), and working * backwards from there. Will fail if i == Integer.MIN_VALUE */ public static void getChars(int i, int index, char[] buf) { int q, r; int charPos = index; char sign = 0; if (i < 0) { sign = '-'; i = -i; } // Generate two digits per iteration while (i >= 65536) { q = i / 100; // really: r = i - (q * 100); r = i - ((q << 6) + (q << 5) + (q << 2)); i = q; buf[--charPos] = DigitOnes[r]; buf[--charPos] = DigitTens[r]; } // Fall thru to fast mode for smaller numbers // assert(i <= 65536, i); for (;;) { q = (i * 52429) >>> (16 + 3); r = i - ((q << 3) + (q << 1)); // r = i-(q*10) ... buf[--charPos] = digits[r]; i = q; if (i == 0) break; } if (sign != 0) { buf[--charPos] = sign; } } public static void getChars(byte b, int index, char[] buf) { int i = b; int q, r; int charPos = index; char sign = 0; if (i < 0) { sign = '-'; i = -i; } // Fall thru to fast mode for smaller numbers // assert(i <= 65536, i); for (;;) { q = (i * 52429) >>> (16 + 3); r = i - ((q << 3) + (q << 1)); // r = i-(q*10) ... buf[--charPos] = digits[r]; i = q; if (i == 0) break; } if (sign != 0) { buf[--charPos] = sign; } } /** * All possible chars for representing a number as a String */ final static char[] digits = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' }; final static char[] DigitTens = { '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '2', '2', '2', '2', '2', '2', '2', '2', '2', '2', '3', '3', '3', '3', '3', '3', '3', '3', '3', '3', '4', '4', '4', '4', '4', '4', '4', '4', '4', '4', '5', '5', '5', '5', '5', '5', '5', '5', '5', '5', '6', '6', '6', '6', '6', '6', '6', '6', '6', '6', '7', '7', '7', '7', '7', '7', '7', '7', '7', '7', '8', '8', '8', '8', '8', '8', '8', '8', '8', '8', '9', '9', '9', '9', '9', '9', '9', '9', '9', '9', }; final static char[] DigitOnes = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', }; final static int[] sizeTable = { 9, 99, 999, 9999, 99999, 999999, 9999999, 99999999, 999999999, Integer.MAX_VALUE }; // Requires positive x public static int stringSize(int x) { for (int i = 0;; i++) { if (x <= sizeTable[i]) { return i + 1; } } } public static void decode(CharsetDecoder charsetDecoder, ByteBuffer byteBuf, CharBuffer charByte) { try { CoderResult cr = charsetDecoder.decode(byteBuf, charByte, true); if (!cr.isUnderflow()) { cr.throwException(); } cr = charsetDecoder.flush(charByte); if (!cr.isUnderflow()) { cr.throwException(); } } catch (CharacterCodingException x) { // Substitution is always enabled, // so this shouldn't happen throw new JSONException("utf8 decode error, " + x.getMessage(), x); } } public static boolean firstIdentifier(char ch) { return ch < IOUtils.firstIdentifierFlags.length && IOUtils.firstIdentifierFlags[ch]; } public static boolean isIdent(char ch) { return ch < identifierFlags.length && identifierFlags[ch]; } public static final char[] CA = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".toCharArray(); public static final int[] IA = new int[256]; static { Arrays.fill(IA, -1); for (int i = 0, iS = CA.length; i < iS; i++) IA[CA[i]] = i; IA['='] = 0; } /** * Decodes a BASE64 encoded char array that is known to be resonably well formatted. The method is about twice as * fast as #decode(char[]). The preconditions are:<br> * + The array must have a line length of 76 chars OR no line separators at all (one line).<br> * + Line separator must be "\r\n", as specified in RFC 2045 + The array must not contain illegal characters within * the encoded string<br> * + The array CAN have illegal characters at the beginning and end, those will be dealt with appropriately.<br> * * @param chars The source array. Length 0 will return an empty array. <code>null</code> will throw an exception. * @return The decoded array of bytes. May be of length 0. */ public static byte[] decodeBase64(char[] chars, int offset, int charsLen) { // Check special case if (charsLen == 0) { return new byte[0]; } int sIx = offset, eIx = offset + charsLen - 1; // Start and end index after trimming. // Trim illegal chars from start while (sIx < eIx && IA[chars[sIx]] < 0) sIx++; // Trim illegal chars from end while (eIx > 0 && IA[chars[eIx]] < 0) eIx--; // get the padding count (=) (0, 1 or 2) int pad = chars[eIx] == '=' ? (chars[eIx - 1] == '=' ? 2 : 1) : 0; // Count '=' at end. int cCnt = eIx - sIx + 1; // Content count including possible separators int sepCnt = charsLen > 76 ? (chars[76] == '\r' ? cCnt / 78 : 0) << 1 : 0; int len = ((cCnt - sepCnt) * 6 >> 3) - pad; // The number of decoded bytes byte[] bytes = new byte[len]; // Preallocate byte[] of exact length // Decode all but the last 0 - 2 bytes. int d = 0; for (int cc = 0, eLen = (len / 3) * 3; d < eLen;) { // Assemble three bytes into an int from four "valid" characters. int i = IA[chars[sIx++]] << 18 | IA[chars[sIx++]] << 12 | IA[chars[sIx++]] << 6 | IA[chars[sIx++]]; // Add the bytes bytes[d++] = (byte) (i >> 16); bytes[d++] = (byte) (i >> 8); bytes[d++] = (byte) i; // If line separator, jump over it. if (sepCnt > 0 && ++cc == 19) { sIx += 2; cc = 0; } } if (d < len) { // Decode last 1-3 bytes (incl '=') into 1-3 bytes int i = 0; for (int j = 0; sIx <= eIx - pad; j++) i |= IA[chars[sIx++]] << (18 - j * 6); for (int r = 16; d < len; r -= 8) bytes[d++] = (byte) (i >> r); } return bytes; } public static byte[] decodeBase64(String chars, int offset, int charsLen) { // Check special case if (charsLen == 0) { return new byte[0]; } int sIx = offset, eIx = offset + charsLen - 1; // Start and end index after trimming. // Trim illegal chars from start while (sIx < eIx && IA[chars.charAt(sIx)] < 0) sIx++; // Trim illegal chars from end while (eIx > 0 && IA[chars.charAt(eIx)] < 0) eIx--; // get the padding count (=) (0, 1 or 2) int pad = chars.charAt(eIx) == '=' ? (chars.charAt(eIx - 1) == '=' ? 2 : 1) : 0; // Count '=' at end. int cCnt = eIx - sIx + 1; // Content count including possible separators int sepCnt = charsLen > 76 ? (chars.charAt(76) == '\r' ? cCnt / 78 : 0) << 1 : 0; int len = ((cCnt - sepCnt) * 6 >> 3) - pad; // The number of decoded bytes byte[] bytes = new byte[len]; // Preallocate byte[] of exact length // Decode all but the last 0 - 2 bytes. int d = 0; for (int cc = 0, eLen = (len / 3) * 3; d < eLen;) { // Assemble three bytes into an int from four "valid" characters. int i = IA[chars.charAt(sIx++)] << 18 | IA[chars.charAt(sIx++)] << 12 | IA[chars.charAt(sIx++)] << 6 | IA[chars.charAt(sIx++)]; // Add the bytes bytes[d++] = (byte) (i >> 16); bytes[d++] = (byte) (i >> 8); bytes[d++] = (byte) i; // If line separator, jump over it. if (sepCnt > 0 && ++cc == 19) { sIx += 2; cc = 0; } } if (d < len) { // Decode last 1-3 bytes (incl '=') into 1-3 bytes int i = 0; for (int j = 0; sIx <= eIx - pad; j++) i |= IA[chars.charAt(sIx++)] << (18 - j * 6); for (int r = 16; d < len; r -= 8) bytes[d++] = (byte) (i >> r); } return bytes; } /** * Decodes a BASE64 encoded string that is known to be resonably well formatted. The method is about twice as fast * as decode(String). The preconditions are:<br> * + The array must have a line length of 76 chars OR no line separators at all (one line).<br> * + Line separator must be "\r\n", as specified in RFC 2045 + The array must not contain illegal characters within * the encoded string<br> * + The array CAN have illegal characters at the beginning and end, those will be dealt with appropriately.<br> * * @param s The source string. Length 0 will return an empty array. <code>null</code> will throw an exception. * @return The decoded array of bytes. May be of length 0. */ public static byte[] decodeBase64(String s) { // Check special case int sLen = s.length(); if (sLen == 0) { return new byte[0]; } int sIx = 0, eIx = sLen - 1; // Start and end index after trimming. // Trim illegal chars from start while (sIx < eIx && IA[s.charAt(sIx) & 0xff] < 0) sIx++; // Trim illegal chars from end while (eIx > 0 && IA[s.charAt(eIx) & 0xff] < 0) eIx--; // get the padding count (=) (0, 1 or 2) int pad = s.charAt(eIx) == '=' ? (s.charAt(eIx - 1) == '=' ? 2 : 1) : 0; // Count '=' at end. int cCnt = eIx - sIx + 1; // Content count including possible separators int sepCnt = sLen > 76 ? (s.charAt(76) == '\r' ? cCnt / 78 : 0) << 1 : 0; int len = ((cCnt - sepCnt) * 6 >> 3) - pad; // The number of decoded bytes byte[] dArr = new byte[len]; // Preallocate byte[] of exact length // Decode all but the last 0 - 2 bytes. int d = 0; for (int cc = 0, eLen = (len / 3) * 3; d < eLen;) { // Assemble three bytes into an int from four "valid" characters. int i = IA[s.charAt(sIx++)] << 18 | IA[s.charAt(sIx++)] << 12 | IA[s.charAt(sIx++)] << 6 | IA[s.charAt(sIx++)]; // Add the bytes dArr[d++] = (byte) (i >> 16); dArr[d++] = (byte) (i >> 8); dArr[d++] = (byte) i; // If line separator, jump over it. if (sepCnt > 0 && ++cc == 19) { sIx += 2; cc = 0; } } if (d < len) { // Decode last 1-3 bytes (incl '=') into 1-3 bytes int i = 0; for (int j = 0; sIx <= eIx - pad; j++) i |= IA[s.charAt(sIx++)] << (18 - j * 6); for (int r = 16; d < len; r -= 8) dArr[d++] = (byte) (i >> r); } return dArr; } public static int encodeUTF8(char[] sa, int sp, int len, byte[] da) { int sl = sp + len; int dp = 0; int dlASCII = dp + Math.min(len, da.length); // ASCII only optimized loop while (dp < dlASCII && sa[sp] < '\u0080') { da[dp++] = (byte) sa[sp++]; } while (sp < sl) { char c = sa[sp++]; if (c < 0x80) { // Have at most seven bits da[dp++] = (byte) c; } else if (c < 0x800) { // 2 bytes, 11 bits da[dp++] = (byte) (0xc0 | (c >> 6)); da[dp++] = (byte) (0x80 | (c & 0x3f)); } else if (c >= '\uD800' && c < ('\uDFFF' + 1)) { //Character.isSurrogate(c) but 1.7 final int uc; int ip = sp - 1; if (Character.isHighSurrogate(c)) { if (sl - ip < 2) { uc = -1; } else { char d = sa[ip + 1]; if (Character.isLowSurrogate(d)) { uc = Character.toCodePoint(c, d); } else { throw new JSONException("encodeUTF8 error", new MalformedInputException(1)); } } } else { if (Character.isLowSurrogate(c)) { throw new JSONException("encodeUTF8 error", new MalformedInputException(1)); } else { uc = c; } } if (uc < 0) { da[dp++] = (byte) '?'; } else { da[dp++] = (byte) (0xf0 | ((uc >> 18))); da[dp++] = (byte) (0x80 | ((uc >> 12) & 0x3f)); da[dp++] = (byte) (0x80 | ((uc >> 6) & 0x3f)); da[dp++] = (byte) (0x80 | (uc & 0x3f)); sp++; // 2 chars } } else { // 3 bytes, 16 bits da[dp++] = (byte) (0xe0 | ((c >> 12))); da[dp++] = (byte) (0x80 | ((c >> 6) & 0x3f)); da[dp++] = (byte) (0x80 | (c & 0x3f)); } } return dp; } public static int decodeUTF8(byte[] sa, int sp, int len, char[] da) { final int sl = sp + len; int dp = 0; int dlASCII = Math.min(len, da.length); // ASCII only optimized loop while (dp < dlASCII && sa[sp] >= 0) da[dp++] = (char) sa[sp++]; while (sp < sl) { int b1 = sa[sp++]; if (b1 >= 0) { // 1 byte, 7 bits: 0xxxxxxx da[dp++] = (char) b1; } else if ((b1 >> 5) == -2 && (b1 & 0x1e) != 0) { // 2 bytes, 11 bits: 110xxxxx 10xxxxxx if (sp < sl) { int b2 = sa[sp++]; if ((b2 & 0xc0) != 0x80) { // isNotContinuation(b2) return -1; } else { da[dp++] = (char) (((b1 << 6) ^ b2)^ (((byte) 0xC0 << 6) ^ ((byte) 0x80 << 0))); } continue; } return -1; } else if ((b1 >> 4) == -2) { // 3 bytes, 16 bits: 1110xxxx 10xxxxxx 10xxxxxx if (sp + 1 < sl) { int b2 = sa[sp++]; int b3 = sa[sp++]; if ((b1 == (byte) 0xe0 && (b2 & 0xe0) == 0x80) // || (b2 & 0xc0) != 0x80 // || (b3 & 0xc0) != 0x80) { // isMalformed3(b1, b2, b3) return -1; } else { char c = (char)((b1 << 12) ^ (b2 << 6) ^ (b3 ^ (((byte) 0xE0 << 12) ^ ((byte) 0x80 << 6) ^ ((byte) 0x80 << 0)))); boolean isSurrogate = c >= Character.MIN_SURROGATE && c < (Character.MAX_SURROGATE + 1); if (isSurrogate) { return -1; } else { da[dp++] = c; } } continue; } return -1; } else if ((b1 >> 3) == -2) { // 4 bytes, 21 bits: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx if (sp + 2 < sl) { int b2 = sa[sp++]; int b3 = sa[sp++]; int b4 = sa[sp++]; int uc = ((b1 << 18) ^ (b2 << 12) ^ (b3 << 6) ^ (b4 ^ (((byte) 0xF0 << 18) ^ ((byte) 0x80 << 12) ^ ((byte) 0x80 << 6) ^ ((byte) 0x80 << 0)))); if (((b2 & 0xc0) != 0x80 || (b3 & 0xc0) != 0x80 || (b4 & 0xc0) != 0x80) // isMalformed4 || // shortest form check !Character.isSupplementaryCodePoint(uc)) { return -1; } else { da[dp++] = (char) ((uc >>> 10) + (Character.MIN_HIGH_SURROGATE - (Character.MIN_SUPPLEMENTARY_CODE_POINT >>> 10))); // Character.highSurrogate(uc); da[dp++] = (char) ((uc & 0x3ff) + Character.MIN_LOW_SURROGATE); // Character.lowSurrogate(uc); } continue; } return -1; } else { return -1; } } return dp; } /** * @deprecated */ public static String readAll(Reader reader) { StringBuilder buf = new StringBuilder(); try { char[] chars = new char[2048]; for (;;) { int len = reader.read(chars, 0, chars.length); if (len < 0) { break; } buf.append(chars, 0, len); } } catch(Exception ex) { throw new JSONException("read string from reader error", ex); } return buf.toString(); } }