/* 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 "chordata/Utils.h"

#include "chordata/Result.h"
using namespace Chordata::Result;

namespace Chordata {

HRESULT DIAPEXIS_CALL Scope::GetStringHeapSize(uint32_t *size) const {
	if (size == NULL)		return E_POINTER;
	*size = ssSize;
	return Success::OK;
}

HRESULT DIAPEXIS_CALL Scope::GetBlobHeapSize(uint32_t *size) const {
	if (size == NULL)		return E_POINTER;
	*size = bSize;
	return Success::OK;
}

HRESULT DIAPEXIS_CALL Scope::GetGuidHeapSize(uint32_t *size) const {
	if (size == NULL)		return E_POINTER;
	//*size = (uint32_t) guids.size() << 4;
	*size = gSize;
	return Success::OK;
}

HRESULT DIAPEXIS_CALL Scope::GetUserStringHeapSize(uint32_t *size) const {
	if (size == NULL)		return E_POINTER;
	*size = usSize;
	return Success::OK;
}

HRESULT DIAPEXIS_CALL Scope::GetNumTables(uint32_t *tables) const {
	if (tables == NULL)		return E_POINTER;
	*tables = 47;
	return Success::OK;
}

HRESULT DIAPEXIS_CALL Scope::GetTableIndex(uint32_t token, uint32_t *index) {
	if (index == NULL)		return E_POINTER;
	*index = token >> 24;
	return Success::OK;
}

HRESULT DIAPEXIS_CALL Scope::GetTableInfo(uint32_t table, uint32_t *size, uint32_t *rows, uint32_t *cols, uint32_t *key, const char **name) {
	if (table > 47)			return E_INVALIDARG;
	const ParseData::TableDef &def = *ParseData::Tables[table];

	if (size != NULL)		*size	= (uint32_t) tables[table].size;
	if (rows != NULL)		*rows	= (uint32_t) tables[table].rows.size();
	if (cols != NULL)		*cols	= def.Number;
	if (key != NULL)		*key	= def.Key;
	if (name != NULL)		*name	= def.Name;

	return Success::OK;
}

HRESULT DIAPEXIS_CALL Scope::GetColumnInfo(uint32_t table, uint32_t col, uint32_t *offset, uint32_t *size, uint32_t *type, const char **name) {
	if (table > 47)			return E_INVALIDARG;
	const ParseData::TableDef &def = *ParseData::Tables[table];
	if (col > def.Number)	return E_INVALIDARG;

	if (offset != NULL) {
		uint32_t data(0);
		for (uint32_t i(0); i < col; i++)
			data += types[def.Columns[i].Type];
		*offset = data;
	}

	if (size != NULL)		*size = types[def.Columns[col].Type];
	if (type != NULL)		*type = def.Columns[col].Type;
	if (name != NULL)		*name = def.Columns[col].Name;

	return Success::OK;
}

HRESULT DIAPEXIS_CALL Scope::GetCodedTokenInfo(uint32_t code, uint32_t *number, uint32_t **tokens, const char **name) {
	if (code > 11)		return E_INVALIDARG;
	const ParseData::Code &coded = *ParseData::Coded[code];

	if (name != NULL)		*name = coded.Name;
	if (number != NULL)		*number = coded.Number;
	if (tokens != NULL)		*tokens = coded.Tokens;

	return Success::OK;
}

HRESULT DIAPEXIS_CALL Scope::GetRow(uint32_t table, uint32_t row, void **data) {
	if (table > 47)				return E_INVALIDARG;
	if (data == NULL)			return E_POINTER;
	if (row == 0 || row > tables[table].rows.size())
		return E_INVALIDARG;
	*data = tables[table].rows[row];
	return Success::OK;
}

HRESULT DIAPEXIS_CALL Scope::GetColumn(uint32_t table, uint32_t col, uint32_t row, uint32_t *value) {
	if (value == NULL)	return E_POINTER;

	void *data; HRESULT hr = GetRow(table, row, &data);
	if (hr != Success::OK) return hr;

	uint32_t offset, size, type, val(0);
	hr = GetColumnInfo(table, col, &offset, &size, &type, NULL);
	if (hr != Success::OK) return hr;
	memmove(&val, (char *) data + offset, size);

	if ((type & 0xf0) == 0x40) {
		const uint32_t *mixed = ParseData::Mixed[type & ~0xf0];
		val = (val >> mixed[-1]) | (mixed[val & ~(-1 << mixed[-1])] << 24);
	}

	*value = val;
	return Success::OK;
}

HRESULT DIAPEXIS_CALL Scope::GetString(uint32_t index, const char **data) const {
	if (data == NULL)		return E_POINTER;
	/*if (index >= m_bStrings->Size) *data = NULL;
	else*/ *data = (const char *) sysStrings + index;
	if (**data == '\0') *data = NULL;
	return Success::OK;
}

HRESULT DIAPEXIS_CALL Scope::GetBlob(uint32_t index, uint32_t *size, const void **data) const {
	if (size == NULL)		return E_POINTER;
	if (data == NULL)		return E_POINTER;
	*data = blobs + index;
	*size = Utils::Uncompress<uint32_t>((const uint8_t * &) *data);
	return Success::OK;
}

HRESULT DIAPEXIS_CALL Scope::GetGuid(uint32_t index, const GUID **guid) const {
	if (guid == NULL)		return E_POINTER;
	*guid = &guids[index - 1];
	return Success::OK;
}

HRESULT DIAPEXIS_CALL Scope::GetUserString(uint32_t index, uint32_t *size, const void **data) const {
	return Success::OK;
}

HRESULT DIAPEXIS_CALL Scope::GetNextString(uint32_t index, uint32_t *next) const {
	if (next == NULL)		return E_POINTER;
	uint8_t *data = blobs + index;
	uint32_t size = Utils::Uncompress<uint32_t>((const uint8_t * &) data);
	*next = data + size - blobs;
	return Success::OK;
}

HRESULT DIAPEXIS_CALL Scope::GetNextBlob(uint32_t index, uint32_t *next) const {
	if (next == NULL)		return E_POINTER;
	return Success::OK;
}

HRESULT DIAPEXIS_CALL Scope::GetNextGuid(uint32_t index, uint32_t *next) const {
	if (next == NULL)		return E_POINTER;
	return Success::OK;
}

HRESULT DIAPEXIS_CALL Scope::GetNextUserString(uint32_t index, uint32_t *next) const {
	if (next == NULL)		return E_POINTER;
	return Success::OK;
}


}
