#include "c2rw_gvar.h"
#include "c2rw_file.h"
#include "resource.h"

#include <commdlg.h>

LPTSTR GetProgramDir(void)
{
    static TCHAR    szPrgPath[MAX_PATH+2];
    DWORD           cnt;

    memset(szPrgPath, 0, sizeof(szPrgPath));
    if ((cnt = GetModuleFileName(NULL, (TCHAR*)&szPrgPath[1], sizeof(szPrgPath) / sizeof(TCHAR))) == 0) goto gprgdir_exit;
    // seach for '\'
    for (; cnt > 0;)
    {
        if (szPrgPath[--cnt] == '\\')
        {
            szPrgPath[cnt + 1] = 0;
            break;
        }
    }
    szPrgPath[0] = '"';
gprgdir_exit:
    return (LPTSTR)&szPrgPath[1];
}

void skip_spacesA(BYTE** pbuf)
{
    while (1)
    {
        if ((*(*pbuf) != 0x20) && (*(*pbuf) != 0x09)) break;
        (*pbuf)++;
    }
}

BOOL sgetbyteA(BYTE** pbuf, PBYTE val)
{
    BYTE    szDgt[4];
    DWORD   cnt;

    skip_spacesA(pbuf);
    memset(szDgt, 0, sizeof(szDgt));
    for (cnt = 0; cnt < 2; cnt++)
    {
        if (((*(*pbuf) >= 0x30) && (*(*pbuf) <= 0x39)) |
            ((*(*pbuf) >= 0x41) && (*(*pbuf) <= 0x46)) |
            ((*(*pbuf) >= 0x61) && (*(*pbuf) <= 0x66))) szDgt[cnt] = *(*pbuf);
        else break;
        (*pbuf)++;
    }
    if (cnt != 2) return FALSE;
    if (val)
    {
        *val = ((szDgt[0] > 0x39) ? szDgt[0] - 0x37 : szDgt[0] - 0x30) << 4;
        *val |= (szDgt[1] > 0x39) ? szDgt[1] - 0x37 : szDgt[1] - 0x30;
    }
    return TRUE;
}

// set/change file extension
void set_fileext(TCHAR* fnm, TCHAR* fext)
{
    DWORD       cnt;
    BOOL        ext;

    if (cnt = lstrlen(fnm)) // search for extension
    {
        // ok, search for extension point
        for (ext = FALSE; cnt != 0; cnt--)
        {
            if (fnm[cnt] == '.') { ext = TRUE; break; }
            if ((fnm[cnt] == '\\') || (fnm[cnt] == '/')) break;
        }
        if (ext == FALSE)
        {
            cnt = lstrlen(fnm);
            fnm[cnt + 0] = '.';
        }
        lstrcpy(&fnm[cnt + 1], fext);
    }
}

