Path: blob/master/jcl/src/openj9.dataaccess/share/classes/com/ibm/dataaccess/ByteArrayUnmarshaller.java
12558 views
/*[INCLUDE-IF DAA]*/1/*******************************************************************************2* Copyright (c) 2013, 2020 IBM Corp. and others3*4* This program and the accompanying materials are made available under5* the terms of the Eclipse Public License 2.0 which accompanies this6* distribution and is available at https://www.eclipse.org/legal/epl-2.0/7* or the Apache License, Version 2.0 which accompanies this distribution and8* is available at https://www.apache.org/licenses/LICENSE-2.0.9*10* This Source Code may also be made available under the following11* Secondary Licenses when the conditions for such availability set12* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU13* General Public License, version 2 with the GNU Classpath14* Exception [1] and GNU General Public License, version 2 with the15* OpenJDK Assembly Exception [2].16*17* [1] https://www.gnu.org/software/classpath/license.html18* [2] http://openjdk.java.net/legal/assembly-exception.html19*20* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception21*******************************************************************************/22package com.ibm.dataaccess;2324/**25* Conversion routines to unmarshall Java binary types (short, int, long, float,26* double) from byte arrays.27*28* <p>29* With sign extensions enabled, the marshalled data is interpreted as signed30* and the data will be appropriately converted into the return type container.31* With sign extensions disabled, unfilled bits in the container will be set to32* zero. For example, <code>-1</code> as one signed byte is <code>0xFF</code>.33* Using <code>readShort</code> with <code>signExtend</code> true, the resultant34* short will contain <code>0xFFFF</code>, which is <code>-1</code> in Java's35* signed format. With <code>signExtend</code> false, the resultant short will36* contain <code>0x00FF</code>, which is <code>255</code>.37* </p>38*39* @author IBM40* @version $Revision$ on $Date$41*/42public final class ByteArrayUnmarshaller {4344// private constructor, class contains only static methods.45private ByteArrayUnmarshaller() {46super();47}4849/**50* Returns a short value copied from two consecutive bytes of the byte array51* starting at the offset.52*53* @param byteArray54* source55* @param offset56* offset in the byte array57* @param bigEndian58* if false the bytes will be copied in reverse (little endian)59* order60*61* @return short62*63* @throws NullPointerException64* if <code>byteArray</code> is null65* @throws ArrayIndexOutOfBoundsException66* if an invalid array access occurs67*/68public static short readShort(byte[] byteArray, int offset,69boolean bigEndian) {70if ((offset + 2 > byteArray.length) || (offset < 0))71throw new ArrayIndexOutOfBoundsException("Array access index out of bounds. " +72"readShort is trying to access byteArray[" + offset + "] and byteArray[" + (offset + 1) + "], " +73" but valid indices are from 0 to " + (byteArray.length - 1) + ".");7475if (bigEndian)76return readShort_(byteArray, offset, true);77else78return readShort_(byteArray, offset, false);79}8081private static short readShort_(byte[] byteArray, int offset,82boolean bigEndian) {83if (bigEndian) {84return (short) (((byteArray[offset] & 0xFF) << 8) | ((byteArray[offset + 1] & 0xFF)));85} else {86return (short) (((byteArray[offset + 1] & 0xFF) << 8) | ((byteArray[offset] & 0xFF)));87}88}8990/**91* Returns a short value copied from zero to two consecutive bytes of the92* byte array starting at the offset.93*94* @param byteArray95* source96* @param offset97* offset in the byte array98* @param bigEndian99* if false the bytes will be copied in reverse (little endian)100* order101* @param numBytes102* the number of bytes to unmarshall, must be 0-2 inclusive103* @param signExtend104* if true and <code>numBytes < 2</code> then the topmost105* bytes of the returned short will be sign extended106*107* @return long108*109* @throws NullPointerException110* if <code>byteArray</code> is null111* @throws IllegalArgumentException112* if <code>numBytes < 0</code> or113* <code>numBytes > 2</code>114* @throws ArrayIndexOutOfBoundsException115* if an invalid array access occurs116*/117public static short readShort(byte[] byteArray, int offset,118boolean bigEndian, int numBytes, boolean signExtend)119{120if ((offset + numBytes > byteArray.length) || offset < 0)121throw new ArrayIndexOutOfBoundsException("Access offset must be positive or zero and last byte must be in range.");122if (numBytes < 0 || numBytes > 2)123throw new IllegalArgumentException("numBytes == " + numBytes);124125if (bigEndian)126{127if (signExtend)128return readShort_(byteArray, offset, true, numBytes, true);129else130return readShort_(byteArray, offset, true, numBytes, false);131}132else133{134if (signExtend)135return readShort_(byteArray, offset, false, numBytes, true);136else137return readShort_(byteArray, offset, false, numBytes, false);138}139}140141private static short readShort_(byte[] byteArray, int offset,142boolean bigEndian, int numBytes, boolean signExtend) {143int i = offset;144switch (numBytes) {145case 0:146return 0;147case 1:148if (signExtend)149return byteArray[i];150else151return (short) (byteArray[i] & 0x00FF);152case 2:153if (bigEndian) {154return (short) (((byteArray[i] & 0xFF) << 8) | ((byteArray[i + 1] & 0xFF)));155} else {156return (short) (((byteArray[i + 1] & 0xFF) << 8) | ((byteArray[i] & 0xFF)));157}158default:159return 0;160}161}162163/**164* Returns an int value copied from four consecutive bytes starting at the165* offset.166*167* @param byteArray168* source169* @param offset170* offset in the byte array171* @param bigEndian172* if false the bytes will be copied in reverse (little endian)173* order174*175* @return int176*177* @throws NullPointerException178* if byteArray is null179* @throws ArrayIndexOutOfBoundsException180* if an invalid array access occurs181*/182public static int readInt(byte[] byteArray, int offset, boolean bigEndian) {183if ((offset + 4 > byteArray.length) || (offset < 0))184throw new ArrayIndexOutOfBoundsException("Array access index out of bounds. " +185"readInt is trying to access byteArray[" + offset + "] to byteArray[" + (offset + 3) + "], " +186" but valid indices are from 0 to " + (byteArray.length - 1) + ".");187188if (bigEndian)189{190return readInt_(byteArray, offset, true);191}192else193{194return readInt_(byteArray, offset, false);195}196}197198private static int readInt_(byte[] byteArray, int offset, boolean bigEndian) {199if (bigEndian) {200return ((byteArray[offset] & 0xFF) << 24)201| ((byteArray[offset + 1] & 0xFF) << 16)202| ((byteArray[offset + 2] & 0xFF) << 8)203| ((byteArray[offset + 3] & 0xFF));204} else {205return ((byteArray[offset + 3] & 0xFF) << 24)206| ((byteArray[offset + 2] & 0xFF) << 16)207| ((byteArray[offset + 1] & 0xFF) << 8)208| ((byteArray[offset] & 0xFF));209}210}211212/**213* Returns an int value copied from zero to four consecutive bytes of the214* byte array starting at the offset.215*216* @param byteArray217* source218* @param offset219* offset in the byte array220* @param bigEndian221* if false the bytes will be copied in reverse (little endian)222* order223* @param numBytes224* the number of bytes to unmarshall, must be 0-4 inclusive225* @param signExtend226* if true and <code>numBytes < 4</code> then the topmost227* bytes of the returned int will be sign extended228*229* @return int230*231* @throws NullPointerException232* if <code>byteArray</code> is null233* @throws IllegalArgumentException234* if <code>numBytes < 0</code> or235* <code>numBytes > 4</code>236* @throws ArrayIndexOutOfBoundsException237* if an invalid array access occurs238*/239public static int readInt(byte[] byteArray, int offset, boolean bigEndian,240int numBytes, boolean signExtend)241{242if ((offset + numBytes > byteArray.length) || (offset < 0))243throw new ArrayIndexOutOfBoundsException("Access offset must be positive or zero and last byte must be in range.");244if (numBytes < 0 || numBytes > 4)245throw new IllegalArgumentException("numBytes == " + numBytes);246247if (bigEndian)248{249if (signExtend)250return readInt_(byteArray, offset, true, numBytes, true);251else252return readInt_(byteArray, offset, true, numBytes, false);253}254else255{256if (signExtend)257return readInt_(byteArray, offset, false, numBytes, true);258else259return readInt_(byteArray, offset, false, numBytes, false);260}261}262263private static int readInt_(byte[] byteArray, int offset, boolean bigEndian,264int numBytes, boolean signExtend) {265int i = offset;266int answer;267switch (numBytes) {268case 0:269return 0;270case 1:271if (signExtend)272return byteArray[i];273else274return byteArray[i] & 0x000000FF;275case 2:276if (bigEndian) {277answer = (((byteArray[i] & 0xFF) << 8) | (byteArray[i + 1] & 0xFF));278} else {279answer = (((byteArray[i + 1] & 0xFF) << 8) | (byteArray[i] & 0xFF));280}281if (signExtend)282return (short) answer;283else284return answer & 0x0000FFFF;285case 3:286if (bigEndian) {287answer = ((byteArray[i] & 0xFF) << 16)288| ((byteArray[i + 1] & 0xFF) << 8)289| ((byteArray[i + 2] & 0xFF));290} else {291answer = ((byteArray[i + 2] & 0xFF) << 16)292| ((byteArray[i + 1] & 0xFF) << 8)293| ((byteArray[i] & 0xFF));294}295/* if the most significant bit is 1, we need to do sign extension */296if (signExtend && (answer & (1 << (3 * 8 - 1))) != 0) {297answer |= 0xFF000000;298}299return answer;300case 4:301if (bigEndian) {302return ((byteArray[i] & 0xFF) << 24)303| ((byteArray[i + 1] & 0xFF) << 16)304| ((byteArray[i + 2] & 0xFF) << 8)305| ((byteArray[i + 3] & 0xFF));306} else {307return ((byteArray[i + 3] & 0xFF) << 24)308| ((byteArray[i + 2] & 0xFF) << 16)309| ((byteArray[i + 1] & 0xFF) << 8)310| ((byteArray[i] & 0xFF));311}312default:313return 0;314}315}316317/**318* Returns a long value copied from eight consecutive bytes of the byte319* array starting at the offset.320*321* @param byteArray322* source323* @param offset324* offset in the byte array325* @param bigEndian326* if false the bytes will be copied in reverse (little endian)327* order328*329* @return long330*331* @throws NullPointerException332* if <code>byteArray</code> is null333* @throws ArrayIndexOutOfBoundsException334* if an invalid array access occurs335*/336public static long readLong(byte[] byteArray, int offset, boolean bigEndian) {337if ((offset + 8 > byteArray.length) || (offset < 0))338throw new ArrayIndexOutOfBoundsException("Array access index out of bounds. " +339"readLong is trying to access byteArray[" + offset + "] to byteArray[" + (offset + 7) + "], " +340" but valid indices are from 0 to " + (byteArray.length - 1) + ".");341342if (bigEndian)343{344return readLong_(byteArray, offset, true);345}346else347{348return readLong_(byteArray, offset, false);349}350}351352private static long readLong_(byte[] byteArray, int offset, boolean bigEndian) {353if (bigEndian) {354return (((long) (byteArray[offset] & 0xFF)) << 56)355| (((long) (byteArray[offset + 1] & 0xFF)) << 48)356| (((long) (byteArray[offset + 2] & 0xFF)) << 40)357| (((long) (byteArray[offset + 3] & 0xFF)) << 32)358| (((long) (byteArray[offset + 4] & 0xFF)) << 24)359| (((byteArray[offset + 5] & 0xFF)) << 16)360| (((byteArray[offset + 6] & 0xFF)) << 8)361| (((byteArray[offset + 7] & 0xFF)));362} else {363return (((long) (byteArray[offset + 7] & 0xFF)) << 56)364| (((long) (byteArray[offset + 6] & 0xFF)) << 48)365| (((long) (byteArray[offset + 5] & 0xFF)) << 40)366| (((long) (byteArray[offset + 4] & 0xFF)) << 32)367| (((long) (byteArray[offset + 3] & 0xFF)) << 24)368| (((byteArray[offset + 2] & 0xFF)) << 16)369| (((byteArray[offset + 1] & 0xFF)) << 8)370| (((byteArray[offset] & 0xFF)));371}372}373374/**375* Returns a long value copied from zero to eight consecutive bytes of the376* byte array starting at the offset.377*378* @param byteArray379* source380* @param offset381* offset in the byte array382* @param bigEndian383* if false the bytes will be copied in reverse (little endian)384* order385* @param numBytes386* the number of bytes to unmarshall, must be 0-8 inclusive387* @param signExtend388* if true and <code>numBytes < 8</code> then the topmost389* bytes of the returned long will be sign extended390*391* @return long392*393* @throws NullPointerException394* if <code>byteArray</code> is null395* @throws IllegalArgumentException396* if <code>numBytes < 0</code> or397* <code>numBytes > 8</code>398* @throws ArrayIndexOutOfBoundsException399* if an invalid array access occurs400*/401public static long readLong(byte[] byteArray, int offset,402boolean bigEndian, int numBytes, boolean signExtend) {403if ((offset + numBytes > byteArray.length) || (offset < 0))404throw new ArrayIndexOutOfBoundsException("Access offset must be positive or zero and last byte must be in range.");405if (numBytes < 0 || numBytes > 8)406throw new IllegalArgumentException("numBytes == " + numBytes);407408if (bigEndian)409{410if (signExtend)411return readLong_(byteArray, offset, true, numBytes, true);412else413return readLong_(byteArray, offset, true, numBytes, false);414}415else416{417if (signExtend)418return readLong_(byteArray, offset, false, numBytes, true);419else420return readLong_(byteArray, offset, false, numBytes, false);421}422}423private static long readLong_(byte[] byteArray, int offset,424boolean bigEndian, int numBytes, boolean signExtend) {425int i = offset;426long answer;427switch (numBytes) {428case 0:429return 0;430case 1:431if (signExtend)432return byteArray[i];433else434return byteArray[i] & 0x00000000000000FFl;435case 2:436if (bigEndian) {437answer = (((byteArray[i] & 0xFF) << 8) | (byteArray[i + 1] & 0xFF));438} else {439answer = (((byteArray[i + 1] & 0xFF) << 8) | (byteArray[i] & 0xFF));440}441if (signExtend)442return (short) answer;443else444return answer & 0x000000000000FFFFl;445case 3:446if (bigEndian) {447answer = (((byteArray[i]) & 0xFF) << 16)448| (((byteArray[i + 1]) & 0xFF) << 8)449| (((byteArray[i + 2]) & 0xFF));450451} else {452answer = (((byteArray[i + 2]) & 0xFF) << 16)453| (((byteArray[i + 1]) & 0xFF) << 8)454| (((byteArray[i]) & 0xFF));455456}457458if (signExtend) {459answer = (answer << 40) >> 40;460}461462return answer;463case 4:464if (bigEndian) {465answer = ((((long) byteArray[i]) & 0xFF) << 24)466| (((byteArray[i + 1]) & 0xFF) << 16)467| (((byteArray[i + 2]) & 0xFF) << 8)468| (((byteArray[i + 3]) & 0xFF));469470} else {471answer = ((((long) byteArray[i + 3]) & 0xFF) << 24)472| (((byteArray[i + 2]) & 0xFF) << 16)473| (((byteArray[i + 1]) & 0xFF) << 8)474| (((byteArray[i]) & 0xFF));475476}477478if (signExtend) {479answer = (answer << 32) >> 32;480}481482return answer;483case 5:484if (bigEndian) {485answer = ((((long) byteArray[i]) & 0xFF) << 32)486| ((((long) byteArray[i + 1]) & 0xFF) << 24)487| (((byteArray[i + 2]) & 0xFF) << 16)488| (((byteArray[i + 3]) & 0xFF) << 8)489| (((byteArray[i + 4]) & 0xFF));490491} else {492answer = ((((long) byteArray[i + 4]) & 0xFF) << 32)493| ((((long) byteArray[i + 3]) & 0xFF) << 24)494| (((byteArray[i + 2]) & 0xFF) << 16)495| (((byteArray[i + 1]) & 0xFF) << 8)496| (((byteArray[i]) & 0xFF));497498}499500if (signExtend) {501answer = (answer << 24) >> 24;502}503return answer;504case 6:505if (bigEndian) {506answer = ((((long) byteArray[i]) & 0xFF) << 40)507| ((((long) byteArray[i + 1]) & 0xFF) << 32)508| ((((long) byteArray[i + 2]) & 0xFF) << 24)509| (((byteArray[i + 3]) & 0xFF) << 16)510| (((byteArray[i + 4]) & 0xFF) << 8)511| (((byteArray[i + 5]) & 0xFF));512513} else {514answer = ((((long) byteArray[i + 5]) & 0xFF) << 40)515| ((((long) byteArray[i + 4]) & 0xFF) << 32)516| ((((long) byteArray[i + 3]) & 0xFF) << 24)517| (((byteArray[i + 2]) & 0xFF) << 16)518| (((byteArray[i + 1]) & 0xFF) << 8)519| (((byteArray[i]) & 0xFF));520}521522if (signExtend) {523answer = (answer << 16) >> 16;524}525return answer;526case 7:527if (bigEndian) {528answer = ((((long) byteArray[i]) & 0xFF) << 48)529| ((((long) byteArray[i + 1]) & 0xFF) << 40)530| ((((long) byteArray[i + 2]) & 0xFF) << 32)531| ((((long) byteArray[i + 3]) & 0xFF) << 24)532| (((byteArray[i + 4]) & 0xFF) << 16)533| (((byteArray[i + 5]) & 0xFF) << 8)534| (((byteArray[i + 6]) & 0xFF));535536} else {537answer = ((((long) byteArray[i + 6]) & 0xFF) << 48)538| ((((long) byteArray[i + 5]) & 0xFF) << 40)539| ((((long) byteArray[i + 4]) & 0xFF) << 32)540| ((((long) byteArray[i + 3]) & 0xFF) << 24)541| (((byteArray[i + 2]) & 0xFF) << 16)542| (((byteArray[i + 1]) & 0xFF) << 8)543| (((byteArray[i]) & 0xFF));544545}546547if (signExtend) {548answer = (answer << 8) >> 8;549}550551return answer;552case 8:553if (bigEndian) {554return ((((long) byteArray[i]) & 0xFF) << 56)555| ((((long) byteArray[i + 1]) & 0xFF) << 48)556| ((((long) byteArray[i + 2]) & 0xFF) << 40)557| ((((long) byteArray[i + 3]) & 0xFF) << 32)558| ((((long) byteArray[i + 4]) & 0xFF) << 24)559| (((byteArray[i + 5]) & 0xFF) << 16)560| (((byteArray[i + 6]) & 0xFF) << 8)561| (((byteArray[i + 7]) & 0xFF));562} else {563return ((((long) byteArray[i + 7]) & 0xFF) << 56)564| ((((long) byteArray[i + 6]) & 0xFF) << 48)565| ((((long) byteArray[i + 5]) & 0xFF) << 40)566| ((((long) byteArray[i + 4]) & 0xFF) << 32)567| ((((long) byteArray[i + 3]) & 0xFF) << 24)568| (((byteArray[i + 2]) & 0xFF) << 16)569| (((byteArray[i + 1]) & 0xFF) << 8)570| (((byteArray[i]) & 0xFF));571}572default:573return 0;574}575}576577/**578* Returns a float value copied from four consecutive bytes of the byte579* array starting at the offset.580*581* @param byteArray582* source583* @param offset584* offset in the byte array585* @param bigEndian586* if false the bytes will be copied in reverse (little endian)587* order588*589* @return float590*591* @throws NullPointerException592* if <code>byteArray</code> is null593* @throws ArrayIndexOutOfBoundsException594* if an invalid array access occurs595*/596public static float readFloat(byte[] byteArray, int offset,597boolean bigEndian) {598if ((offset + 4 > byteArray.length) || (offset < 0))599throw new ArrayIndexOutOfBoundsException("Array access index out of bounds. " +600"readFloat is trying to access byteArray[" + offset + "] to byteArray[" + (offset + 3) + "], " +601" but valid indices are from 0 to " + (byteArray.length - 1) + ".");602603if (bigEndian)604return readFloat_(byteArray, offset, true);605else606return readFloat_(byteArray, offset, false);607}608609private static float readFloat_(byte[] byteArray, int offset,610boolean bigEndian) {611return Float.intBitsToFloat(readInt(byteArray, offset, bigEndian));612}613614/**615* Returns a double value copied from eight consecutive bytes of the byte616* array starting at the offset.617*618* @param byteArray619* source620* @param offset621* offset in the byte array622* @param bigEndian623* if false the bytes will be copied in reverse (little endian)624* order625*626* @return double627*628* @throws NullPointerException629* if <code>byteArray</code> is null630* @throws ArrayIndexOutOfBoundsException631* if an invalid array access occurs632*/633public static double readDouble(byte[] byteArray, int offset,634boolean bigEndian) {635if ((offset + 8 > byteArray.length) || (offset < 0))636throw new ArrayIndexOutOfBoundsException("Array access index out of bounds. " +637"readDouble is trying to access byteArray[" + offset + "] to byteArray[" + (offset + 7) + "], " +638" but valid indices are from 0 to " + (byteArray.length - 1) + ".");639640if (bigEndian)641return readDouble_(byteArray, offset, true);642else643return readDouble_(byteArray, offset, false);644}645private static double readDouble_(byte[] byteArray, int offset,646boolean bigEndian) {647return Double.longBitsToDouble(readLong(byteArray, offset, bigEndian));648}649}650651652