#pragma warning (disable:4996)
#include "c2rw.h"
#include "c2rw_gui.h"
#include "c2rw_gvar.h"
#include "resource.h"

#include <commctrl.h>

// convertation: quad sector to real sector
BYTE qs2rs(BYTE qs)
{
    return ((qs < 32) ? qs : (qs >> 2) + 24);
}

// convertation: quad sector to blk-trailer
BYTE qs2trailer(BYTE qs)
{
    return (qs < 32) ? (qs << 2) | 3 : (qs << 2) | 0x0F;
}

// convertation: real sector to start block
BYTE rs2sblk(BYTE rs)
{
    return (rs < 32) ? rs << 2 : (rs - 24) << 4;
}

// convertation: real sector to blk-trailer
BYTE rs2trailer(BYTE rs)
{
    return (rs < 32) ? (rs << 2) | 3 : (rs - 24) << 4 | 0x0F;
}


// convertation: block to real sector
BYTE blk2rs(BYTE blk)
{
    return (blk < 128) ? blk >> 2 : (blk >> 4) + 24;
}

// trailer check
BOOL istrailer(BYTE blk)
{
    return (blk < 128) ? (((blk & 3) == 3) ? TRUE : FALSE) : (((blk & 15) == 15) ? TRUE : FALSE);
}

// block state: en or di
BOOL blkstate(BYTE blk)
{
    return (c2rw_set.cl_en[blk2rs(blk)] & ((blk < 128) ? bitsh[blk & 3] : bitsh[blk & 15])) ? TRUE : FALSE;
}

// real sector state: en or di
BOOL get_rsstate(BYTE blk)
{
    return (c2rw_set.cl_en[blk2rs(blk)] & ((blk < 128) ? 0x0F : 0xFFFF)) ? TRUE : FALSE;
}
// set new state to block
void set_blkstate(BYTE blk, BOOL en)
{
    WORD    mask;

    mask = ((blk < 128) ? bitsh[blk & 3] : bitsh[blk & 15]);
    if (en) c2rw_set.cl_en[blk2rs(blk)] |= mask;
    else c2rw_set.cl_en[blk2rs(blk)] &= ~mask;
}

// page state: en or di
BOOL get_pgstate(BYTE pg)
{
    return (c2rw_set.ul_en & bitsh[pg]) ? TRUE : FALSE;
}

// set new state to page
void set_pgstate(BYTE pg, BOOL en)
{
    WORD    mask;

    mask = bitsh[pg];
    if (en) c2rw_set.ul_en |= mask;
    else c2rw_set.ul_en &= ~mask;
}

