/*
 * COFF_Header.java - This file is part of the Jakstab project.
 * 
 * Copyright 2007-2015 Johannes Kinder <jk@jakstab.org>
 * Copyright (C) 2003 The University of Arizona
 *
 * The original code for this class was taken from "MBEL: The Microsoft 
 * Bytecode Engineering Library" and modified for use with Jakstab.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code 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
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, see <http://www.gnu.org/licenses/>.
 */

package org.jakstab.loader.pe;

import org.jakstab.loader.BinaryParseException;
import org.jakstab.util.BinaryInputBuffer;
import org.jakstab.util.Logger;

/** 
 * This class holds the data from the COFF Header in a PE/COFF file.
 * The COFF header comes right after the PE signature, and right before the PE header.
 * 
 * @author Michael Stepp
 * @author Johannes Kinder
 */
@SuppressWarnings("unused")
class COFF_Header {
	private final static Logger logger = Logger.getLogger(COFF_Header.class);

	// Constants for 'Machine' field /////////////////////////
	private static final int IMAGE_FILE_MACHINE_UNKNOWN = 0x0;     // The contents of this field are assumed to be applicable to any machine type
	private static final int IMAGE_FILE_MACHINE_AM33 = 0x1d3;      // Matsushita AM33
	private static final int IMAGE_FILE_MACHINE_AMD64 = 0x8664;    // x64
	private static final int IMAGE_FILE_MACHINE_ARM = 0x1c0;       // ARM little endian
	private static final int IMAGE_FILE_MACHINE_EBC = 0xebc;       // EFI byte code
	private static final int IMAGE_FILE_MACHINE_I386 = 0x14c;      // Intel 386 or later processors and compatible processors
	private static final int IMAGE_FILE_MACHINE_IA64 = 0x200;      // Intel Itanium processor family
	private static final int IMAGE_FILE_MACHINE_M32R = 0x9041;     // Mitsubishi M32R little endian
	private static final int IMAGE_FILE_MACHINE_MIPS16 = 0x266;    // MIPS16
	private static final int IMAGE_FILE_MACHINE_MIPSFPU = 0x366;   // MIPS with FPU
	private static final int IMAGE_FILE_MACHINE_MIPSFPU16 = 0x466; // MIPS16 with FPU
	private static final int IMAGE_FILE_MACHINE_POWERPC = 0x1f0;   // Power PC little endian
	private static final int IMAGE_FILE_MACHINE_POWERPCFP = 0x1f1; // Power PC with floating point support
	private static final int IMAGE_FILE_MACHINE_R4000 = 0x166;     // MIPS little endian
	private static final int IMAGE_FILE_MACHINE_SH3 = 0x1a2;       // Hitachi SH3
	private static final int IMAGE_FILE_MACHINE_SH3DSP = 0x1a3;    // Hitachi SH3 DSP
	private static final int IMAGE_FILE_MACHINE_SH4 = 0x1a6;       // Hitachi SH4
	private static final int IMAGE_FILE_MACHINE_SH5 = 0x1a8;       // Hitachi SH5
	private static final int IMAGE_FILE_MACHINE_THUMB = 0x1c2;     // Thumb
	private static final int IMAGE_FILE_MACHINE_WCEMIPSV2 = 0x169; // MIPS little endian WCE v2

	// Constants for 'Characteristics' field ///////////////////
	private static final int IMAGE_FILE_RELOCS_STRIPPED          = 0x0001;
	private static final int IMAGE_FILE_EXECUTABLE_IMAGE         = 0x0002;
	private static final int IMAGE_FILE_LINE_NUMS_STRIPPED       = 0x0004;
	private static final int IMAGE_FILE_LOCAL_SYMS_STRIPPED      = 0x0008;
	private static final int IMAGE_FILE_AGGRESIVE_WS_TRIM        = 0x0010;
	private static final int IMAGE_FILE_LARGE_ADDRESS_AWARE      = 0x0020;
	private static final int IMAGE_FILE_BYTES_REVERSED_LO        = 0x0080;
	private static final int IMAGE_FILE_32BIT_MACHINE            = 0x0100;
	private static final int IMAGE_FILE_DEBUG_STRIPPED           = 0x0200;
	private static final int IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP  = 0x0400;
	private static final int IMAGE_FILE_NET_RUN_FROM_SWAP        = 0x0800;
	private static final int IMAGE_FILE_SYSTEM                   = 0x1000;
	private static final int IMAGE_FILE_DLL                      = 0x2000;
	private static final int IMAGE_FILE_UP_SYSTEM_ONLY           = 0x4000;
	private static final int IMAGE_FILE_BYTES_REVERSED_HI        = 0x8000;

	private final int Machine;                 // 2bytes
	private final int NumberOfSections;        // 2bytes
	private final long TimeDateStamp;          // 4bytes
	private final long PointerToSymbolTable;   // 4bytes (==0) (file pointer)
	private final int NumberOfSymbols;        // 4bytes (==0)
	private final int SizeOfOptionalHeader;    // 2bytes
	private final int Characteristics;         // 2bytes

	/** Parses a COFF_Header from an input stream
	 */
	public COFF_Header(BinaryInputBuffer in) throws java.io.IOException, BinaryParseException{
		Machine              = in.readWORD();
		NumberOfSections     = in.readWORD();
		TimeDateStamp        = in.readDWORD();
		PointerToSymbolTable = in.readDWORD();
		NumberOfSymbols      = (int)in.readDWORD();
		SizeOfOptionalHeader = in.readWORD();
		Characteristics      = in.readWORD();

		if (!isX86()) throw new BinaryParseException("Non-x86 COFF files currently not supported!");

		//		logger.debug("COFF Header: {");
		//		logger.debug("  Machine = " + "0x" + Integer.toHexString(Machine));
		//		logger.debug("  NumberOfSections = " + getNumberOfSections());
		//		logger.debug("  TimeDateStamp = " + "0x" + Long.toHexString(TimeDateStamp));
		//		logger.debug("  PointerToSymbolTable = " + "0x" + Long.toHexString(PointerToSymbolTable));
		//		logger.debug("  NumberOfSymbols = " + NumberOfSymbols);
		//		logger.debug("  SizeOfOptionalHeader = " + SizeOfOptionalHeader);
		//		logger.debug("  Characteristics = " + Integer.toBinaryString(Characteristics));
		//		logger.debug("}");
	}

	/**
	 * @return the numberOfSections
	 */
	public int getNumberOfSections() {
		return NumberOfSections;
	}

	/** 
	 * Returns true iff this is a DLL file (according to the flags)
	 */
	public boolean isDLLFile(){
		return ((Characteristics & COFF_Header.IMAGE_FILE_DLL) != 0);
	}

	public boolean isX86() {
		return Machine == IMAGE_FILE_MACHINE_I386;
	}

	public long getPointerToSymbolTable() {
		return PointerToSymbolTable;
	}

	public int getNumberOfSymbols() {
		return NumberOfSymbols;
	}

}


