001/**
002 *
003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved.
004 *
005 * This library is free software; you can redistribute it and/or
006 * modify it under the terms of the GNU Lesser General Public
007 * License as published by the Free Software Foundation; either 
008 * version 2.1 of the License, or (at your option) any later version.
009 * 
010 * This library is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013 * Lesser General Public License for more details.
014 * 
015 * You should have received a copy of the GNU Lesser General Public 
016 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
017 * 
018 **/
019package lucee.runtime.crypt;
020
021public final class BinConverter {
022
023  /**
024    * gets bytes from an array into a long
025    * @param buffer where to get the bytes
026    * @param nStartIndex index from where to read the data
027    * @return the 64bit integer
028    */
029  public static long byteArrayToLong(byte[] buffer,int nStartIndex) {
030
031    return (((long)buffer[nStartIndex]) << 56) |
032           ((buffer[nStartIndex + 1] & 0x0ffL) << 48) |
033           ((buffer[nStartIndex + 2] & 0x0ffL) << 40) |
034           ((buffer[nStartIndex + 3] & 0x0ffL) << 32) |
035           ((buffer[nStartIndex + 4] & 0x0ffL) << 24) |
036           ((buffer[nStartIndex + 5] & 0x0ffL) << 16) |
037           ((buffer[nStartIndex + 6] & 0x0ffL) << 8) |
038           ((long)buffer[nStartIndex + 7] & 0x0ff);
039
040  }
041
042  /**
043    * converts a long o bytes which are put into a given array
044    * @param lValue the 64bit integer to convert
045    * @param buffer the target buffer
046    * @param nStartIndex where to place the bytes in the buffer
047    */
048  public static void longToByteArray(long lValue,byte[] buffer,int nStartIndex) {
049    buffer[nStartIndex] = (byte) (lValue >>> 56);
050    buffer[nStartIndex + 1] = (byte) ((lValue >>> 48) & 0x0ff);
051    buffer[nStartIndex + 2] = (byte) ((lValue >>> 40) & 0x0ff);
052    buffer[nStartIndex + 3] = (byte) ((lValue >>> 32) & 0x0ff);
053    buffer[nStartIndex + 4] = (byte) ((lValue >>> 24) & 0x0ff);
054    buffer[nStartIndex + 5] = (byte) ((lValue >>> 16) & 0x0ff);
055    buffer[nStartIndex + 6] = (byte) ((lValue >>> 8) & 0x0ff);
056    buffer[nStartIndex + 7] = (byte) lValue;
057  }
058
059  /**
060    * converts values from an integer array to a long
061    * @param buffer where to get the bytes
062    * @param nStartIndex index from where to read the data
063    * @return the 64bit integer
064    */
065  public static long intArrayToLong(int[] buffer,int nStartIndex) {
066    return (((long) buffer[nStartIndex]) << 32) | (( buffer[nStartIndex + 1]) & 0x0ffffffffL);
067  }
068
069  /**
070    * converts a long to integers which are put into a given array
071    * @param lValue the 64bit integer to convert
072    * @param buffer the target buffer
073    * @param nStartIndex where to place the bytes in the buffer
074    */
075  public static void longToIntArray(long lValue,int[] buffer,int nStartIndex) {
076    buffer[nStartIndex]     = (int) (lValue >>> 32);
077    buffer[nStartIndex + 1] = (int) lValue;
078  }
079
080  /**
081    * makes a long from two integers (treated unsigned)
082    * @param nLo lower 32bits
083    * @param nHi higher 32bits
084    * @return the built long
085    */
086  public static long makeLong(int nLo,int nHi) {
087    return (((long)nHi << 32) | (nLo & 0x00000000ffffffffL));
088  }
089
090  /**
091    * gets the lower 32 bits of a long
092    * @param lVal the long integer
093    * @return lower 32 bits
094    */
095  public static int longLo32(long lVal) {
096    return (int)lVal;
097  }
098
099  /**
100    * gets the higher 32 bits of a long
101    * @param lVal the long integer
102    * @return higher 32 bits
103    */
104  public static int longHi32(long lVal) {
105    return (int)((lVal >>> 32));
106  }
107
108  final static char[] HEXTAB = { '0', '1', '2', '3', '4', '5', '6', '7',
109                                 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
110
111  /**
112    * converts a byte array to a binhex string
113    * @param data the byte array
114    * @return the binhex string
115    */
116  public static String bytesToBinHex(byte[] data) {
117    return bytesToBinHex(data, 0, data.length);
118  }
119
120  /**
121    * converts a byte array to a binhex string
122    * @param data the byte array
123    * @param nStartPos start index where to get the bytes
124    * @param nNumOfBytes number of bytes to convert
125    * @return the binhex string
126    */
127  public static String bytesToBinHex(byte[] data,int nStartPos,int nNumOfBytes) {
128        StringBuilder sbuf = new StringBuilder();
129    sbuf.setLength(nNumOfBytes << 1);
130    int nPos = 0;
131    for (int nI = 0; nI < nNumOfBytes; nI++) {
132      sbuf.setCharAt(nPos++, HEXTAB[(data[nI + nStartPos] >> 4) & 0x0f]);
133      sbuf.setCharAt(nPos++, HEXTAB[data[nI + nStartPos] & 0x0f]);
134    }
135    return sbuf.toString();
136  }
137
138  /**
139    * converts a binhex string back into a byte array (invalid codes will be skipped)
140    * @param sBinHex binhex string
141    * @param data the target array
142    * @param nSrcPos from which character in the string the conversion should begin,
143    *                remember that (nSrcPos modulo 2) should equals 0 normally
144    * @param nDstPos to store the bytes from which position in the array
145    * @param nNumOfBytes number of bytes to extract
146    * @return number of extracted bytes
147    */
148  public static int binHexToBytes(String sBinHex,byte[] data,int nSrcPos,int nDstPos,int nNumOfBytes) {
149    // check for correct ranges
150    int nStrLen = sBinHex.length();
151    int nAvailBytes = (nStrLen - nSrcPos) >> 1;
152    if (nAvailBytes < nNumOfBytes)
153      nNumOfBytes = nAvailBytes;
154    int nOutputCapacity = data.length - nDstPos;
155    if (nNumOfBytes > nOutputCapacity)
156      nNumOfBytes = nOutputCapacity;
157    // convert now
158    int nResult = 0;
159    for (int nI = 0; nI < nNumOfBytes; nI++) {
160      byte bActByte = 0;
161      boolean blConvertOK = true;
162      for (int nJ = 0; nJ < 2; nJ++) {
163        bActByte <<= 4;
164        char cActChar = sBinHex.charAt(nSrcPos++);
165        if ((cActChar >= 'a') && (cActChar <= 'f'))
166          bActByte |= (byte)(cActChar - 'a') + 10;
167        else if ((cActChar >= '0') && (cActChar <= '9'))
168            bActByte |= (byte)(cActChar - '0');
169          else
170            blConvertOK = false;
171      }
172      if (blConvertOK) {
173        data[nDstPos++] = bActByte;
174        nResult++;
175      }
176    }
177    return nResult;
178  }
179
180  /**
181    * converts a byte array into an UNICODE string
182    * @param data the byte array
183    * @param nStartPos where to begin the conversion
184    * @param nNumOfBytes number of bytes to handle
185    * @return the string
186    */
187  public static String byteArrayToUNCString(byte[] data,int nStartPos,int nNumOfBytes) {
188    // we need two bytes for every character
189    nNumOfBytes &= ~1;
190    // enough bytes in the buffer?
191    int nAvailCapacity = data.length - nStartPos;
192    if (nAvailCapacity < nNumOfBytes)
193      nNumOfBytes = nAvailCapacity;
194    StringBuilder sbuf = new StringBuilder();
195    sbuf.setLength(nNumOfBytes >> 1);
196    int nSBufPos = 0;
197    while (nNumOfBytes > 0) {
198      sbuf.setCharAt(nSBufPos++,
199                     (char)((data[nStartPos] << 8) | (data[nStartPos + 1] & 0x0ff)));
200      nStartPos += 2;
201      nNumOfBytes -= 2;
202    }
203    return sbuf.toString();
204  }
205}