// window centering fn
BOOL CenterWindow(HWND hwndChild, HWND hwndParent)
{
    RECT            rcChild,rcParent;
    int             cxChild,cyChild,cxParent,cyParent;
    int             cxScreen,cyScreen, xNew,yNew;
    HDC             hdc;
    // get the Height and Width of the child window
    GetWindowRect(hwndChild, &rcChild);
    cxChild=rcChild.right-rcChild.left;
    cyChild=rcChild.bottom-rcChild.top;
    // get the Height and Width of the parent window
    GetWindowRect(hwndParent,&rcParent);
    cxParent=rcParent.right-rcParent.left;
    cyParent=rcParent.bottom-rcParent.top;
    // get the display limits
    hdc = GetDC(hwndChild);
    cxScreen = GetDeviceCaps(hdc, HORZRES);
    cyScreen = GetDeviceCaps(hdc, VERTRES);
    ReleaseDC(hwndChild, hdc);
    // calculate new X position, then adjust for screen
    xNew = rcParent.left + ((cxParent - cxChild) / 2);
    if (xNew < 0) xNew = 0;
    else if ((xNew + cxChild) > cxScreen) xNew = cxScreen - cxChild;
    // Calculate new Y position, then adjust for screen
    yNew = rcParent.top  + ((cyParent - cyChild) / 2);
    if (yNew < 0) yNew = 0;
    else if ((yNew + cyChild) > cyScreen) yNew = cyScreen - cyChild;
    // Set it, and return
    return SetWindowPos(hwndChild, NULL, xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
}

// error box
int dlg4err(DWORD nres_cap, DWORD nres1_msg, DWORD nres2_msg, DWORD boxflg)
{
    TCHAR       szCapt[64];
    TCHAR       szMsg[256];

    LoadString(hInst, nres_cap, szCapt, sizeof(szCapt) / sizeof(TCHAR));
    LoadString(hInst, nres1_msg, szMsg, sizeof(szMsg) / sizeof(TCHAR));
    if (nres2_msg)
    {
        LoadString(hInst, nres2_msg, &szMsg[lstrlen(szMsg)], (sizeof(szMsg) - lstrlen(szMsg)) / sizeof(TCHAR));
    }
    return MessageBox(NULL, &szMsg[1], szCapt, boxflg);
}

// stretch bitmap
void stretch4menu(HBITMAP* hbmp, int isz)
{
    HDC                     hSrc, hDst;
    HBITMAP                 hobd;
    int                     mcx, mcy;
    static  OSVERSIONINFOEX ov = { 0 };

    ov.dwOSVersionInfoSize = sizeof(ov);
    if ((GetVersionEx((LPOSVERSIONINFO)&ov)) && (ov.dwMajorVersion > 5)) return;
    mcx = GetSystemMetrics(SM_CXMENUCHECK) + 1;
    mcy = GetSystemMetrics(SM_CYMENUCHECK) + 1;
    hSrc = CreateCompatibleDC(NULL);
    DeleteObject(SelectObject(hSrc, *hbmp));
    hDst = CreateCompatibleDC(NULL);
    hobd = (HBITMAP)SelectObject(hDst, (HGDIOBJ)CreateCompatibleBitmap(hSrc, mcx, mcy));
    StretchBlt(hDst, 0, 0, mcx, mcy, hSrc, 0, 0, isz, isz, SRCCOPY);
    *hbmp = (HBITMAP)SelectObject(hDst, hobd);
    DeleteDC(hSrc);
    DeleteDC(hDst);
}

// set color mask to bitmap
HBITMAP bmpcolormask(HBITMAP* hbmp, COLORREF bk, DWORD size)
{
    HDC             hDC;
    HBRUSH          hbr, hobr;
    HBITMAP         hob;

    hDC = CreateCompatibleDC(NULL);
    hob = (HBITMAP)SelectObject(hDC, *hbmp);
    hbr = CreateSolidBrush(bk);
    hobr = (HBRUSH)SelectObject(hDC, hbr);
    // выбираем цвет пикселя для удаления
    bk = GetPixel(hDC, 0, 0);
    // делаем новый фон
    ExtFloodFill(hDC, 0, 0, bk, FLOODFILLSURFACE);
    // делаем новый фон
    ExtFloodFill(hDC, size - 1, 0, bk, FLOODFILLSURFACE);
    // делаем новый фон
    ExtFloodFill(hDC, 0, size - 1, bk, FLOODFILLSURFACE);
    // делаем новый фон
    ExtFloodFill(hDC, size - 1, size - 1, bk, FLOODFILLSURFACE);
    SelectObject(hDC, hobr);
    DeleteObject(hbr);
    *hbmp = (HBITMAP)SelectObject(hDC, hob);
    DeleteDC(hDC);
    return *hbmp;
}

void gui_setmenucheck(DWORD nres, BOOL chk)
{
    CheckMenuItem(GetMenu(hMain), nres, MF_BYCOMMAND | ((chk) ? MF_CHECKED : MF_UNCHECKED));
}

BOOL gui_getmenucheck(DWORD nres)
{
    MENUITEMINFO        mii;
    memset(&mii, 0, sizeof(mii));
    mii.cbSize = sizeof(mii);
    mii.fMask = MIIM_CHECKMARKS;
    return ((GetMenuItemInfo(GetMenu(hMain), nres, FALSE, &mii)) && (mii.fState == MFS_CHECKED)) ? TRUE : FALSE;
}

// set icon to menu item
void gui_setmenuicon(DWORD nres, DWORD mnu)
{
    MENUITEMINFO        mii;
    // set menu icon
    memset(&mii, 0, sizeof(mii));
    mii.cbSize = sizeof(mii);
    mii.fMask = MIIM_CHECKMARKS;
    // set menu binary icon
    mii.hbmpUnchecked = LoadBitmap(hInst, MAKEINTRESOURCE(nres));
    bmpcolormask(&mii.hbmpUnchecked, GetSysColor(COLOR_MENU), ICONL_SIZE);
    stretch4menu(&mii.hbmpUnchecked, ICONL_SIZE);
    SetMenuItemInfo(GetMenu(hMain), mnu, FALSE, &mii);
}

// set message to status bar
void gui_stbar(LPTSTR szText)
{
    if (szText[0])
    {
        DWORD       icn = IDI_STINFO;
        if (szText[0] == 2) icn = IDI_STOK;
        else if (szText[0] == 3) icn = IDI_STFAIL;
        else if (szText[0] == 4) icn = IDI_STRFSH;
        SendMessage(GetDlgItem(hMain, IDC_STBAR), SB_SETICON, 0, (LPARAM)LoadImage(hInst, MAKEINTRESOURCE(icn), IMAGE_ICON, 16, 16, LR_SHARED));
        SendMessage(GetDlgItem(hMain, IDC_STBAR), SB_SETTEXT, 0, (LPARAM)&szText[1]);
    }
}
// set message to status bar by resource number
void gui_res2stbar(DWORD nres)
{
    TCHAR       szLocal[256];
    LoadString(hInst, nres, szLocal, sizeof(szLocal) / sizeof(TCHAR));
    gui_stbar(szLocal);
}
// set status to "Complete" state
void gui_ok2stbar(void)
{
    TCHAR       szLocal[256];
    TCHAR       szOk[32];

    LoadString(hInst, STR_ACOMPLETE, szOk, sizeof(szOk) / sizeof(TCHAR));
    SendMessage(GetDlgItem(hMain, IDC_STBAR), SB_GETTEXT, 0, (LPARAM)&szLocal[1]);
    lstrcat(szLocal, szOk);
    szLocal[0] = 2;
    gui_stbar(szLocal);
}

// input hex string from edit control(nres) to buf(max 16 bytes)
BOOL gui_gethex(DWORD nres, DWORD buflen, PBYTE buf)
{
    TCHAR       szLocal[36];
    TCHAR       szDgt[4];
    DWORD       tmp;
    BOOL        bRet = FALSE;

    if (((tmp = GetDlgItemText(hMain, nres, szLocal, sizeof(szLocal) / sizeof(TCHAR))) == (buflen * 2)) && (buf))
    {
        for (tmp = 0; tmp != (buflen * 2); tmp++)
            if (!_istxdigit(szLocal[tmp])) break;
        if (tmp == (buflen * 2))
        {
            for (tmp = 0; tmp != buflen; tmp++)
            {
                DWORD       tb;
                szDgt[0] = szLocal[tmp * 2 + 0]; szDgt[1] = szLocal[tmp * 2 + 1]; szDgt[2] = 0;
                tb = 0; _stscanf(szDgt, TEXT("%X"), &tb);
                buf[tmp] = (BYTE)tb;
            }
            bRet = TRUE;
        }
    }
    return bRet;
}

// update UID, ATQA, SAK from sector/page 0
void gui_upzero(void)
{
    BYTE        buf[10];
    BYTE        buflen, buferr, plf;
    WORD        atqa;
    BYTE        sak;

    TCHAR       szLocal[40];
    DWORD       cnt;

    // vars initialization
    plf = FALSE;                    // PL-flag
    buferr = TRUE;
    memset(buf, 0, sizeof(buf));    // UID by default
    buflen = 0;
    atqa = 0;                       // ATQA by default
    sak = 0;                        // SAK by default

    if (c2rw_dsc[c2rw_set.tp].tp == SCD_UL)
    {
        // build UID
        buflen = 7;
        buf[0] = c2rw_set.mfd_ul[0];
        buf[1] = c2rw_set.mfd_ul[1];
        buf[2] = c2rw_set.mfd_ul[2];
        buf[3] = c2rw_set.mfd_ul[4];
        buf[4] = c2rw_set.mfd_ul[5];
        buf[5] = c2rw_set.mfd_ul[6];
        buf[6] = c2rw_set.mfd_ul[7];
        if (((buf[0] ^ buf[1] ^ buf[2] ^ c2rw_set.mfd_ul[3]) == 0x88) &&
            ((buf[3] ^ buf[4] ^ buf[5] ^ buf[6]) == c2rw_set.mfd_ul[8]) ) buferr = FALSE;
        // gui output: INT
        wsprintf(szLocal, TEXT("%02X"), (DWORD)c2rw_set.mfd_ul[9]);
        SetDlgItemText(hMain, IDE_SCPARM0, szLocal);
        // gui output: BCC1
        wsprintf(szLocal, TEXT("%02X"), (DWORD)c2rw_set.mfd_ul[3]);
        SetDlgItemText(hMain, IDE_SCPARM1, szLocal);
        // gui output: BCC2
        wsprintf(szLocal, TEXT("%02X"), (DWORD)c2rw_set.mfd_ul[8]);
        SetDlgItemText(hMain, IDE_SCPARM2, szLocal);
    }
    else if ((c2rw_dsc[c2rw_set.tp].tp == SCD_CL1K) || (c2rw_dsc[c2rw_set.tp].tp == SCD_CL4K))
    {
        // build UID
        buflen = 4;
        buf[0] = c2rw_set.mfd_cl[0];
        buf[1] = c2rw_set.mfd_cl[1];
        buf[2] = c2rw_set.mfd_cl[2];
        buf[3] = c2rw_set.mfd_cl[3];
        if ((buf[0] ^ buf[1] ^ buf[2] ^ buf[3] ^ c2rw_set.mfd_cl[4]) == 0) buferr = FALSE;
        // gui output: BCC
        wsprintf(szLocal, TEXT("%02X"), (DWORD)c2rw_set.mfd_cl[4]);
        SetDlgItemText(hMain, IDE_SCPARM0, szLocal);
        // gui output: SAK
        wsprintf(szLocal, TEXT("%02X"), (DWORD)c2rw_set.mfd_cl[5]);
        SetDlgItemText(hMain, IDE_SCPARM1, szLocal);
        // gui output: ATQA
        wsprintf(szLocal, TEXT("%04X"), ((DWORD)c2rw_set.mfd_cl[6]) | ((DWORD)c2rw_set.mfd_cl[7] << 8));
        SetDlgItemText(hMain, IDE_SCPARM2, szLocal);
    }
    else if ((c2rw_dsc[c2rw_set.tp].tp == SCD_PL2S1) || (c2rw_dsc[c2rw_set.tp].tp == SCD_PL4S1))
    {
        // build UID
        buflen = 7;
        buf[0] = c2rw_set.mfd_cl[0];
        buf[1] = c2rw_set.mfd_cl[1];
        buf[2] = c2rw_set.mfd_cl[2];
        buf[3] = c2rw_set.mfd_cl[3];
        buf[4] = c2rw_set.mfd_cl[4];
        buf[5] = c2rw_set.mfd_cl[5];
        buf[6] = c2rw_set.mfd_cl[6];
        plf = TRUE;
        buferr = FALSE;
        // gui output: unused parm 0
        SetDlgItemText(hMain, IDE_SCPARM0, TEXT(""));
        // gui output: SAK
        wsprintf(szLocal, TEXT("%02X"), (DWORD)c2rw_set.mfd_cl[7]);
        SetDlgItemText(hMain, IDE_SCPARM1, szLocal);
        // gui output: ATQA
        wsprintf(szLocal, TEXT("%04X"), ((WORD)c2rw_set.mfd_cl[8]) | ((WORD)c2rw_set.mfd_cl[9] << 8));
        SetDlgItemText(hMain, IDE_SCPARM2, szLocal);
    }
    // gui output: UID
    szLocal[0] = 0;
    if (buflen)
    {
        for (cnt = 0; (cnt < (DWORD)buflen) && (cnt < 10); cnt++)
            wsprintf(&szLocal[lstrlen(szLocal)], TEXT("%02X"), buf[cnt]);
        if (buferr) lstrcat(szLocal, TEXT("[err]"));
    }
    SetDlgItemText(hMain, IDE_SCUID, szLocal);
    EnableWindow(GetDlgItem(hMain, IDC_SCUFIX), (BOOL)buflen);
}

BOOL gui_getzero(void)
{
    BYTE        buf[16];
    DWORD       cnt;
    BOOL        bRet = FALSE;

    if (c2rw_dsc[c2rw_set.tp].tp == SCD_UL)
    {

        for (cnt = 0; cnt < 3; cnt++)
            if (!gui_gethex(IDE_PG00 + cnt, 4, &buf[cnt << 2])) break;
        if (cnt == 3)
        {
            memcpy(&c2rw_set.mfd_ul, buf, 12);      // copy pages 0..2 to memory
            bRet = TRUE;
        }
    }
    else
    {
        if (c2rw_set.qs == 0)
        {
            if (gui_gethex(IDE_DATA0, 16, buf))
            {
                memcpy(c2rw_set.mfd_cl, buf, 16);   // copy data to memory block
                bRet = TRUE;
            }
        }
    }
    return bRet;
}

// set type of card
void gui_settp(void)
{
    updif = TRUE;                       // disable update
    gui_setdata();                      // update all fields with data from other quad
    gui_setqs();                        // set new selector by card type
    SendMessage(GetDlgItem(hMain, IDC_SCTPSEL), CB_SETCURSEL, (WPARAM)c2rw_set.tp, 0);
    gui_upzero();                       // update card parameters group
    updif = FALSE;                      // enable update
}

// read type of card
BYTE gui_gettp(void)
{
    DWORD       tmp;
    if (((tmp = SendMessage(GetDlgItem(hMain, IDC_SCTPSEL), CB_GETCURSEL, 0, 0)) == CB_ERR) ||
        (tmp > MAX_CCTYPE))
    {
        tmp = 0;
    }
    return (BYTE)tmp;
}

// reinitialize quad sector selector
void gui_setqs(void)
{
    TCHAR       szLocal[16];
    DWORD       cnt;
    BOOL        setf;

    updif = TRUE;
    if (c2rw_dsc[c2rw_set.tp].tp != SCD_UL)
    {
        // sector selector initialize
        SendMessage(GetDlgItem(hMain, IDC_SCSSEL), CB_RESETCONTENT, 0, 0);
        for (setf = FALSE, cnt = 0; cnt <= c2rw_dsc[c2rw_set.tp].maxqs; cnt++)
        {
            if (cnt < 32) wsprintf(szLocal, TEXT(" %2u"), cnt);
            else wsprintf(szLocal, TEXT("%2u/%u"), cnt / 4 + 24, cnt & 3);
            SendMessage(GetDlgItem(hMain, IDC_SCSSEL), CB_INSERTSTRING, cnt, (LPARAM)szLocal);
            if (cnt == c2rw_set.qs)
            {
                SendMessage(GetDlgItem(hMain, IDC_SCSSEL), CB_SETCURSEL, (WPARAM)cnt, 0);
                setf = TRUE;
            }
        }
        if (!setf)
        {
            c2rw_set.qs = 0;
            SendMessage(GetDlgItem(hMain, IDC_SCSSEL), CB_SETCURSEL, (WPARAM)c2rw_set.qs, 0);
        }
    }
    updif = FALSE;
}

// read quad sector selector
BYTE gui_getqs(void)
{
    DWORD       tmp;
    // quad sector
    if (((tmp = SendMessage(GetDlgItem(hMain, IDC_SCSSEL), CB_GETCURSEL, 0, 0)) == CB_ERR) || (tmp > 63))
    {
        tmp = 0;
    }
    return (BYTE)tmp;
}

void gui_dupkeyA(void)
{
    TCHAR       szLocal[32];

    szLocal[0] = 0;
    GetDlgItemText(hMain, IDE_SCKEYA, szLocal, sizeof(szLocal) / sizeof(TCHAR));
    SetDlgItemText(hMain, IDE_DATA3A, szLocal);
}

void gui_dupkeyB(void)
{
    TCHAR       szLocal[32];

    szLocal[0] = 0;
    GetDlgItemText(hMain, IDE_SCKEYB, szLocal, sizeof(szLocal) / sizeof(TCHAR));
    SetDlgItemText(hMain, IDE_DATA3B, szLocal);
}

// set new data to data group
void gui_setdata(void)
{
    BYTE        buf[16];
    BYTE        buflen = 0;

    TCHAR       szLocal[40];
    DWORD       cnt, idx;
    BYTE        blk, tblk;

    updif = TRUE;

    gui_setmenucheck(CM_NRWMSG, c2rw_set.flg & MASK_NRWMSG);    // update non-RW card message state
    gui_setmenucheck(CM_ALLDT, c2rw_set.flg & MASK_ALLDATA);    // update "read-all" option
    gui_upzero();   // update UID, ATQA, SAK

    // *** CL/PL ***
    // calculate trailer
    tblk = qs2trailer(c2rw_set.qs);
    // gui output: block activity
    for (blk = c2rw_set.qs << 2, cnt = 0; cnt != 4; cnt++)
    {
        SendMessage(GetDlgItem(hMain, cnt + IDX_DATA0), BM_SETCHECK,
            (WPARAM)((blkstate(blk + (BYTE)cnt)) ? BST_CHECKED : BST_UNCHECKED), 0);
    }
    // RW-mode set
    SendMessage(GetDlgItem(hMain, IDC_SCRW), BM_SETCHECK,
        (WPARAM)((c2rw_set.flg & MASK_RWCARD) ? BST_CHECKED : BST_UNCHECKED), 0);
    // gui output: key A
    memcpy(buf, &c2rw_set.mfd_cl[((DWORD)tblk) << 4], 6);           // copy auth A data
    for (szLocal[0] = 0, cnt = 0; cnt != 6; cnt++)
        wsprintf(&szLocal[lstrlen(szLocal)], TEXT("%02X"), buf[cnt]);
    SetDlgItemText(hMain, IDE_SCKEYA, szLocal);     // output auth A value
    SetDlgItemText(hMain, IDE_DATA3A, szLocal);     // field in data record
    // gui output: key mode
    memcpy(buf, &c2rw_set.mfd_cl[(((DWORD)tblk) << 4) + 6], 4);     // copy key mode
    for (szLocal[0] = 0, cnt = 0; cnt != 4; cnt++)
        wsprintf(&szLocal[lstrlen(szLocal)], TEXT("%02X"), buf[cnt]);
    SetDlgItemText(hMain, IDE_DATA3M, szLocal);     // field in data record
    // gui output: key B
    memcpy(buf, &c2rw_set.mfd_cl[(((DWORD)tblk) << 4) + 10], 6);    // copy auth B data
    for (szLocal[0] = 0, cnt = 0; cnt != 6; cnt++)
        wsprintf(&szLocal[lstrlen(szLocal)], TEXT("%02X"), buf[cnt]);
    SetDlgItemText(hMain, IDE_SCKEYB, szLocal);     // output auth B value
    SetDlgItemText(hMain, IDE_DATA3B, szLocal);     // field in data record
    // gui output: data rows
    blk = c2rw_set.qs << 2; // row 0 setup
    for (idx = 0; idx != 4; idx++, blk++)
    {
        // text message output
        memcpy(buf, &c2rw_set.mfd_cl[((DWORD)blk) << 4], 16);   // copy block data
        wsprintf(szLocal, TEXT("%c%u:%u / B%u"),
            (istrailer(blk)) ? 'T' : 'S',
            blk2rs(blk),
            (blk < 128) ? blk & 3 : blk & 15,
            blk);
        SetDlgItemText(hMain, IDT_DATA0 + idx, szLocal);    // output row 0 help string
        // data output
        for (szLocal[0] = 0, cnt = 0; cnt != 16; cnt++)
            wsprintf(&szLocal[lstrlen(szLocal)], TEXT("%02X"), buf[cnt]);
        SetDlgItemText(hMain, IDE_DATA0 + idx, szLocal);    // output row 0 data string
    }
    // *** UL ***
    for (idx = 0; idx != 16; idx++)
    {
        // gui output: page activity
        SendMessage(GetDlgItem(hMain, idx + IDX_PG00), BM_SETCHECK,
            (WPARAM)((c2rw_set.ul_en & bitsh[idx]) ? BST_CHECKED : BST_UNCHECKED), 0);
        // data output
        memcpy(buf, &c2rw_set.mfd_ul[idx << 2], 4);     // copy page data
        for (szLocal[0] = 0, cnt = 0; cnt != 4; cnt++)
            wsprintf(&szLocal[lstrlen(szLocal)], TEXT("%02X"), buf[cnt]);
        SetDlgItemText(hMain, IDE_PG00 + idx, szLocal); // output page data string
    }
    updif = FALSE;
}

// read all data exclude quad sector (see gui_getqs)
BOOL gui_getall(DWORD iflg)
{
    BYTE        authA[6], authB[6];
    BOOL        authAerr = TRUE, authBerr = TRUE;
    BYTE        blk;
    BOOL        ierr = FALSE;

    BYTE        buf[16];
    DWORD       cnt, tmp;

    // card type
    if (((tmp = SendMessage(GetDlgItem(hMain, IDC_SCTPSEL), CB_GETCURSEL, 0, 0)) == CB_ERR) || (tmp > MAX_CCTYPE))
    {
        ierr = TRUE;
    }
    else c2rw_set.tp = (BYTE)tmp;
    // rw-mode
    c2rw_set.flg &= ~MASK_RWCARD;
    c2rw_set.flg |= (SendMessage(GetDlgItem(hMain, IDC_SCRW), BM_GETCHECK, 0, 0) == BST_CHECKED) ? MASK_RWCARD : 0;
    // auth A
    if (gui_gethex(IDE_SCKEYA, 6, authA)) authAerr = FALSE;
    else ierr = TRUE;
    // auth B
    if (gui_gethex(IDE_SCKEYB, 6, authB)) authBerr = FALSE;
    else ierr = TRUE;
    if ((iflg & IFLG_NODATA) == 0)
    {
        // *** CL/PL data ***
        // copy data from gui to dump
        for (blk = c2rw_set.qs << 2, cnt = 0; cnt < 4; cnt++, blk++)
        {
            // read block activity
            set_blkstate(blk,
                (SendMessage(GetDlgItem(hMain, cnt + IDX_DATA0), BM_GETCHECK, 0, 0) == BST_CHECKED) ? TRUE : FALSE);
            // read data
            if (istrailer(blk))
            {
                if (gui_gethex(IDE_DATA3M, 4, buf)) memcpy(&c2rw_set.mfd_cl[(((DWORD)blk) << 4) + 6], buf, 4);  // copy mode bytes to trailer
                else ierr = TRUE;
            }
            else
            {
                if (gui_gethex(IDE_DATA0 + cnt, 16, buf)) memcpy(&c2rw_set.mfd_cl[((DWORD)blk) << 4], buf, 16); // copy data to memory block
                else ierr = TRUE;
            }
        }
        // *** UL data ***
        // copy data from gui to dump
        for (cnt = 0; cnt < 16; cnt++)
        {
            // read page activity
            set_pgstate((BYTE)cnt,
                (SendMessage(GetDlgItem(hMain, cnt + IDX_PG00), BM_GETCHECK, 0, 0) == BST_CHECKED) ? TRUE : FALSE);
            // read data
            if (gui_gethex(IDE_PG00 + cnt, 4, buf)) memcpy(&c2rw_set.mfd_ul[cnt << 2], buf, 4); // copy page to memory
            else ierr = TRUE;
        }
    }
    blk = qs2trailer(c2rw_set.qs);  // calculate trailer block
    if (!authAerr) memcpy(&c2rw_set.mfd_cl[((DWORD)blk) << 4], authA, 6);           // copy key A to memory block
    if (!authBerr) memcpy(&c2rw_set.mfd_cl[(((DWORD)blk) << 4) + 10], authB, 6);    // copy key B to memory block

    if (ierr) gui_setdata();
    return (BOOL)(!ierr);
}

// controls disable/enable
void gui_disen(BOOL eidi)
{
    TCHAR       szLocal[128];
    DWORD       cnt;
    BOOL        clf, rwf, tmpf;

    // disable fix button
    EnableWindow(GetDlgItem(hMain, IDC_SCUFIX), eidi);
    // card type: UL / CL
    clf = (SendMessage(GetDlgItem(hMain, IDC_SCTPSEL), CB_GETCURSEL, 0, 0)) ? TRUE : FALSE;
    // rw-mode
    rwf = (SendMessage(GetDlgItem(hMain, IDC_SCRW), BM_GETCHECK, 0, 0) == BST_CHECKED) ? FALSE : TRUE;
    // global controls
    EnableWindow(GetDlgItem(hMain, IDC_SCTPSEL), eidi);     // card type selector
    EnableWindow(GetDlgItem(hMain, IDC_SCTPSRCH), eidi);    // search type button
    EnableWindow(GetDlgItem(hMain, IDC_SCRW), eidi);        // RW checkbox

    EnableWindow(GetDlgItem(hMain, IDC_SCRDCRD), eidi);     // RD card
    EnableWindow(GetDlgItem(hMain, IDC_SCWRCRD), eidi);     // WR card

    // change UID frame caption
    LoadString(hInst, ((clf) ? STR_CUGBLK : STR_CUGPGS), szLocal, sizeof(szLocal) / sizeof(TCHAR));
    SetDlgItemText(hMain, IDC_SCUGRP, szLocal);
    // hide/show and change caption for controls
    if (c2rw_dsc[c2rw_set.tp].tp == SCD_UL)
    {
        // parameter 0 (INT for UL)
        SetDlgItemText(hMain, IDT_SCPARM0, TEXT("INT"));
        ShowWindow(GetDlgItem(hMain, IDT_SCPARM0), SW_SHOW);
        ShowWindow(GetDlgItem(hMain, IDE_SCPARM0), SW_SHOW);
        // parameter 1 (BCC1 for UL)
        SetDlgItemText(hMain, IDT_SCPARM1, TEXT("BCC1"));
        ShowWindow(GetDlgItem(hMain, IDT_SCPARM1), SW_SHOW);
        ShowWindow(GetDlgItem(hMain, IDE_SCPARM1), SW_SHOW);
        // parameter 2 (BCC2 for UL)
        SetDlgItemText(hMain, IDT_SCPARM2, TEXT("BCC2"));
        ShowWindow(GetDlgItem(hMain, IDT_SCPARM2), SW_SHOW);
        ShowWindow(GetDlgItem(hMain, IDE_SCPARM2), SW_SHOW);
    }
    else if ((c2rw_dsc[c2rw_set.tp].tp == SCD_PL2S1) || (c2rw_dsc[c2rw_set.tp].tp == SCD_PL4S1))
    {
        // parameter 0 (unused for PL)
        ShowWindow(GetDlgItem(hMain, IDT_SCPARM0), SW_HIDE);
        ShowWindow(GetDlgItem(hMain, IDE_SCPARM0), SW_HIDE);
        // parameter 1 (SAK for PL)
        SetDlgItemText(hMain, IDT_SCPARM1, TEXT("SAK"));
        ShowWindow(GetDlgItem(hMain, IDT_SCPARM1), SW_SHOW);
        ShowWindow(GetDlgItem(hMain, IDE_SCPARM1), SW_SHOW);
        // parameter 2 (ATQA for PL)
        SetDlgItemText(hMain, IDT_SCPARM2, TEXT("ATQA"));
        ShowWindow(GetDlgItem(hMain, IDT_SCPARM2), SW_SHOW);
        ShowWindow(GetDlgItem(hMain, IDE_SCPARM2), SW_SHOW);
    }
    else
    {
        // parameter 0 (BCC for CL)
        SetDlgItemText(hMain, IDT_SCPARM0, TEXT("BCC"));
        ShowWindow(GetDlgItem(hMain, IDT_SCPARM0), SW_SHOW);
        ShowWindow(GetDlgItem(hMain, IDE_SCPARM0), SW_SHOW);
        // parameter 1 (SAK for CL)
        SetDlgItemText(hMain, IDT_SCPARM1, TEXT("SAK"));
        ShowWindow(GetDlgItem(hMain, IDT_SCPARM1), SW_SHOW);
        ShowWindow(GetDlgItem(hMain, IDE_SCPARM1), SW_SHOW);
        // parameter 2 (ATQA for CL)
        SetDlgItemText(hMain, IDT_SCPARM2, TEXT("ATQA"));
        ShowWindow(GetDlgItem(hMain, IDT_SCPARM2), SW_SHOW);
        ShowWindow(GetDlgItem(hMain, IDE_SCPARM2), SW_SHOW);
    }
    // quad sector selector ei/di
    ShowWindow(GetDlgItem(hMain, IDT_SCSSEL), (clf) ? SW_SHOW : SW_HIDE);
    EnableWindow(GetDlgItem(hMain, IDC_SCSSEL), eidi);
    ShowWindow(GetDlgItem(hMain, IDC_SCSSEL), (clf) ? SW_SHOW : SW_HIDE);
    // change data frame caption
    LoadString(hInst, ((clf) ? STR_CDGBLK : STR_CDGPGS), szLocal, sizeof(szLocal) / sizeof(TCHAR));
    SetDlgItemText(hMain, IDC_SCBGRP, szLocal);
    // * CL/PL controls by card type selector *
    tmpf = get_rsstate(c2rw_set.qs << 2);   // full activity for real sector
    // auth group
    for (cnt = 0; cnt != 6; cnt++)
    {
        EnableWindow(GetDlgItem(hMain, cnt + IDT_SCKEYA), eidi && tmpf);
        ShowWindow(GetDlgItem(hMain, cnt + IDT_SCKEYA), (clf) ? SW_SHOW : SW_HIDE);
    }
    // read/write sector button
    EnableWindow(GetDlgItem(hMain, IDC_SCRDSEC), eidi && (tmpf || (c2rw_set.flg & MASK_ALLDATA)));  // RD sector
    ShowWindow(GetDlgItem(hMain, IDC_SCRDSEC), (clf) ? SW_SHOW : SW_HIDE);
    EnableWindow(GetDlgItem(hMain, IDC_SCWRSEC), eidi && tmpf);     // WR sector
    ShowWindow(GetDlgItem(hMain, IDC_SCWRSEC), (clf) ? SW_SHOW : SW_HIDE);
    // data group
    for (cnt = 0; cnt != 4; cnt++)      // data 0..2 group
    {
        tmpf = blkstate((c2rw_set.qs << 2) + (BYTE)cnt);    // get block activity
        // text
        EnableWindow(GetDlgItem(hMain, cnt + IDT_DATA0), eidi && tmpf);
        ShowWindow(GetDlgItem(hMain, cnt + IDT_DATA0), (clf) ? SW_SHOW : SW_HIDE);
        // enable button
        EnableWindow(GetDlgItem(hMain, cnt + IDX_DATA0), eidi);
        ShowWindow(GetDlgItem(hMain, cnt + IDX_DATA0), (clf) ? SW_SHOW : SW_HIDE);
        // row 3
        if (cnt == 3)
        {
            BOOL    trf = istrailer((c2rw_set.qs << 2) | 3);
            // CL/PL data output
            EnableWindow(GetDlgItem(hMain, IDT_DATA3), eidi && tmpf);       // data 3 text
            ShowWindow(GetDlgItem(hMain, IDT_DATA3), (clf) ? SW_SHOW : SW_HIDE);
            EnableWindow(GetDlgItem(hMain, IDE_DATA3), eidi && tmpf);       // data 3 edit
            ShowWindow(GetDlgItem(hMain, IDE_DATA3), (clf && (!trf)) ? SW_SHOW : SW_HIDE);
            EnableWindow(GetDlgItem(hMain, IDX_DATA3), eidi);               // data 3 enable button
            ShowWindow(GetDlgItem(hMain, IDX_DATA3), (clf) ? SW_SHOW : SW_HIDE);
            // CL/PL trailer output
            EnableWindow(GetDlgItem(hMain, IDE_DATA3A), eidi && tmpf);      // A-key data
            ShowWindow(GetDlgItem(hMain, IDE_DATA3A), (clf && trf) ? SW_SHOW : SW_HIDE);
            EnableWindow(GetDlgItem(hMain, IDE_DATA3M), eidi && tmpf);      // key mode data
            ShowWindow(GetDlgItem(hMain, IDE_DATA3M), (clf && trf) ? SW_SHOW : SW_HIDE);
            EnableWindow(GetDlgItem(hMain, IDE_DATA3B), eidi && tmpf);      // B-key data
            ShowWindow(GetDlgItem(hMain, IDE_DATA3B), (clf && trf) ? SW_SHOW : SW_HIDE);
        }
        else
        {
            // edit
            EnableWindow(GetDlgItem(hMain, cnt + IDE_DATA0), eidi && tmpf);
            ShowWindow(GetDlgItem(hMain, cnt + IDE_DATA0), (clf) ? SW_SHOW : SW_HIDE);
        }
    }
    // * UL controls by card type selector *
    // text
    EnableWindow(GetDlgItem(hMain, IDT_PGR0), eidi && (c2rw_set.ul_en & 0x000F));
    ShowWindow(GetDlgItem(hMain, IDT_PGR0), (!clf) ? SW_SHOW : SW_HIDE);
    EnableWindow(GetDlgItem(hMain, IDT_PGR1), eidi && (c2rw_set.ul_en & 0x00F0));
    ShowWindow(GetDlgItem(hMain, IDT_PGR1), (!clf) ? SW_SHOW : SW_HIDE);
    EnableWindow(GetDlgItem(hMain, IDT_PGR2), eidi && (c2rw_set.ul_en & 0x0F00));
    ShowWindow(GetDlgItem(hMain, IDT_PGR2), (!clf) ? SW_SHOW : SW_HIDE);
    EnableWindow(GetDlgItem(hMain, IDT_PGR3), eidi && (c2rw_set.ul_en & 0xF000));
    ShowWindow(GetDlgItem(hMain, IDT_PGR3), (!clf) ? SW_SHOW : SW_HIDE);
    // data
    for (cnt = 0; cnt != 16; cnt++)
    {
        tmpf = get_pgstate((BYTE)cnt);  // get page activity
        // edit
        EnableWindow(GetDlgItem(hMain, cnt + IDE_PG00), eidi && tmpf);
        ShowWindow(GetDlgItem(hMain, cnt + IDE_PG00), (!clf) ? SW_SHOW : SW_HIDE);
        // enable button
        EnableWindow(GetDlgItem(hMain, cnt + IDX_PG00), eidi);
        ShowWindow(GetDlgItem(hMain, cnt + IDX_PG00), (!clf) ? SW_SHOW : SW_HIDE);
    }
}

// fix bcc for UID
void gui_uidfix(void)
{
    DWORD       tmp;
    if (((tmp = SendMessage(GetDlgItem(hMain, IDC_SCTPSEL), CB_GETCURSEL, 0, 0)) != CB_ERR) &&
        (tmp <= MAX_CCTYPE))
    {
        if (c2rw_dsc[tmp].tp == SCD_UL)
        {
            c2rw_set.mfd_ul[3] = c2rw_set.mfd_ul[0] ^ c2rw_set.mfd_ul[1] ^ c2rw_set.mfd_ul[2] ^ 0x88;
            c2rw_set.mfd_ul[8] = c2rw_set.mfd_ul[4] ^ c2rw_set.mfd_ul[5] ^ c2rw_set.mfd_ul[6] ^ c2rw_set.mfd_ul[7];
            gui_setdata();
        }
        else if (c2rw_dsc[tmp].tp == SCD_CL1K)
        {
            c2rw_set.mfd_cl[4] = c2rw_set.mfd_cl[0] ^ c2rw_set.mfd_cl[1] ^ c2rw_set.mfd_cl[2] ^ c2rw_set.mfd_cl[3];
            c2rw_set.mfd_cl[5] = 0x08;  // SAK
            c2rw_set.mfd_cl[6] = 0x04;  // ATQA_Lo
            c2rw_set.mfd_cl[7] = 0x00;  // ATQA_Hi
            gui_setdata();
        }
        else if (c2rw_dsc[tmp].tp == SCD_CL4K)
        {
            c2rw_set.mfd_cl[4] = c2rw_set.mfd_cl[0] ^ c2rw_set.mfd_cl[1] ^ c2rw_set.mfd_cl[2] ^ c2rw_set.mfd_cl[3];
            c2rw_set.mfd_cl[5] = 0x18;  // SAK
            c2rw_set.mfd_cl[6] = 0x02;  // ATQA_Lo
            c2rw_set.mfd_cl[7] = 0x00;  // ATQA_Hi
            gui_setdata();
        }
        else if (c2rw_dsc[tmp].tp == SCD_PL2S1)
        {
            c2rw_set.mfd_cl[7] = 0x08;  // SAK
            c2rw_set.mfd_cl[8] = 0x44;  // ATQA_Lo
            c2rw_set.mfd_cl[9] = 0x00;  // ATQA_Hi
            gui_setdata();
        }
        else if (c2rw_dsc[tmp].tp == SCD_PL4S1)
        {
            c2rw_set.mfd_cl[7] = 0x18;  // SAK
            c2rw_set.mfd_cl[8] = 0x42;  // ATQA_Lo
            c2rw_set.mfd_cl[9] = 0x00;  // ATQA_Hi
            gui_setdata();
        }
    }
}

// resource initialization
void initrc(void)
{
    TCHAR               szLocal[128];
    DWORD               cnt;
    // main icon
    SendMessage(hMain, WM_SETICON, ICON_BIG, (LPARAM)LoadIcon(hInst, MAKEINTRESOURCE(IDI_APPICON)));
    // menu icons
    gui_setmenuicon(IDB_MNBIN, CM_BINLD);   // set menu binary icon
    gui_setmenuicon(IDB_MNASC, CM_ASCLD);   // set menu ascii icon
    gui_setmenuicon(IDB_MNCFG, CM_CFGLD);   // set menu ascii cfg
    gui_setmenuicon(IDB_MNPWR, CM_EXIT);    // set menu "power" icon
    // type selector init
    SendMessage(GetDlgItem(hMain, IDC_SCTPSEL), CB_RESETCONTENT, 0, 0);
    for (cnt = 0; cnt < sizeof(c2rw_dsc) / sizeof(c2rw_dsc[0]); cnt++)
    {
        wsprintf(szLocal, TEXT(" %s"), c2rw_dsc[cnt].txt);
        SendMessage(GetDlgItem(hMain, IDC_SCTPSEL), CB_INSERTSTRING, cnt, (LPARAM)szLocal);
    }
    // sector selector initialize
    gui_setqs();
    // *** CL/PL ***
    SendMessage(GetDlgItem(hMain, IDE_SCKEYA), EM_LIMITTEXT, 12, 0);    // auth A limit set
    SendMessage(GetDlgItem(hMain, IDE_SCKEYB), EM_LIMITTEXT, 12, 0);    // auth B limit set
    for (cnt = 0; cnt != 4; cnt++)
        SendMessage(GetDlgItem(hMain, IDE_DATA0 + cnt), EM_LIMITTEXT, 32, 0);   // limit to data row
    // *** UL ***
    for (cnt = 0; cnt != 16; cnt++)
        SendMessage(GetDlgItem(hMain, IDE_PG00 + cnt), EM_LIMITTEXT, 8, 0);     // limit to pages for UL
    // set data to gui
    gui_settp();
    // enable controls
    gui_disen(TRUE);
    // set main caption
    LoadString(hInst, STR_CMAIN, szLocal, sizeof(szLocal) / sizeof(TCHAR));
    lstrcat(szLocal, RDRAPI_VER);
    SetWindowText(hMain, szLocal);
    // set start status message
    if ((cport) && (cbr)) wsprintf(szLocal, TEXT("\1COM%u, %ubps. "), cport, cbr);
    else lstrcpy(szLocal, TEXT("\1USB. "));
    LoadString(hInst, STR_ASTRTM, &szLocal[lstrlen(szLocal)], sizeof(szLocal) / sizeof(TCHAR) - lstrlen(szLocal));
    gui_stbar(szLocal);
}