BOOL load_cfg(LPTSTR fname)
{
    HANDLE          fH = INVALID_HANDLE_VALUE;
    DWORD           tmp, fsize = 0;
    BYTE            buf[sizeof(C2RW_SET) + 1], crc8;
    BOOL            bRet = FALSE;

    // open file
    if ((fH = CreateFile(fname, GENERIC_READ, 0,
        NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE) goto ferr_exit;
    if ((fsize = GetFileSize(fH, NULL)) != sizeof(buf)) goto ferr_exit;             // check file size
    if ((!ReadFile(fH, buf, fsize, &tmp, NULL)) || (tmp != fsize)) goto ferr_exit;  // reading
    for (crc8 = 0, tmp = 0; tmp != (sizeof(buf) - 1); tmp++) crc8 += buf[tmp];      // calculate CRC8
    if (buf[tmp] != crc8) goto ferr_exit;
    memcpy(&c2rw_set, buf, sizeof(C2RW_SET));
    bRet = TRUE;
ferr_exit:
    if (fH != INVALID_HANDLE_VALUE) CloseHandle(fH);
    return bRet;
}

BOOL save_cfg(LPTSTR fname)
{
    HANDLE          fH = INVALID_HANDLE_VALUE;
    DWORD           tmp;
    BYTE            crc8, *buf;
    BOOL            bRet = FALSE;

    buf = (BYTE*)&c2rw_set; // create pointer to byte
    for (crc8 = 0, tmp = 0; tmp != sizeof(C2RW_SET); tmp++) crc8 += buf[tmp];   // calculate CRC8
    // open file
    if ((fH = CreateFile(fname, GENERIC_WRITE, 0,
        NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE) goto ferr_exit;
    // writing
    if ((!WriteFile(fH, buf, sizeof(C2RW_SET), &tmp, NULL)) || (tmp != sizeof(C2RW_SET))) goto ferr_exit;
    if ((!WriteFile(fH, &crc8, sizeof(crc8), &tmp, NULL)) || (tmp != sizeof(crc8))) goto ferr_exit;
    bRet = TRUE;
ferr_exit:
    if (fH != INVALID_HANDLE_VALUE) CloseHandle(fH);
    return bRet;
}

BOOL load_asc(LPTSTR fname)
{
    HANDLE          fH = INVALID_HANDLE_VALUE;
    DWORD           fsize = 0, cnt, idx;
    PBYTE           buf = NULL, cptr;
    BYTE            dump[4096];
    BOOL            bRet = FALSE;

    if (!fname) goto ferr_exit;
    // load ASCII dump
    if ((fH = CreateFile(fname, GENERIC_READ, FILE_SHARE_READ, NULL,
        OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE) goto ferr_exit;
    if (((fsize = GetFileSize(fH, NULL)) < 128) || (fsize > 0x10000)) goto ferr_exit;
    if ((buf = (PBYTE)GlobalAlloc(GPTR, fsize + 1)) == NULL) goto ferr_exit;
    if ((!ReadFile(fH, buf, fsize, &cnt, NULL)) || (cnt != fsize)) goto ferr_exit;
    buf[fsize] = 0;                                         // zero terminated string
    for (cnt = 0; cnt != fsize; cnt++)                      // kill control chars
        if (buf[cnt] < 0x20) buf[cnt] = 0x20;
    for (cptr = buf, cnt = 0; cnt < sizeof(dump); cnt++)    // data read
        if (!sgetbyteA(&cptr, &dump[cnt])) break;
    // determine gui(!) type
    for (idx = 0; idx <= MAX_CCTYPE; idx++)
    {
        if ((((DWORD)c2rw_dsc[idx].maxqs + 1) << 6) == cnt)
        {
            c2rw_set.tp = (BYTE)idx;
            memcpy(((c2rw_dsc[idx].tp == SCD_UL) ? c2rw_set.mfd_ul : c2rw_set.mfd_cl),
                dump, cnt); // copy data block
            break;
        }
    }
    if (idx <= MAX_CCTYPE) bRet = TRUE;
ferr_exit:
    if (buf) GlobalFree((HGLOBAL)buf);
    if (fH != INVALID_HANDLE_VALUE) CloseHandle(fH);
    return bRet;
}

BOOL save_asc(LPTSTR fname)
{
#define SBUFASC_SZ  0x10000
    HANDLE          fH = INVALID_HANDLE_VALUE;
    DWORD           dumplen, cnt, idx;
    PBYTE           buf = NULL;
    BYTE            dump[4096];
    BOOL            bRet = FALSE;

    if (!fname) goto ferr_exit;
    dumplen = ((DWORD)c2rw_dsc[c2rw_set.tp].maxqs + 1) << 6;    // determine dumplen
    // copy data to buffer
    memcpy(dump, (c2rw_dsc[c2rw_set.tp].tp == SCD_UL) ? c2rw_set.mfd_ul : c2rw_set.mfd_cl, dumplen);
    if ((buf = (PBYTE)GlobalAlloc(GPTR, SBUFASC_SZ)) == NULL) goto ferr_exit;
    // create ascii card dump
    for (idx = 0, cnt = 0; (cnt < dumplen) && (idx < (SBUFASC_SZ - 4)); cnt++)
    {
        BYTE    tb;
        tb = dump[cnt] >> 4;    // hi nibble
        buf[idx++] = (tb > 9) ? tb + 0x37 : tb + 0x30;
        tb = dump[cnt] & 0x0F;  // lo nibble
        buf[idx++] = (tb > 9) ? tb + 0x37 : tb + 0x30;
        if ((cnt % 16) == 15)
        {
            buf[idx++] = 0x0D;  // '\r'
            buf[idx++] = 0x0A;  // '\n'
        }
        if ((((cnt >> 4) < 128) && ((cnt % 64) == 63)) ||
            (((cnt >> 4) >= 128) && ((cnt % 256) == 255)))
        {
            buf[idx++] = 0x0D;  // '\r'
            buf[idx++] = 0x0A;  // '\n'
        }
    }
    DeleteFile(fname);  // erase old file
    if ((fH = CreateFile(fname, GENERIC_WRITE, FILE_SHARE_READ, NULL,
        OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE) goto ferr_exit;
    if ((!WriteFile(fH, buf, idx, &cnt, NULL)) || (idx != cnt)) goto ferr_exit;
    bRet = TRUE;
ferr_exit:
    if (buf) GlobalFree((HGLOBAL)buf);
    if (fH != INVALID_HANDLE_VALUE) CloseHandle(fH);
    return bRet;
}

BOOL load_bin(LPTSTR fname)
{
    HANDLE          fH = INVALID_HANDLE_VALUE;
    DWORD           fsize = 0, cnt;
    BYTE            dump[4096], tp;
    BOOL            bRet = FALSE;

    tp = c2rw_set.tp;
    if (!fname) goto ferr_exit;
    // load binary dump
    if ((fH = CreateFile(fname, GENERIC_READ, FILE_SHARE_READ, NULL,
        OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE) goto ferr_exit;
    if (((fsize = GetFileSize(fH, NULL)) < 64) || (fsize > 4096)) goto ferr_exit;
    // determine gui(!) type
    for (cnt = 0; cnt <= MAX_CCTYPE; cnt++)
    {
        if ((((DWORD)c2rw_dsc[cnt].maxqs + 1) << 6) == fsize)
        {
            tp = (BYTE)cnt;
            break;
        }
    }
    if (cnt > MAX_CCTYPE) goto ferr_exit;   // if invalid size
    if ((!ReadFile(fH, dump, fsize, &cnt, NULL)) || (cnt != fsize)) goto ferr_exit;
    c2rw_set.tp = tp;   // set new card type
    memcpy(((c2rw_dsc[tp].tp == SCD_UL) ? c2rw_set.mfd_ul : c2rw_set.mfd_cl), dump, cnt);   // copy data block
    bRet = TRUE;
ferr_exit:
    if (fH != INVALID_HANDLE_VALUE) CloseHandle(fH);
    return bRet;
}

BOOL save_bin(LPTSTR fname)
{
    HANDLE          fH = INVALID_HANDLE_VALUE;
    DWORD           dumplen, tmp;
    BYTE            dump[4096];
    BOOL            bRet = FALSE;

    if (!fname) goto ferr_exit;
    dumplen = ((DWORD)c2rw_dsc[c2rw_set.tp].maxqs + 1) << 6;    // determine dumplen
    // copy data to buffer
    memcpy(dump, (c2rw_dsc[c2rw_set.tp].tp == SCD_UL) ? c2rw_set.mfd_ul : c2rw_set.mfd_cl, dumplen);
    DeleteFile(fname);  // erase old file
    if ((fH = CreateFile(fname, GENERIC_WRITE, FILE_SHARE_READ, NULL,
        OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE) goto ferr_exit;
    if ((!WriteFile(fH, dump, dumplen, &tmp, NULL)) || (dumplen != tmp)) goto ferr_exit;
    bRet = TRUE;
ferr_exit:
    if (fH != INVALID_HANDLE_VALUE) CloseHandle(fH);
    return bRet;
}


void build_fname(DWORD nres_ext)
{
    TCHAR       szLocal[32];

    lstrcpy(filepath, c2rw_dsc[c2rw_set.tp].txt);   // copy card name
    lstrcat(filepath, TEXT("_"));
    GetDlgItemText(hMain, IDE_SCUID, szLocal, sizeof(szLocal) / sizeof(TCHAR));
    lstrcat(filepath, szLocal);                     // add UID
    LoadString(hInst, nres_ext, szLocal, sizeof(szLocal) / sizeof(TCHAR));
    lstrcat(filepath, szLocal);                     // add extension
}

// load file dialog; length of fname must be MAX_PATH
BOOL dlg4load(DWORD nres_cap, DWORD nres_flt, TCHAR *fname)
{
    TCHAR           szFilt[256] = { 0 };
    TCHAR           szCap[256] = { 0 };
    TCHAR           szfd[MAX_PATH];
    OPENFILENAME    ofn;
    BOOL            bRet = FALSE;

    if (fname)
    {
        LoadString(hInst, nres_cap, szCap, sizeof(szCap) / sizeof(TCHAR));
        LoadString(hInst, nres_flt, szFilt, sizeof(szFilt) / sizeof(TCHAR));
        GetCurrentDirectory(sizeof(szfd) / sizeof(TCHAR), szfd);

        memset(&ofn, 0, sizeof(ofn));
        ofn.lStructSize = sizeof(ofn);
        ofn.hwndOwner = hMain;
        ofn.lpstrFilter = szFilt;
        ofn.nFilterIndex = 0;
        ofn.lpstrFile = fname;
        ofn.nMaxFile = MAX_PATH;
        ofn.lpstrInitialDir = szfd;
        ofn.lpstrTitle = szCap;
        ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST |
            OFN_HIDEREADONLY | OFN_EXPLORER | OFN_NONETWORKBUTTON;
    }
    // open dialog
    return ((GetOpenFileName(&ofn)) ? TRUE : FALSE);
}

// save file dialog; length of fname must be MAX_PATH
BOOL dlg4save(DWORD nres_cap, DWORD nres_flt, TCHAR *fname)
{
    TCHAR           szFilt[256] = { 0 };
    TCHAR           szCap[256] = { 0 };
    TCHAR           szExt[16] = { 0 };
    TCHAR           szfd[MAX_PATH];
    OPENFILENAME    ofn;
    BOOL            bRet = FALSE;

    if (fname)
    {
        LoadString(hInst, nres_cap, szCap, sizeof(szCap) / sizeof(TCHAR));
        LoadString(hInst, nres_flt, szFilt, sizeof(szFilt) / sizeof(TCHAR));
        GetCurrentDirectory(sizeof(szfd) / sizeof(TCHAR), szfd);

        memset(&ofn, 0, sizeof(ofn));
        ofn.lStructSize = sizeof(ofn);
        ofn.hwndOwner = hMain;
        ofn.lpstrFilter = szFilt;
        ofn.nFilterIndex = 0;
        ofn.lpstrFile = fname;
        ofn.nMaxFile = MAX_PATH;
        ofn.lpstrInitialDir = szfd;
        ofn.lpstrTitle = szCap;
        ofn.Flags = OFN_HIDEREADONLY | OFN_EXPLORER | OFN_NONETWORKBUTTON;
    }
    // open dialog
    return ((GetSaveFileName(&ofn)) ? TRUE : FALSE);
}
