/*
 * Copyright (C) 2007-2009 KenD00
 * 
 * This file is part of DumpHD.
 * 
 * DumpHD is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package dumphd.util;

/**
 * Provides methods to get and set (multi)byte-values from byte-arrays. No checks are performed before an operation, may result in exceptions.
 * Multibyte-values are treated big-endian!
 * 
 * @author KenD00  
 */
public class ByteArray {

   /**
    * @param source Source byte-array
    * @param index Starting index
    * @return Byte (unsigned) at index as int
    */
   public static int getUByte(byte[] source, int index) {
      return (int)source[index] & 0xFF;
   }

   /**
    * @param source Source byte-array
    * @param index Starting index
    * @return Short (unsigned) starting at index as int, 2 bytes get read
    */
   public static int getUShort(byte[] source, int index) {
      int output = ((int)source[index] & 0xFF) << 8;
      output |= (int)source[index+1] & 0xFF;
      return output;
   }

   /**
    * @param source Source byte-array
    * @param index Starting index
    * @return Int (unsigned) starting at index as long, 4 bytes get read
    */
   public static long getUInt(byte[] source, int index) {
      long output = ((long)source[index] & 0xFF) << 24;
      output |= ((long)source[index+1] & 0xFF) << 16;
      output |= ((long)source[index+2] & 0xFF) << 8;
      output |= ((long)source[index+3] & 0xFF);
      return output;
   }
   
   /**
    * @param source Source byte-aray
    * @param index Starting index
    * @return Int (signed) starting at index as int, 4 bytes get read
    */
   public static int getInt(byte[] source, int index) {
      int output = ((int)source[index] & 0xFF) << 24;
      output |= ((int)source[index+1] & 0xFF) << 16;
      output |= ((int)source[index+2] & 0xFF) << 8;
      output |= ((int)source[index+3] & 0xFF);
      return output;
   }

   /**
    * @param source Source byte-array
    * @param index Starting index
    * @return Long (signed) starting at index as long, 8 bytes get read
    */
   public static long getLong(byte[] source, int index) {
      long output = ((long)source[index] & 0xFF) << 56;
      output |= ((long)source[index + 1] & 0xFF) << 48;
      output |= ((long)source[index + 2] & 0xFF) << 40;
      output |= ((long)source[index + 3] & 0xFF) << 32;
      output |= ((long)source[index + 4] & 0xFF) << 24;
      output |= ((long)source[index + 5] & 0xFF) << 16;
      output |= ((long)source[index + 6] & 0xFF) << 8;
      output |= (long)source[index + 7] & 0xFF;
      return output;
   }

   /**
    * @param source Source byte-array
    * @param index Starting index
    * @param length Number of bytes getting read (must be 1 - 8)
    * @return Long (signed) starting at index as long, length bytes get read
    */
   public static long getVarLong(byte[] source, int index, int length) {
      long output = 0;
      for (int i = 0; i < length; i++) {
         output |= ((long)source[index + i] & 0xFF) << ((length - i - 1) * 8);
      }
      return output;
   }

   /**
    * @param source Byte-array to write to
    * @param index Starting index
    * @param data Data to write, one byte gets written
    */
   public static void setByte(byte[] source, int index, int data) {
      source[index] = (byte)data;
   }

   /**
    * @param source Byte-array to write to
    * @param index Starting index
    * @param data Data to write, two bytes get written
    */
   public static void setShort(byte[] source, int index, int data) {
      source[index+1] = (byte)data;
      data = data >>> 8;
      source[index] = (byte)data;
   }

   /**
    * @param source Byte-array to write to
    * @param index Starting index
    * @param data Data to write, four bytes get written
    */
   public static void setInt(byte[] source, int index, int data) {
      source[index+3] = (byte)data;
      data = data >>> 8;
      source[index+2] = (byte)data;
      data = data >>> 8;
      source[index+1] = (byte)data;
      data = data >>> 8;
      source[index] = (byte)data;
   }

   /**
    * @param source Byte-array to write to
    * @param index Starting index
    * @param data Data to write, eight bytes get written
    */
   public static void setLong(byte[] source, int index, long data) {
      source[index + 7] = (byte)data;
      data = data >>> 8;
      source[index + 6] = (byte)data;
      data = data >>> 8;
      source[index + 5] = (byte)data;
      data = data >>> 8;
      source[index + 4] = (byte)data;
      data = data >>> 8;
      source[index + 3] = (byte)data;
      data = data >>> 8;
      source[index + 2] = (byte)data;
      data = data >>> 8;
      source[index + 1] = (byte)data;
      data = data >>> 8;
      source[index] = (byte)data;
   }

   /**
    * @param source Byte-array to write to
    * @param index Starting index
    * @param data Data to write
    * @param length Number of bytes getting written (must be 1 - 8)
    */
   public static void setVarLong(byte[] source, int index, long data, int length) {
      for (int i = 0; i < length; i++) {
         source[index + length - i - 1] = (byte)data;
         data = data >>> 8;
      }
   }
}