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

#include "kbsnesapu_id666.h"

typedef void (*pfnGetStr)(DWORD dwData, wchar_t *pszDest, DWORD dwSize);//文字列取得(サイズは文字数単位)
static void GetDateStr(DWORD dwData, wchar_t *pszDate, DWORD dwSize);
static void GetEmuStr(DWORD dwData, wchar_t *pszEmu, DWORD dwSize);
static void GetChMuteStr(DWORD dwData, wchar_t *pszCh, DWORD dwSize);
static void GetTrackNoStr(DWORD dwData, wchar_t *pszTrackNo, DWORD dwSize);
static void GetDwordStr(DWORD dwData, wchar_t *pszData, DWORD dwSize);
static void TickToTimeStr(DWORD dwTick, wchar_t *pszTime, DWORD dwSize);
static void MsToTimeStr(DWORD dwMs, wchar_t *pszTime, DWORD dwSize);
static int  StrToIntDef(const char *cszStr, int nDefault);
///////////////////////////////////////////////////////////////////////////
static int __fastcall IsText(const char *str, int length)
{
    int c = 0;

    while (c<length && ((str[c]>=0x30 && str[c]<=0x39) || str[c]=='/')) c++;
    if (c==length || str[c]==0){
        return c;
    }
    else{
        return -1;
    }
}
///////////////////////////////////////////////////////////////////////////
static int __fastcall CheckBinary(const ID666_TEXT *pId666)
{//ID666_TEXT(or ID666_BIN) がテキスト/バイナリのいずれのモードかを調べる
 //バイナリなら 1 、テキストなら 0、不明の場合は -1 を返す
 //判別方法は SNESAmp の id666.cpp となるべく同じくする
    int bin = 0;
    int preferbin = -1;//判別不可(テキストと見なす)
    int i, j, k;
    i = IsText(pId666->length, sizeof(pId666->length));
    j = IsText(pId666->fade, sizeof(pId666->fade));
    k = IsText(pId666->date, sizeof(pId666->date));
    if (!(i | j | k))                           //If no times or date, use default
    {
        if (pId666->channel == 1 && pId666->emulator == 0){ //Was the file dumped with ZSNES?
            bin = true;
        }
        else{
            bin = preferbin;
        }
    }
    else if(i != -1 && j != -1){    //If no time, or time is text
        if (k > 0){
            bin = false;                        //If date is text, then tag is text
        }
        else if (k == 0){                               //No date
            bin = -1;                           //Times could still be binary (ex. 56 bin = '8' txt)
        }
        else if (k == -1){                      //Date contains invalid characters
            if (!((u32*)&pId666->date)[1]){     //If bytes 4-7 are 0's, it's probably a ZSNES dump
                bin = true;
            }
            else{
                bin = false;                    //Otherwise date may contain alpha characters
            }
        }
    }
    else{
        bin = true;                             //If time is not text, tag is binary
    }
    return bin;
}
///////////////////////////////////////////////////////////////////////////
static UINT64 TickTo100ns(DWORD dwTick)
{
    return (UINT64)dwTick * 10000 / 64;
}
///////////////////////////////////////////////////////////////////////////
static INT64 TickTo100ns(INT32 nTick)
{
    return (INT64)nTick * 10000 / 64;
}///////////////////////////////////////////////////////////////////////////
static DWORD TickToMs(DWORD dwTick)
{
    return (DWORD)((UINT64)dwTick / 64);
}
///////////////////////////////////////////////////////////////////////////
static void TickToTimeStr(DWORD dwTick, wchar_t *pszTime, DWORD dwSize)
{
    DWORD dwMs = TickToMs(abs((int)dwTick));
    DWORD dwMin = dwMs / 1000 / 60;
    DWORD dwSec = (dwMs % 60000)/1000;
    dwMs %= 1000;
    wchar_t szSign[2];
    if((int)dwMs < 0){
        szSign[0] = L'-';
        szSign[1] = 0;
    }
    else{
        szSign[0] = 0;
    }
    _snwprintf_s(pszTime, dwSize, _TRUNCATE,
                 L"%d(%s%d:%02d.%03d)", dwTick, szSign, dwMin, dwSec, dwMs);
}
///////////////////////////////////////////////////////////////////////////
static void MsToTimeStr(DWORD dwMs, wchar_t *pszTime, DWORD dwSize)
{
    DWORD dwMin = dwMs / 1000 / 60;
    DWORD dwSec = (dwMs % 60000)/1000;
    DWORD dwMs0 = dwMs % 1000;
    _snwprintf_s(pszTime, dwSize, _TRUNCATE,
                 L"%d:%02d.%03d", dwMin, dwSec, dwMs0);
}
///////////////////////////////////////////////////////////////////////////
static void GetDateStr(DWORD dwData, wchar_t *pszDate, DWORD dwSize)
{
    int y = dwData>>16;
    int m = (dwData&0xFF00)>>8;
    int d = (dwData&0xFF);
    if(y && m && d){
        _snwprintf_s(pszDate, dwSize, _TRUNCATE, L"%d/%d/%d", y, m, d);
    }
    else if(y && m && !d){
        _snwprintf_s(pszDate, dwSize, _TRUNCATE, L"%d/%d", y, m);
    }
    else if(y && !m && !d){
        _snwprintf_s(pszDate, dwSize, _TRUNCATE, L"%d", y);
    }
    else{
        pszDate[0] = 0;
    }
}
///////////////////////////////////////////////////////////////////////////
static void GetEmuStr(DWORD dwData, wchar_t *pszEmu, DWORD dwSize)
{
    static const wchar_t *cszEmulators[] = {
        L"Unknown",
        L"ZSNES",
        L"SNES9X",
        L"ZST2SPC",
        L"ETC",
        L"SNEShout",
        L"ZSNES/W",
        L"SNES9Xpp",
        L"SNESGT",
        NULL
    };
    if(dwData >= sizeof(cszEmulators) / sizeof(cszEmulators[0])){
        dwData = 0;
    }
    wcsncpy_s(pszEmu, dwSize, cszEmulators[dwData], _TRUNCATE);
}
///////////////////////////////////////////////////////////////////////////
static void GetChMuteStr(DWORD dwData, wchar_t *pszCh, DWORD dwSize)
{
    if(dwSize < 9){//最低でも9文字分必要
        pszCh[0] = 0;
        return;
    }
    DWORD i;
    for(i = 0; i < 8; i++){
        if((dwData >> i) & 0x01){
            pszCh[i] = L'1';
        }
        else{
            pszCh[i] = L'0';
        }
    }
    pszCh[i] = 0;
}
///////////////////////////////////////////////////////////////////////////
static void GetTrackNoStr(DWORD dwData, wchar_t *pszTrackNo, DWORD dwSize)
{
    DWORD dwTrackNumber = (dwData >> 8) & 0xFF;
    wchar_t track_op = dwData & 0xFF;
    if(!iswascii(track_op)){
        track_op = 0;
    }
    _snwprintf_s(pszTrackNo, dwSize, _TRUNCATE,
                 L"%d%c", dwTrackNumber, track_op);
}
///////////////////////////////////////////////////////////////////////////
static void GetDwordStr(DWORD dwData, wchar_t *pszData, DWORD dwSize)
{
    _snwprintf_s(pszData, dwSize, _TRUNCATE, L"%d", dwData);
}
///////////////////////////////////////////////////////////////////////////
static int StrToIntDef(const char *cszStr, int nDefault)
{//ASCII 文字列を int に変換
 //'0'〜'9' 以外の文字が見つかったら nDefault を返す
    if(!*cszStr){//終端文字で始まる場合は nDefault を返す
        return nDefault;
    }
    //空白文字を含むことがあるかどうかは不明だが、ASCII 文字列なので
    //あり得るとして処理する
    int nRet = 0;
    //先頭の空白は読み飛ばす
    while(*cszStr == ' '){
        cszStr++;
    }
    while(*cszStr){
        if('0' <= *cszStr && *cszStr <= '9'){
            nRet *= 10;
            nRet += *cszStr - '0';
        }
        else if(*cszStr == ' '){//空白を見つけたら終了
            break;
        }
        else{
            return nDefault;
        }
        cszStr++;
    }
    return nRet;
}
///////////////////////////////////////////////////////////////////////////
//KbId666
///////////////////////////////////////////////////////////////////////////
KbId666::KbId666(void)
{
    m_bIsBinary= FALSE;
    m_pXid6 = NULL;
    m_dwXid6Size = 0;
    ZeroMemory(&m_id666, sizeof(m_id666));
    ZeroMemory(&m_id666_length, sizeof(m_id666_length));
    ZeroMemory(&m_xid6_length, sizeof(m_xid6_length));
    m_id666_length.dwFade = -1;
    m_xid6_length.dwFade = -1;
    m_xid6_length.dwLoopCount = -1;
}
///////////////////////////////////////////////////////////////////////////
KbId666::~KbId666(void)
{
    if(m_pXid6){
        free(m_pXid6);
    }
}
///////////////////////////////////////////////////////////////////////////
BOOL __fastcall KbId666::Open(IKpiFile *pFile)
{
#pragma pack(push, 1) //構造体のアラインメント
    struct SPC_HEAD
    {
        BYTE head[33];
        BYTE dummy1;
        BYTE dummy2;
        BYTE contain;
        BYTE version_minor;
    };
#pragma pack(pop) //構造体のアラインメント
    SPC_HEAD spcHead;
    pFile->Seek(0, FILE_BEGIN);
    if(pFile->Read(&spcHead, sizeof(spcHead)) != sizeof(spcHead)){
        return FALSE;
    }
    if (memcmp(spcHead.head, "SNES-SPC700", 11) != 0) {
        return FALSE;
    }
    if(spcHead.dummy1 != 26 ||
       spcHead.dummy2 != 26){
       return TRUE;
    }
    //if(spcHead.contain != 26){//27 なのにタグを含むデータが存在する
    //    return TRUE;
    //}
    pFile->Seek(0x2e, FILE_BEGIN);
    if(pFile->Read(&m_id666, sizeof(m_id666)) != sizeof(m_id666)){
        return FALSE;
    }
    //id666
    BOOL bIsBinary = CheckBinary(&m_id666.text) == 1;
    ID666_TEXT *pid666_text = &m_id666.text;
    ID666_BIN  *pid666_bin =  &m_id666.bin;
    m_bIsBinary = bIsBinary;
    if(bIsBinary){
        m_id666_length.dwLength = *(WORD*)pid666_bin->length * 1000;
        m_id666_length.dwFade = pid666_bin->dwFade;
    }
    else{
        char szLength[6];
        memcpy(szLength, pid666_text->length, 3);
        szLength[3] = 0;
        m_id666_length.dwLength  = StrToIntDef(szLength, 0) * 1000;
        memcpy(szLength, pid666_text->fade, 5);
        szLength[5] = 0;
        m_id666_length.dwFade = StrToIntDef(szLength, -1);
    }
    //xid6
    pFile->Seek(sizeof(SPCDATA), FILE_BEGIN);
    struct{
        DWORD dwType;
        DWORD dwSize;
    }xid6_chunk;
    if(pFile->Read(&xid6_chunk, 8) != 8){
        return true;
    }
    if(xid6_chunk.dwType != *(DWORD*)"xid6"){
        return true;
    }
    if(xid6_chunk.dwSize > pFile->GetSize() - pFile->Seek(0, FILE_CURRENT)){
    //サイズがおかしい
        return true;
    }
    m_pXid6 = (BYTE*)malloc(xid6_chunk.dwSize);
    m_dwXid6Size = pFile->Read(m_pXid6, xid6_chunk.dwSize);
    ReadXid6(NULL, FALSE);
    return true;
}
///////////////////////////////////////////////////////////////////////////
void __fastcall KbId666::ReadId666(IKpiTagInfo *pTagInfo, DWORD dwTagGetFlags)
{
    ID666_TEXT *pid666_text = GetId666Text();
    ID666_BIN  *pid666_bin =  GetId666Bin();
    BYTE  channel;
    DWORD emulator;
    if(!m_bIsBinary){
        if(pid666_text->title[0] && (dwTagGetFlags & KPI_TAGGET_FLAG_TITLE)){
            pTagInfo->wSetValueA(L"title", -1, (const char*)pid666_text->title, sizeof(pid666_text->title));
        }
        if(pid666_text->artist[0] && (dwTagGetFlags & KPI_TAGGET_FLAG_ARTIST)){
            pTagInfo->wSetValueA(L"artist", -1, (const char*)pid666_text->artist, sizeof(pid666_text->artist));
        }
        if(pid666_text->game[0] && (dwTagGetFlags & KPI_TAGGET_FLAG_ALBUM)){
            pTagInfo->wSetValueA(L"game", -1, (const char*)pid666_text->game, sizeof(pid666_text->game));
        }
        if(pid666_text->dumper[0] && (dwTagGetFlags & KPI_TAGGET_FLAG_GENERAL)){
            pTagInfo->wSetValueA(L"dumper", -1, (const char*)pid666_text->dumper, sizeof(pid666_text->dumper));
        }
        if(pid666_text->comment[0] && (dwTagGetFlags & KPI_TAGGET_FLAG_COMMENT)){
            pTagInfo->wSetValueA(L"comment", -1, (const char*)pid666_text->comment, sizeof(pid666_text->comment));
        }
        if(pid666_text->date[0] && (dwTagGetFlags & KPI_TAGGET_FLAG_DATE)){
            pTagInfo->wSetValueA(L"date", -1, (const char*)pid666_text->date, sizeof(pid666_text->date));
        }
        channel = pid666_text->channel;
        emulator = pid666_text->emulator - '0';//ascii で入っているので '0' だけ差し引く
    }
    else if(pid666_bin){
        if(pid666_bin->title[0] && (dwTagGetFlags & KPI_TAGGET_FLAG_TITLE)){
            pTagInfo->wSetValueA(L"title", -1, (const char*)pid666_bin->title, sizeof(pid666_bin->title));
        }
        if(pid666_bin->artist[0] && (dwTagGetFlags & KPI_TAGGET_FLAG_ARTIST)){
            pTagInfo->wSetValueA(L"artist", -1, (const char*)pid666_bin->artist, sizeof(pid666_bin->artist));
        }
        if(pid666_bin->game[0] && (dwTagGetFlags & KPI_TAGGET_FLAG_ALBUM)){
            pTagInfo->wSetValueA(L"game", -1, (const char*)pid666_bin->game, sizeof(pid666_bin->game));
        }
        if(pid666_bin->dumper[0] && (dwTagGetFlags & KPI_TAGGET_FLAG_GENERAL)){
            pTagInfo->wSetValueA(L"dumper", -1, (const char*)pid666_bin->dumper, sizeof(pid666_bin->dumper));
        }
        if(pid666_bin->comment[0] && (dwTagGetFlags & KPI_TAGGET_FLAG_COMMENT)){
            pTagInfo->wSetValueA(L"comment", -1, (const char*)pid666_bin->comment, sizeof(pid666_bin->comment));
        }
        if(pid666_bin->dwDate && (dwTagGetFlags & KPI_TAGGET_FLAG_DATE)){
            wchar_t szDate[32];
            GetDateStr(pid666_bin->dwDate, szDate, _countof(szDate));
            pTagInfo->wSetValueW(L"date", -1, szDate, -1);
        }
        channel = pid666_bin->channel;
        emulator = pid666_bin->emulator;
    }
    if(!(dwTagGetFlags & KPI_TAGGET_FLAG_GENERAL)){
        return;
    }
    //pTagInfo->wSetValueW(L"default channel", -1, channel ? L"disable" : L"enable", -1);
    //↑SNESAmp でも使われていないようなので通知するのをやめた
    wchar_t szData[128];
    GetEmuStr(emulator, szData, _countof(szData));
    pTagInfo->wSetValueW(L"emulator", -1, szData, -1);

    if(m_id666_length.dwLength != 0){
        //曲の長さ(id666 に含まれる場合のみ通知)
        MsToTimeStr(m_id666_length.dwLength, szData, _countof(szData));
        if(m_xid6_length.dwIntro != 0){
        //xid6 に曲の長さを含む場合は (igonored) 追加
            wcsncat_s(szData, L"(ignored)", _TRUNCATE);
        }
        pTagInfo->wSetValueW(L"length(id666)", -1, szData, -1);
    }
    if(m_id666_length.dwFade != (DWORD)-1){
        //フェード時間(id666 に含まれる場合のみ通知)
        MsToTimeStr(m_id666_length.dwFade, szData, _countof(szData));
        if(m_xid6_length.dwFade != (DWORD)-1){
        //xid6 にフェード時間を含む場合は (igonored) 追加
            wcsncat_s(szData, L"(ignored)", _TRUNCATE);
        }
        pTagInfo->wSetValueW(L"fade(id666)", -1, szData, -1);
    }
}
///////////////////////////////////////////////////////////////////////////
void  __fastcall KbId666::ReadXid6(IKpiTagInfo *pTagInfo, DWORD dwTagGetFlags)
{
    if(!m_pXid6){
        return;
    }
    enum{
        xid6_type_len = 0,
        xid6_type_str = 1,
        xid6_type_int = 4,
    };
    static const struct S{
        BYTE id;
        BYTE type;
        BYTE size;
        const wchar_t *cszName;//IKpiTagInfo に通知する name
        pfnGetStr fnGetStr;//type == xid6_type_str の場合は NULL
        DWORD dwFlag;//0 の場合は省略しない
    }s[] = {
        //type_len のときの size は SPCFormat.txt と異なる場合がある
        //4byte で align されているので支障なし?
        {0x01, xid6_type_str, 0, L"title", NULL, KPI_TAGGET_FLAG_TITLE},
        {0x02, xid6_type_str, 0, L"game",  NULL, KPI_TAGGET_FLAG_ALBUM},
        {0x03, xid6_type_str, 0, L"artist", NULL, KPI_TAGGET_FLAG_ARTIST},
        {0x04, xid6_type_str, 0, L"dumper", NULL, KPI_TAGGET_FLAG_GENERAL},
        {0x05, xid6_type_int, 4, L"date", GetDateStr, KPI_TAGGET_FLAG_DATE},
        {0x06, xid6_type_len, 1, L"emulator", GetEmuStr, KPI_TAGGET_FLAG_GENERAL},
        {0x07, xid6_type_str, 0, L"comment", NULL, KPI_TAGGET_FLAG_COMMENT},
        {0x10, xid6_type_str, 0, L"soundtrack", NULL, KPI_TAGGET_FLAG_GENERAL},
        {0x11, xid6_type_len, 1, L"discnumber", GetDwordStr, KPI_TAGGET_FLAG_TRACK},
        {0x12, xid6_type_len, 2, L"tracknumber", GetTrackNoStr, KPI_TAGGET_FLAG_TRACK},
        {0x13, xid6_type_str, 0, L"publisher", NULL, KPI_TAGGET_FLAG_GENERAL},
        {0x14, xid6_type_len, 2, L"copyright year", GetDwordStr, KPI_TAGGET_FLAG_GENERAL},

        {0x30, xid6_type_int, 4, L"intro", TickToTimeStr, 0}, //dwTagGetFlags によらず省略しない
        {0x31, xid6_type_int, 4, L"loop", TickToTimeStr, 0},  //dwTagGetFlags によらず省略しない
        {0x32, xid6_type_int, 4, L"end", TickToTimeStr, 0},   //dwTagGetFlags によらず省略しない 
        {0x33, xid6_type_int, 4, L"fade", TickToTimeStr, 0},  //dwTagGetFlags によらず省略しない 
        {0x34, xid6_type_len, 1, L"muted channels", GetChMuteStr, KPI_TAGGET_FLAG_GENERAL}, //ID6666 だと size=4 で書き込まれる
        {0x35, xid6_type_len, 1, L"loopcount", GetDwordStr, 0}, //dwTagGetFlags によらず省略しない
        {0x36, xid6_type_int, 4, L"amplification", GetDwordStr, KPI_TAGGET_FLAG_GENERAL},

        {0, 0, NULL, NULL, NULL},
    };
    XID6_SUBCHUNK *pSubChunk = (XID6_SUBCHUNK*)m_pXid6;
    DWORD dwPos = 0;
    while(1){
        dwPos += sizeof(XID6_SUBCHUNK);
        if(dwPos > m_dwXid6Size){
            break;
        }
        if(pSubChunk->type != 0){
            if((UINT64)dwPos + pSubChunk->length > m_dwXid6Size){
                break;
            }
        }
        int i;
        for(i = 0; s[i].cszName; i++){
            if(pSubChunk->id == s[i].id){
                break;
            }
        }
        BYTE* pData = m_pXid6 + dwPos;
        bool bSkip = true;//不要な情報は省略
        if(!s[i].cszName){
            if(dwTagGetFlags & KPI_TAGGET_FLAG_GENERAL){
                bSkip = false;
            }
        }
        else if(s[i].dwFlag & dwTagGetFlags){
            bSkip = false;
        }
        else if(s[i].dwFlag == 0){
            bSkip = false;
        }
        if(bSkip){
            switch(pSubChunk->id){
            case 0x01:case 0x03:case 0x30:case 0x31:case 0x32:case 0x33:case 0x35:
            //title, aritist, intro, loop, end, fade, loopcount は省略しない
                bSkip = false;
                break;
            }
        }
        if(!bSkip && s[i].cszName){
            if(pSubChunk->type == xid6_type_str){
                if(pTagInfo){
                    pTagInfo->wSetValueA(s[i].cszName, -1, (char*)pData, pSubChunk->length);
                }
            }
            else if(pSubChunk->type == xid6_type_int){
                DWORD dwData;
                wchar_t szData[128];
                if(pSubChunk->length == s[i].size){
                    dwData = *(DWORD*)pData;
                }
                else{//サイズがおかしい場合は念のため 0 にする
                    dwData = 0;
                }
                s[i].fnGetStr(dwData, szData, _countof(szData));
                switch(pSubChunk->id){//intro, loop, end, fade, loopcount
                    case 0x30: m_xid6_length.dwIntro = dwData;break;
                    case 0x31: m_xid6_length.dwLoop = dwData;break;
                    case 0x32: m_xid6_length.nEnd = dwData;break;
                    case 0x33: m_xid6_length.dwFade = dwData;break;
                    case 0x35: m_xid6_length.dwLoopCount = dwData;break;//xid6_type_len の筈だが念のため
                    case 0x36: m_xid6_length.dwAmp = dwData;break;
                }
                if(pTagInfo && szData[0]){
                    pTagInfo->wSetValueW(s[i].cszName, -1, szData, -1);
                }
            }
            else if(pSubChunk->type == xid6_type_len){
                DWORD dwData;
                wchar_t szData[128];
                if(s[i].size == 1){
                    dwData = *(BYTE*)(&pSubChunk->length);
                }
                else if(s[i].size == 2){
                    dwData = *(WORD*)(&pSubChunk->length);
                }
                else if(s[i].size == 4){
                    dwData = pSubChunk->length;
                }
                else{
                    dwData = 0;
                }
                if(s[i].fnGetStr){
                    s[i].fnGetStr(dwData, szData, _countof(szData));
                }
                if(pTagInfo && szData[0]){
                    pTagInfo->wSetValueW(s[i].cszName, -1, szData, -1);
                }
                if(s[i].id == 0x35){//loopcount
                    m_xid6_length.dwLoopCount = dwData;
                }
            }
        }
        if(pSubChunk->type != 0){
            dwPos += (pSubChunk->length);
        }
        while(dwPos%4){
            dwPos++;
        }//4バイト境界
        if(dwPos > m_dwXid6Size){
            break;
        }
        pSubChunk = (XID6_SUBCHUNK*)(m_pXid6 + dwPos);
    }
}
///////////////////////////////////////////////////////////////////////////
UINT64 KbId666::GetLength(void)
{//xid6 のイントロ時間はイントロ＋ループ(１通り再生し終わるまでの長さ?)
 //KPI_MEDIAINFO::dwLength と同じ意味
    if(m_xid6_length.dwIntro){
        return TickTo100ns(m_xid6_length.dwIntro);
    }
    return (UINT64)m_id666_length.dwLength * 10000;
}
///////////////////////////////////////////////////////////////////////////
UINT64 KbId666::GetFade(void)
{
    if(m_xid6_length.dwFade != (DWORD)-1){
        return TickTo100ns(m_xid6_length.dwFade);
    }
    if(m_id666_length.dwFade != (DWORD)-1){
        return (UINT64)m_id666_length.dwFade * 10000;
    }
    return -1;
}
///////////////////////////////////////////////////////////////////////////
UINT64 KbId666::GetLoop(void)
{
    return TickTo100ns(m_xid6_length.dwLoop);
}
///////////////////////////////////////////////////////////////////////////
DWORD KbId666::GetLoopCount(void)
{
    //kpi のループ回数仕様に合わせるため +1 する必要がある
    //未指定の場合、m_xid6_length.dwLoopCount == (DWORD)-1 なので 0 に
    //なって丁度良い
    return m_xid6_length.dwLoopCount + 1;
}
///////////////////////////////////////////////////////////////////////////
INT64 KbId666::GetEnd(void)
{
    return TickTo100ns(m_xid6_length.nEnd);
}
///////////////////////////////////////////////////////////////////////////
DWORD KbId666::GetAmp(void)
{
    return m_xid6_length.dwAmp;
}
///////////////////////////////////////////////////////////////////////////
void __fastcall KbId666::GetTagInfo(IKpiTagInfo *pTagInfo, DWORD dwTagGetFlags)
{
    if(!pTagInfo){
        return;
    }
    //本体のデフォルトタグ取得ルーチンを呼ばなくさせる
    pTagInfo->wSetValueW(NULL, -1, NULL, -1);
    if((dwTagGetFlags & KPI_TAGGET_FLAG_GENERAL)){
        if(!m_bIsBinary){
            pTagInfo->wSetValueW(L"id666", -1, L"text", -1);
        }
        else{
            pTagInfo->wSetValueW(L"id666", -1, L"binary", -1);
        }
        if(m_pXid6){
            pTagInfo->wSetValueW(L"xid6", -1, L"stored", -1);
        }
        else{
            pTagInfo->wSetValueW(L"xid6", -1, L"not stored", -1);
        }
    }
    ReadXid6(pTagInfo, dwTagGetFlags);
    ReadId666(pTagInfo, dwTagGetFlags);
}
