/* Filet - Binary Format Parsing Utility
 * Copyright (C) 2001-2002  Jay Freeman (saurik)
*/

/*
 *        Redistribution and use in source and binary
 * forms, with or without modification, are permitted
 * provided that the following conditions are met:
 * 
 * 1. Redistributions of source code must retain the
 *    above copyright notice, this list of conditions
 *    and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the
 *    above copyright notice, this list of conditions
 *    and the following disclaimer in the documentation
 *    and/or other materials provided with the
 *    distribution.
 * 3. The name of the author may not be used to endorse
 *    or promote products derived from this software
 *    without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS''
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "stdafx.h"
#include "filet/ObjectFile.h"

#include "apr_mmap.h"

using namespace System::Runtime::InteropServices;

namespace Filet {

	ObjectFile::ObjectFile(String *name) :
		m_Name(name),
		m_NTHeaders(NULL)
	{
		apr_pool_t *context;
		apr_pool_create(&context, NULL);

		apr_finfo_t info;

		IntPtr pname = Marshal::StringToHGlobalAnsi(name);

		apr_file_t *hfile;
		apr_mmap_t *hmmap;

		apr_file_open(&hfile, (const char *) pname.ToPointer(), APR_READ, APR_UREAD | APR_GREAD, context);
		apr_file_info_get(&info, APR_FINFO_NORM, file);
		uint32_t errI = apr_mmap_create(&hmmap, file, 0, (apr_size_t) info.size, APR_MMAP_READ, context);

		file = hfile;
		mmap = hmmap;

		m_Base = (uint8_t *) mmap->mm;

		/*m_Handle	= ::CreateFile(m_Name.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
		m_Map		= ::CreateFileMapping(m_Handle, NULL, PAGE_READONLY, 0, 0, NULL);
		m_Base		= (uint8_t *) ::MapViewOfFile(m_Map, FILE_MAP_READ, 0, 0, 0);*/

		// XXX: Check for file lengths, this could be very important :).

		m_DOSHeader	= (Headers::DOS *) m_Base;
		m_JavaHeader = (Headers::Java *) m_Base;

		if (m_DOSHeader->e_magic == Signatures::DOS)
			m_NTHeaders = (Headers::NT32 *) (m_Base + m_DOSHeader->e_lfanew);
	}

	void ObjectFile::Dispose(bool disposing) {
		apr_mmap_delete(mmap);

		/*::UnmapViewOfFile(m_Base);
		::CloseHandle(m_Map);
		::CloseHandle(m_Handle);*/
	}

	void ObjectFile::Dispose() {
		Dispose(true);
	}

	ObjectFile::~ObjectFile() {
		Dispose(false);
	}

	String *ObjectFile::get_Type() {
		if (m_DOSHeader->e_magic == Signatures::DOS) {
			uint8_t *anew = m_Base + m_DOSHeader->e_lfanew;

			if (* (uint32_t *) anew == Signatures::NT) {
				if (Filet::Utils::ImageRvaToVa(m_NTHeaders, m_Base, m_NTHeaders->OptionalHeader.DataDirectory[Filet::PE::DataDirectories::COMDescriptor].VirtualAddress, NULL) != NULL)
					return "COR";
				return "NT";
			} else switch (* (uint16_t *) anew) {
				case Signatures::OS2:
					return "OS2";
				case Signatures::VXD:
					return "VXD";
			} return "DOS";
		} else if (m_JavaHeader->magic == Signatures::Java)
			return "Java";
		return "Unknown";
	}

	uint8_t *ObjectFile::get_Base() {
		return m_Base;
	}

	String *ObjectFile::get_Name() {
		return m_Name;
	}

	void *ObjectFile::FindRVA(uint32_t rva) {
		return Filet::Utils::ImageRvaToVa(m_NTHeaders, m_Base, rva, NULL);
	}

}