#include <windows.h>
#include <stdio.h>
#include <wchar.h>

#include "kpi.h"

#include "kbvgm_convert.h"
#include "kbvgm_gzfile.h"
#include "mamiya/s98device.h"
#include "mamiya/s98types.h"

/* S98 file header */
#define S98_MAGIC_V0    (0x53393830)    /* 'S980' */
#define S98_MAGIC_V1    (0x53393831)    /* 'S981' */
#define S98_MAGIC_V2    (0x53393832)    /* 'S982' */
#define S98_MAGIC_V3    (0x53393833)    /* 'S983' */
#define S98_MAGIC_VZ    (0x5339385A)    /* 'S98Z' */
#define S98_OFS_MAGIC       (0x00)
#define S98_OFS_TIMER_INFO1 (0x04)
#define S98_OFS_TIMER_INFO2 (0x08)
#define S98_OFS_COMPRESSING (0x0C)
#define S98_OFS_OFSTITLE    (0x10)
#define S98_OFS_OFSDATA     (0x14)
#define S98_OFS_OFSLOOP     (0x18)
#define S98_OFS_OFSCOMP     (0x1C)
#define S98_OFS_DEVICECOUNT (0x1C)
#define S98_OFS_DEVICEINFO  (0x20)

#define VGM_MAGIC       (0x56676D20)    /* 'Vgm ' */


static void SetDwordLE(Uint8* p, Uint32 v)
{
    p[0] = (v >> (8 * 0)) & 0xFF;
    p[1] = (v >> (8 * 1)) & 0xFF;
    p[2] = (v >> (8 * 2)) & 0xFF;
    p[3] = (v >> (8 * 3)) & 0xFF;
}
static void SetDwordBE(Uint8* p, Uint32 v)
{
    p[0] = (v >> (8 * 3)) & 0xFF;
    p[1] = (v >> (8 * 2)) & 0xFF;
    p[2] = (v >> (8 * 1)) & 0xFF;
    p[3] = (v >> (8 * 0)) & 0xFF;
}
static Uint32 GetWordLE(Uint8* p)
{
    int ret;
    ret = ((Uint32)(Uint8)p[0]) << 0x00;
    ret |= ((Uint32)(Uint8)p[1]) << 0x08;
    return ret;
}
static Uint32 GetDwordLE(Uint8* p)
{
    int ret;
    ret = ((Uint32)(Uint8)p[0]) << 0x00;
    ret |= ((Uint32)(Uint8)p[1]) << 0x08;
    ret |= ((Uint32)(Uint8)p[2]) << 0x10;
    ret |= ((Uint32)(Uint8)p[3]) << 0x18;
    return ret;
}
static Uint32 GetDwordBE(Uint8* p)
{
    Uint32 ret;
    ret = ((Uint32)(Uint8)p[0]) << 0x18;
    ret |= ((Uint32)(Uint8)p[1]) << 0x10;
    ret |= ((Uint32)(Uint8)p[2]) << 0x08;
    ret |= ((Uint32)(Uint8)p[3]) << 0x00;
    return ret;
}

#include "mamiya/x1f.h"
#include "mamiya/mym.h"

///////////////////////////////////////////////////////////////////////////
BYTE* ConvertToS98(IKpiFile* pFile, DWORD* pdwSizeConverted) //拡張子が mym/cym/x1f なら S98 に変換
{
    *pdwSizeConverted = 0;

    wchar_t szFileName[MAX_PATH];
    pFile->GetFileName(szFileName, sizeof(szFileName));
    const wchar_t* cszExt = wcsrchr(szFileName, L'.');
    if (!cszExt)return NULL;

    const DWORD  dwMaxSize = 256 * 1024 * 1024;//最大256MBまで
    
    if (_wcsicmp(cszExt, L".mym") == 0 || 
        _wcsicmp(cszExt, L".cym") == 0 ||
        _wcsicmp(cszExt, L".x1f") == 0) {
        UINT64 qwSize = pFile->GetSize();
        if(qwSize > dwMaxSize)return NULL;//サイズが大き過ぎる
        pFile->Seek(0, FILE_BEGIN);
        BYTE *pBuffer = (BYTE*)malloc(qwSize);
        DWORD dwSize = pFile->Read(pBuffer, qwSize);
        pFile->Seek(0, FILE_BEGIN);
        BYTE *ret;
        if(_wcsicmp(cszExt, L".x1f") == 0){// x1f
            ret = x1f2s98(pBuffer, dwSize, pdwSizeConverted);
        }
        else{// mym/cym
            ret = mym2s98(pBuffer, dwSize, pdwSizeConverted);
        }
        free(pBuffer);
        return ret;
    }
    return NULL;
}
///////////////////////////////////////////////////////////////////////////
IKpiFile* ExtractGZ(IKpiFile* pFile)//pFile が GZ 圧縮されてるなら展開後の IKpiFile を返す
{
    KbGzFile *pGzFile = new KbGzFile;
    if(pGzFile->Open(pFile)){
        return pGzFile;
    }
    pGzFile->Release();
    return NULL;
}
///////////////////////////////////////////////////////////////////////////
