/* 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.
*/

#ifndef CHORDATA_SCOPE_H
#define CHORDATA_SCOPE_H

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include "menes-com/Handle.h"
#include "chordata/chordata.h"

#include "IMetaDataInternal.h"

#include "chordata/IMetaDataAssemblyEmit.h"
#include "chordata/IMetaDataAssemblyImport.h"

#include "chordata/IMetaDataEmit.h"
#include "chordata/IMetaDataImport.h"
#include "chordata/IMetaDataTables.h"

#include <vector>

namespace Chordata {

static const uint32_t TABLES(47);

DIAPEXIS_CLASS Scope :
	public IMetaDataInternal,
	//public IMetaDataAssemblyEmit,
	public IMetaDataAssemblyImport,
	//public IMetaDataEmit,
	public IMetaDataImport,
	public IMetaDataTables
{
    DIAPEXIS_FUZZY_UNKNOWN(IMetaDataInternal)

	DIAPEXIS_OBJECT_METADATA(Scope)

	DIAPEXIS_QUERY_BEGIN(Scope)
    DIAPEXIS_QUERY_FUZZY(Diapexis::Unknown, IMetaDataInternal)
	DIAPEXIS_QUERY_MAP(IMetaDataAssemblyImport)
	DIAPEXIS_QUERY_MAP(IMetaDataInternal)
	DIAPEXIS_QUERY_MAP(IMetaDataImport)
	DIAPEXIS_QUERY_MAP(IMetaDataTables)
	DIAPEXIS_QUERY_END()

  protected:
	//typedef std::pair<bool, uint8_t *> Row;
	typedef std::vector<uint8_t *> RowVector;

	struct Table {
		uint32_t size;
		bool sorted;
		RowVector rows;
	};

	Table tables[TABLES];
	uint32_t types[256];

	//std::vector<GUID *> guids;

	GUID *guids;
	uint32_t gSize;

	wchar_t *userStrings;
	uint8_t *sysStrings;
	uint8_t *blobs;

	uint32_t usSize, ssSize, bSize;

	bool compressed;
	Diapexis::Handle<Diapexis::Unknown> handler;

  public:
	Scope();
	virtual ~Scope();

    virtual void DIAPEXIS_CALL CloseEnum(CorEnum hEnum);

	/////////////////////////
	/// IMetaDataInternal ///
	/////////////////////////

	virtual void DIAPEXIS_CALL Open(const void *data, uint32_t size, uint32_t flags);
	virtual void DIAPEXIS_CALL UpdateSize();

	///////////////////////////////
	/// IMetaDataAssemblyImport ///
	///////////////////////////////

	virtual HRESULT DIAPEXIS_CALL GetAssemblyProps(Tokens::mdAssembly mda, const void **ppbPublicKey, uint32_t *pcbPublicKey, uint32_t *pulHashAlgId, wstr_t szName, uint32_t cchName, uint32_t *pchName, AssemblyMetadata *pMetaData, uint32_t *pdwAssemblyFlags);
	virtual HRESULT DIAPEXIS_CALL GetAssemblyRefProps(Tokens::mdAssemblyRef mdar, const void **ppbPublicKeyOrToken, uint32_t *pcbPublicKeyOrToken, wstr_t szName, uint32_t cchName, uint32_t *pchName, AssemblyMetadata *pMetaData, const void **ppbHashValue, uint32_t *pcbHashValue, uint32_t *pdwAssemblyRefFlags);
	virtual HRESULT DIAPEXIS_CALL GetFileProps(Tokens::mdFile mdf, wstr_t szName, uint32_t cchName, uint32_t *pchName, const void **ppbHashValue, uint32_t *pcbHashValue, uint32_t *pdwFileFlags);
	virtual HRESULT DIAPEXIS_CALL GetExportedTypeProps(Tokens::mdExportedType mdct, wstr_t szName, uint32_t cchName, uint32_t *pchName, Token *ptkImplementation, Tokens::mdTypeDef *ptkTypeDef, uint32_t *pdwExportedTypeFlags);
	virtual HRESULT DIAPEXIS_CALL GetManifestResourceProps(Tokens::mdManifestResource mdmr, wstr_t szName, uint32_t cchName, uint32_t *pchName, Token *ptkImplementation, uint32_t *pdwOffset, uint32_t *pdwResourceFlags);
	virtual HRESULT DIAPEXIS_CALL EnumAssemblyRefs(CorEnum *phEnum, Tokens::mdAssemblyRef rAssemblyRefs[], uint32_t cMax, uint32_t *pcTokens);
	virtual HRESULT DIAPEXIS_CALL EnumFiles(CorEnum *phEnum, Tokens::mdFile rFiles[], uint32_t cMax, uint32_t *pcTokens);
	virtual HRESULT DIAPEXIS_CALL EnumExportedTypes(CorEnum *phEnum, Tokens::mdExportedType   rExportedTypes[], uint32_t cMax, uint32_t *pcTokens);
	virtual HRESULT DIAPEXIS_CALL EnumManifestResources(CorEnum *phEnum, Tokens::mdManifestResource rManifestResources[], uint32_t cMax, uint32_t *pcTokens);
	virtual HRESULT DIAPEXIS_CALL GetAssemblyFromScope(Tokens::mdAssembly *ptkAssembly);
	virtual HRESULT DIAPEXIS_CALL FindExportedTypeByName(wcstr_t szName, Token mdtExportedType, Tokens::mdExportedType *ptkExportedType);
	virtual HRESULT DIAPEXIS_CALL FindManifestResourceByName(wcstr_t szName, Tokens::mdManifestResource *ptkManifestResource);
	virtual HRESULT DIAPEXIS_CALL FindAssembliesByName(wcstr_t szAppBase, wcstr_t szPrivateBin, wcstr_t szAssemblyName, Diapexis::Unknown *ppIUnk[], uint32_t cMax, uint32_t *pcAssemblies);

	/////////////////////
	/// IMetaDataEmit ///
	/////////////////////

    virtual HRESULT DIAPEXIS_CALL SetHandler(IUnknown *unknown);

	///////////////////////
	/// IMetaDataImport ///
	///////////////////////

    virtual HRESULT DIAPEXIS_CALL CountEnum(CorEnum hEnum, uint32_t *count);
    virtual HRESULT DIAPEXIS_CALL ResetEnum(CorEnum hEnum, uint32_t pos);

    virtual HRESULT DIAPEXIS_CALL EnumTypeDefs(CorEnum *phEnum, Tokens::mdTypeDef rTypeDefs[], uint32_t cMax, uint32_t *pcTypeDefs);
    virtual HRESULT DIAPEXIS_CALL EnumInterfaceImpls(CorEnum *phEnum, Tokens::mdTypeDef td, Tokens::mdInterfaceImpl rImpls[], uint32_t cMax, uint32_t *pcImpls);
    virtual HRESULT DIAPEXIS_CALL EnumTypeRefs(CorEnum *phEnum, Tokens::mdTypeRef rTypeRefs[], uint32_t cMax, uint32_t *pcTypeRefs);

    virtual HRESULT DIAPEXIS_CALL FindTypeDefByName(wcstr_t szTypeDef, Token tkEnclosingClass, Tokens::mdTypeDef *ptd);
    virtual HRESULT DIAPEXIS_CALL GetScopeProps(wstr_t szName, uint32_t cchName, uint32_t *pchName, GUID *pmvid);

    virtual HRESULT DIAPEXIS_CALL GetModuleFromScope(Tokens::mdModule *pmd);

    virtual HRESULT DIAPEXIS_CALL GetTypeDefProps(Tokens::mdTypeDef td, wstr_t szTypeDef, uint32_t cchTypeDef, uint32_t *pchTypeDef, uint32_t *pdwTypeDefFlags, Token *ptkExtends);
    virtual HRESULT DIAPEXIS_CALL GetInterfaceImplProps(Tokens::mdInterfaceImpl iiImpl, Tokens::mdTypeDef *pClass, Token *ptkIface);

    virtual HRESULT DIAPEXIS_CALL GetTypeRefProps(Tokens::mdTypeRef tr, Token *ptkResolutionScope, wstr_t szName, uint32_t cchName, uint32_t *pchName);
    virtual HRESULT DIAPEXIS_CALL ResolveTypeRef(Tokens::mdTypeRef tr, REFIID riid, Diapexis::Unknown **ppIScope, Tokens::mdTypeDef *ptd);

    virtual HRESULT DIAPEXIS_CALL EnumMembers(CorEnum *phEnum, Tokens::mdTypeDef cl, Token rMembers[], uint32_t cMax, uint32_t *pcTokens);
    virtual HRESULT DIAPEXIS_CALL EnumMembersWithName(CorEnum *phEnum, Tokens::mdTypeDef cl, wcstr_t szName, Token rMembers[], uint32_t cMax, uint32_t *pcTokens);

    virtual HRESULT DIAPEXIS_CALL EnumMethods(CorEnum *phEnum, Tokens::mdTypeDef cl, Tokens::mdMethodDef rMethods[], uint32_t cMax, uint32_t *pcTokens);
    virtual HRESULT DIAPEXIS_CALL EnumMethodsWithName(CorEnum *phEnum, Tokens::mdTypeDef cl, wcstr_t szName, Tokens::mdMethodDef rMethods[], uint32_t cMax, uint32_t *pcTokens);

	virtual HRESULT DIAPEXIS_CALL EnumFields(CorEnum *phEnum, Tokens::mdTypeDef cl, Tokens::mdFieldDef rFields[], uint32_t cMax, uint32_t *pcTokens);
    virtual HRESULT DIAPEXIS_CALL EnumFieldsWithName(CorEnum *phEnum, Tokens::mdTypeDef cl, wcstr_t szName, Tokens::mdFieldDef rFields[], uint32_t cMax, uint32_t *pcTokens);

    virtual HRESULT DIAPEXIS_CALL EnumParams(CorEnum *phEnum, Tokens::mdMethodDef mb, Tokens::mdParamDef rParams[], uint32_t cMax, uint32_t *pcTokens);
    virtual HRESULT DIAPEXIS_CALL EnumMemberRefs(CorEnum *phEnum, Token tkParent, Tokens::mdMemberRef rMemberRefs[], uint32_t cMax, uint32_t *pcTokens);
    virtual HRESULT DIAPEXIS_CALL EnumMethodImpls(CorEnum *phEnum, Tokens::mdTypeDef td, Token rMethodBody[], Token rMethodDecl[], uint32_t cMax, uint32_t *pcTokens);
    virtual HRESULT DIAPEXIS_CALL EnumPermissionSets(CorEnum *phEnum, Token tk, uint32_t dwActions, Tokens::mdPermission rPermission[], uint32_t cMax, uint32_t *pcTokens);

    virtual HRESULT DIAPEXIS_CALL FindMember(Tokens::mdTypeDef td, wcstr_t name, const Signature *pvSigBlob, uint32_t cbSigBlob, Token *pmb);
    virtual HRESULT DIAPEXIS_CALL FindMethod(Tokens::mdTypeDef td, wcstr_t name, const Signature *pvSigBlob, uint32_t cbSigBlob, Tokens::mdMethodDef *pmb);
    virtual HRESULT DIAPEXIS_CALL FindField(Tokens::mdTypeDef td, wcstr_t name, const Signature *pvSigBlob, uint32_t cbSigBlob, Tokens::mdFieldDef *pmb);
    virtual HRESULT DIAPEXIS_CALL FindMemberRef(Tokens::mdTypeRef td, wcstr_t szName, const Signature *pvSigBlob, uint32_t cbSigBlob, Tokens::mdMemberRef *pmr);

    virtual HRESULT DIAPEXIS_CALL GetMethodProps(Tokens::mdMethodDef mb, Tokens::mdTypeDef *pClass, wstr_t szMethod, uint32_t cchMethod, uint32_t *pchMethod, uint32_t *pdwAttr, const Signature **ppvSigBlob, uint32_t *pcbSigBlob, uint32_t *pulCodeRVA, uint32_t *pdwImplFlags);
    virtual HRESULT DIAPEXIS_CALL GetMemberRefProps(Tokens::mdMemberRef mr, Token *ptk, wstr_t szMember, uint32_t cchMember, uint32_t *pchMember, const Signature **ppvSigBlob, uint32_t *pbSig);

    virtual HRESULT DIAPEXIS_CALL EnumProperties(CorEnum *phEnum, Tokens::mdTypeDef td, Tokens::mdProperty rProperties[], uint32_t cMax, uint32_t *pcProperties);
    virtual HRESULT DIAPEXIS_CALL EnumEvents(CorEnum *phEnum, Tokens::mdTypeDef td, Tokens::mdEvent rEvents[], uint32_t cMax, uint32_t *pcEvents);

    virtual HRESULT DIAPEXIS_CALL GetEventProps(Tokens::mdEvent ev, Tokens::mdTypeDef *pClass, wcstr_t szEvent, uint32_t cchEvent, uint32_t *pchEvent, uint32_t *pdwEventFlags, Token *ptkEventType, Tokens::mdMethodDef *pmdAddOn, Tokens::mdMethodDef *pmdRemoveOn, Tokens::mdMethodDef *pmdFire, Tokens::mdMethodDef rmdOtherMethod[], uint32_t cMax, uint32_t *pcOtherMethod);

    virtual HRESULT DIAPEXIS_CALL EnumMethodSemantics(CorEnum *phEnum, Tokens::mdMethodDef mb, Token rEventProp[], uint32_t cMax, uint32_t *pcEventProp);
    virtual HRESULT DIAPEXIS_CALL GetMethodSemantics(Tokens::mdMethodDef mb, Token tkEventProp, uint32_t *pdwSemanticsFlags);

    virtual HRESULT DIAPEXIS_CALL GetClassLayout(Tokens::mdTypeDef td, uint32_t *pdwPackSize, FieldOffset rFieldOffset[], uint32_t cMax, uint32_t *pcFieldOffset, uint32_t *pulClassSize);
    virtual HRESULT DIAPEXIS_CALL GetFieldMarshal(Token tk, const Signature **ppvNativeType, uint32_t *pcbNativeType);

    virtual HRESULT DIAPEXIS_CALL GetRVA(Token tk, uint32_t *pulCodeRVA, uint32_t *pdwImplFlags);

    virtual HRESULT DIAPEXIS_CALL GetPermissionSetProps(Tokens::mdPermission pm, uint32_t *pdwAction, void const **ppvPermission, uint32_t *pcbPermission);
    virtual HRESULT DIAPEXIS_CALL GetSigFromToken(Tokens::mdSignature mdSig, const Signature **ppvSig, uint32_t *pcbSig);

    virtual HRESULT DIAPEXIS_CALL GetModuleRefProps(Tokens::mdModuleRef mur, wchar_t *szName, uint32_t cchName, uint32_t *pchName);
    virtual HRESULT DIAPEXIS_CALL EnumModuleRefs(CorEnum *phEnum, Tokens::mdModuleRef rModuleRefs[], uint32_t cmax, uint32_t *pcModuleRefs);

    virtual HRESULT DIAPEXIS_CALL GetTypeSpecFromToken(Tokens::mdTypeSpec typespec, const Signature **ppvSig, uint32_t *pcbSig);
    virtual HRESULT DIAPEXIS_CALL GetNameFromToken(Token tk, cstr_t *pszUtf8NamePtr);

    virtual HRESULT DIAPEXIS_CALL EnumUnresolvedMethods(CorEnum *phEnum, Token rMethods[], uint32_t cMax, uint32_t *pcTokens);

	virtual HRESULT DIAPEXIS_CALL GetUserString(Tokens::mdString stk, wstr_t szString, uint32_t cchString, uint32_t *pchString);
    virtual HRESULT DIAPEXIS_CALL GetPinvokeMap(Token tk, uint32_t *pdwMappingFlags, wstr_t szImportName, uint32_t cchImportName, uint32_t *pchImportName, Tokens::mdModuleRef *pmrImportDLL);

    virtual HRESULT DIAPEXIS_CALL EnumSignatures(CorEnum *phEnum, Tokens::mdSignature rSignatures[], uint32_t cmax, uint32_t *pcSignatures);
    virtual HRESULT DIAPEXIS_CALL EnumTypeSpecs(CorEnum *phEnum, Tokens::mdTypeSpec rTypeSpecs[], uint32_t cmax, uint32_t *pcTypeSpecs);
    virtual HRESULT DIAPEXIS_CALL EnumUserStrings(CorEnum *phEnum, Tokens::mdString rStrings[], uint32_t cmax, uint32_t *pcStrings);

    virtual HRESULT DIAPEXIS_CALL GetParamForMethodIndex(Tokens::mdMethodDef md, uint32_t ulParamSeq, Tokens::mdParamDef *ppd);

	virtual HRESULT DIAPEXIS_CALL EnumCustomAttributes(CorEnum *phEnum, Token tk, Token tkType, Tokens::mdCustomAttribute rCustomAttributes[], uint32_t cMax, uint32_t *pcCustomAttributes);
	virtual HRESULT DIAPEXIS_CALL GetCustomAttributeProps(Tokens::mdCustomAttribute cv, Token *ptkObj, Token *ptkType, void const **ppBlob, uint32_t *pcbSize);

    virtual HRESULT DIAPEXIS_CALL FindTypeRef(Token tkResolutionScope, wcstr_t szName, Tokens::mdTypeRef *ptr);

    virtual HRESULT DIAPEXIS_CALL GetMemberProps(Token mb, Tokens::mdTypeDef *pClass, wstr_t szMember, uint32_t cchMember, uint32_t *pchMember, uint32_t *pdwAttr, const Signature **ppvSigBlob, uint32_t *pcbSigBlob, uint32_t *pulCodeRVA, uint32_t *pdwImplFlags, uint32_t *pdwCPlusTypeFlag, void const **ppValue, uint32_t *pcchValue);
    virtual HRESULT DIAPEXIS_CALL GetFieldProps(Tokens::mdFieldDef mb, Tokens::mdTypeDef *pClass, wstr_t szField, uint32_t cchField, uint32_t *pchField, uint32_t *pdwAttr, const Signature **ppvSigBlob, uint32_t *pcbSigBlob, uint32_t *pdwCPlusTypeFlag, void const **ppValue, uint32_t *pcchValue);
    virtual HRESULT DIAPEXIS_CALL GetPropertyProps(Tokens::mdProperty prop, Tokens::mdTypeDef *pClass, wstr_t szProperty, uint32_t cchProperty, uint32_t *pchProperty, uint32_t *pdwPropFlags, const Signature **ppvSig, uint32_t *pbSig, uint32_t *pdwCPlusTypeFlag, void const **ppDefaultValue, uint32_t *pcbDefaultValue, Tokens::mdMethodDef *pmdSetter, Tokens::mdMethodDef *pmdGetter, Tokens::mdMethodDef rmdOtherMethod[], uint32_t cMax, uint32_t *pcOtherMethod);
    virtual HRESULT DIAPEXIS_CALL GetParamProps(Tokens::mdParamDef tk, Tokens::mdMethodDef *pmd, uint32_t *pulSequence, wstr_t szName, uint32_t cchName, uint32_t *pchName, uint32_t *pdwAttr, uint32_t *pdwCPlusTypeFlag, void const **ppValue, uint32_t *pcchValue);

    virtual HRESULT DIAPEXIS_CALL GetCustomAttributeByName(Token tkObj, wcstr_t szName, const void **ppData, uint32_t *pcbData);

    virtual BOOL DIAPEXIS_CALL IsValidToken(Token tk);

    virtual HRESULT DIAPEXIS_CALL GetNestedClassProps(Tokens::mdTypeDef tdNestedClass, Tokens::mdTypeDef *ptdEnclosingClass);
    virtual HRESULT DIAPEXIS_CALL GetNativeCallConvFromSig(void const *pvSig, uint32_t cbSig, uint32_t *pCallConv);

	virtual HRESULT DIAPEXIS_CALL IsGlobal(Token pd, int32_t *pbGlobal);

	///////////////////////
	/// IMetaDataTables ///
	///////////////////////

	virtual HRESULT DIAPEXIS_CALL GetStringHeapSize(uint32_t *size) const;
	virtual HRESULT DIAPEXIS_CALL GetBlobHeapSize(uint32_t *size) const;
	virtual HRESULT DIAPEXIS_CALL GetGuidHeapSize(uint32_t *size) const;
	virtual HRESULT DIAPEXIS_CALL GetUserStringHeapSize(uint32_t *size) const;

	virtual HRESULT DIAPEXIS_CALL GetNumTables(uint32_t *tables) const;
	virtual HRESULT DIAPEXIS_CALL GetTableIndex(uint32_t token, uint32_t *index);
	virtual HRESULT DIAPEXIS_CALL GetTableInfo(uint32_t table, uint32_t *size, uint32_t *rows, uint32_t *cols, uint32_t *key, cstr_t *name);

	virtual HRESULT DIAPEXIS_CALL GetColumnInfo(uint32_t table, uint32_t col, uint32_t *offset, uint32_t *size, uint32_t *type, cstr_t *name);
	virtual HRESULT DIAPEXIS_CALL GetCodedTokenInfo(uint32_t code, uint32_t *number, uint32_t **tokens, cstr_t *name);

	virtual HRESULT DIAPEXIS_CALL GetRow(uint32_t table, uint32_t row, void **data);
	virtual HRESULT DIAPEXIS_CALL GetColumn(uint32_t table, uint32_t col, uint32_t row, uint32_t *value);

	virtual HRESULT DIAPEXIS_CALL GetString(uint32_t index, cstr_t *data) const;
	virtual HRESULT DIAPEXIS_CALL GetBlob(uint32_t index, uint32_t *size, const void **data) const;
	virtual HRESULT DIAPEXIS_CALL GetGuid(uint32_t index, const GUID **guid) const;
	virtual HRESULT DIAPEXIS_CALL GetUserString(uint32_t index, uint32_t *size, const void **data) const;

    virtual HRESULT DIAPEXIS_CALL GetNextString(uint32_t index, uint32_t *next) const;
	virtual HRESULT DIAPEXIS_CALL GetNextBlob(uint32_t index, uint32_t *next) const;
	virtual HRESULT DIAPEXIS_CALL GetNextGuid(uint32_t index, uint32_t *next) const;
	virtual HRESULT DIAPEXIS_CALL GetNextUserString(uint32_t index, uint32_t *next) const;
};

}

#endif CHORDATA_SCOPE_H