/* Chordata - .NET File Format Parser
 * 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 "chordata/Scope.h"
#include "chordata/ParseData.h"

#include "filet/PE.h"
#include "filet/Utils.h"
#include "Headers.h"

namespace Chordata {

Scope::Scope() {}
Scope::~Scope() {}

void Scope::Open(const void *image, uint32_t size, uint32_t flags) {
	const uint8_t *base = (uint8_t *) image;

	Headers::DOS	*dos	= (Headers::DOS *)		base;
	Headers::NT32	*nt		= (Headers::NT32 *)		(base + dos->e_lfanew);
	Headers::COR20	*cor	= (Headers::COR20 *)	Filet::Utils::ImageRvaToVa(nt, (void *) base, nt->OptionalHeader.DataDirectory[Filet::PE::DataDirectories::COMDescriptor].VirtualAddress, NULL);

	Headers::MetaDataRoot		*root		= (Headers::MetaDataRoot *)		Filet::Utils::ImageRvaToVa(nt, (void *) base, cor->MetaData.VirtualAddress, NULL);
	Headers::MetaDataStreams	*streams	= (Headers::MetaDataStreams *)	((uint8_t *) (root + 1) + root->Length);

	str_t version = (str_t) (root + 1);

	Headers::SquigglyStream *squiggly;

	Headers::DataDirectory *stream = (Headers::DataDirectory *) (streams + 1);
	uint8_t * const data = (uint8_t *) root;

	for (uint16_t i(0); i < streams->Streams; i++) {
		const char *name = (const char *) (stream + 1);
		if (strcmp(name, "#Blob") == 0) {
			blobs = data + stream->VirtualAddress;
			bSize = stream->Size;
		} else if (strcmp(name, "#GUID") == 0) {
			/*GUID *guid = (GUID *) (data + stream->VirtualAddress);
			GUID *end = guid + (stream->Size >> 4);
			for (; guid < end; guid++)
				guids.push_back(guid);*/
			guids = (GUID *) (data + stream->VirtualAddress);
			gSize = stream->Size;
		} else if (strcmp(name, "#Strings") == 0) {
			sysStrings = data + stream->VirtualAddress;
			ssSize = stream->Size;
		} else if (strcmp(name, "#US") == 0) {
			userStrings = (wchar_t *) (data + stream->VirtualAddress);
			usSize = stream->Size;
		} else if (strcmp(name, "#~") == 0)
			squiggly = (Headers::SquigglyStream *) (data + stream->VirtualAddress);

		stream = (Headers::DataDirectory *) Filet::Utils::AlignPointer(name + strlen(name) + 1);
	}

	uint32_t *rows = (uint32_t *) (squiggly + 1);

	//memset(m_Tables, 0, sizeof(m_Tables));
	for (uint64_t t(0); t < 64; t++)
		if ((squiggly->Valid & ((uint64_t) 1 << t)) != 0)
			tables[t].rows.resize(*(rows++));

	ZeroMemory(types, sizeof(uint32_t) * 256);
	memmove(types, ParseData::Types, sizeof(ParseData::Types));
	UpdateSize();
	/*if (m_bStrings->Size >= 65536) m_Columns[0x65] = 4;*/

	uint8_t *row = (uint8_t *) rows;
	for (t = 0; t < TABLES; t++) {
		const ParseData::TableDef &table = *ParseData::Tables[t];
		for (uint32_t c(0); c < table.Number; c++)
			tables[t].size += types[table.Columns[c].Type];
		if (tables[t].rows.size() != 0) {
			//for (uint32_t r(0); r < m_Tab
			//tables[t].Data = data;
			row += tables[t].size * tables[t].rows.size();
		}
	}
}

void Scope::UpdateSize() {
}

}