Top secrets sources NedoPC pentevo

Rev

Blame | Last modification | View Log | Download | RSS feed | ?url?

#include "std.h"

#include "resource.h"
#include "emul.h"
#include "vars.h"
#include "snapshot.h"
#include "tape.h"
#include "memory.h"
#include "opendlg.h"
#include "draw.h"
#include "config.h"
#include "z80.h"
#include "sshot_png.h"
#include "funcs.h"

#include "util.h"



#include <io.h> // äëÿ access [NS]

int readSP();
int readSNA48();
int readSNA128();
int readZ80();
int writeSNA(FILE*);

int load_arc(char *fname);

//=============================================================================
SNAP what_is(char *filename)
{
   FILE *ff = fopen(filename, "rb");
   if (!ff) return snNOFILE;
   snapsize = unsigned(fread(snbuf, 1, sizeof snbuf, ff));
   fclose(ff);
   if (snapsize == sizeof snbuf) return snTOOLARGE;
   SNAP type = snUNKNOWN;
   char *ptr = strrchr(filename, '.');
   unsigned ext = ptr? (*(unsigned*)(ptr+1) | 0x20202020U) : 0;
   if (snapsize < 32) return type;

   if (snapsize == 131103 || snapsize == 147487) type = snSNA_128;
   if (snapsize == 49179) type = snSNA_48;
   if (ext == WORD4('t','a','p',' ')) type = snTAP;
   if (ext == WORD4('z','8','0',' ')) type = snZ80;
   if(ext == WORD4('p', 'a', 'l', ' ') && (snapsize == sizeof(comp.comp_pal)))
   {
       type = snPAL;
       return type;
   }
   if (conf.trdos_present)
   {
      if (!snbuf[13] && snbuf[14] && (int)snapsize == snbuf[14]*256+17) type = snHOB;
      if (snapsize >= 8192 && !(snapsize & 0xFF) && ext == WORD4('t','r','d',' ')) type = snTRD;

      if (snapsize >= 8192 && ext == WORD4('i','s','d',' '))
          type = snISD;

      if (snapsize >= 8192 && ext == WORD4('p','r','o',' '))
          type = snPRO;

      if(snapsize >= 8192 && ext == WORD4('d', 's', 'k', ' '))
          type = snDSK;

      if(snapsize >= 8192 && ext == WORD4('i', 'p', 'f', ' '))
          type = snIPF;

      if (!memcmp(snbuf, "SINCLAIR", 8))
      {
          unsigned nfiles = snbuf[8];
          unsigned nsec = 0;
          for(unsigned i = 0; i < nfiles; i++)
          {
              nsec += snbuf[9+14*i+13];
          }
         
          if(snapsize >= 9 + nfiles * 14 + nsec * 0x100)
              type = snSCL;
      }
      if (!memcmp(snbuf, "FDI", 3) && *(unsigned short*)(snbuf+4) <= MAX_CYLS && *(unsigned short*)(snbuf+6) <= 2) type = snFDI;
      if (((*(short*)snbuf|0x2020) == WORD2('t','d')) && snbuf[4] >= 10 && snbuf[4] <= 21 && snbuf[9] <= 2) type = snTD0;
      if (*(unsigned*)snbuf == WORD4('U','D','I','!') && *(unsigned*)(snbuf+4)==snapsize-4 && snbuf[9] < MAX_CYLS && snbuf[10]<2 && !snbuf[8]) type = snUDI;
   }
   if (snapsize > 10 && !memcmp(snbuf, "ZXTape!\x1A", 8))
   {
       type = snTZX;
   }
   if (snapsize > 0x22 && !memcmp(snbuf, "Compressed Square Wave\x1A", 23)) type = snCSW;
   if (*(unsigned short*)snbuf == WORD2('S','P') && *(unsigned short*)(snbuf+2)+0x26 == (int)snapsize) type = snSP;
   return type;
}
//=============================================================================

static int readPAL();

//=============================================================================
int loadsnap(char *filename)
{
    //-------------------------------------------------------------------------
    if (load_arc(filename))
        return 1;
    //-------------------------------------------------------------------------
    SNAP type = what_is(filename);
    //-------------------------------------------------------------------------
    if (type >= snHOB)
    {
        if (trd_toload == -1U)
        {
            unsigned last = -1U;
            for (unsigned i = 0; i < 4; i++)
                if (trd_loaded[i]) last = i;
            trd_toload = (last == -1U)    ?     0 :
                                                (
                                                    (type == snHOB)  ?  last :
                                                                        (last+1) & 3
                                                );
        }
        //---------------------------------------------------------------------
        for (unsigned k = 0; k < 4; k++)
        {
            if ((k != trd_toload) && (!stricmp(comp.fdd[k].name, filename)))
            {
                // ìåðçñêàÿ ìåðçîñòü !!!
                static char err[] =     "This disk image is already loaded to drive X:\n"
                                        "Do you still want to load it to drive Y:?";
                err[43] = char(k+'A');
                err[84] = char(trd_toload+'A');
                if (MessageBox(GetForegroundWindow(), err, "Warning", MB_YESNO | MB_ICONWARNING) == IDNO)
                    return 1;
            }
        }
        //---------------------------------------------------------------------
        FDD *drive = comp.fdd + trd_toload;
        //---------------------------------------------------------------------
        if (!drive->test())
            return 0;
        //---------------------------------------------------------------------
        comp.wd.Eject(trd_toload);
        int ok = drive->read(type);
        //---------------------------------------------------------------------
        if (ok)
        {
            //-----------------------------------------------------------------
            if (*conf.appendboot)
                drive->addboot();
            //-----------------------------------------------------------------
            strcpy(drive->name, filename);
            //-----------------------------------------------------------------
            if (GetFileAttributes(filename) & FILE_ATTRIBUTE_READONLY)
                conf.trdos_wp[trd_toload] = 1;
            //-----------------------------------------------------------------
            drive->snaptype = (type == snHOB || type == snSCL)    ?     snTRD :
                                                                        type;
            trd_loaded[trd_toload] = 1;
           
            //---------Alone Coder
            char *name = filename;
           
            for (char *x = name; *x; x++)
                if (*x == '\\')
                    name = x + 1;
             
            strcpy(temp.LastSnapName, name);
            char *p = strrchr(temp.LastSnapName, '.');
            if (p)
            {
                *p = 0;
            }
            //printf("loaded file name printing\n");
            char wintitle[0x200];
            strcpy(wintitle,name);
            //strcat(wintitle," - UnrealSpeccy");
            strcat(wintitle," - Unreal_NS");    //äëÿ çàãðóæàåìîãî äèñêîâ
            SetWindowText(wnd, wintitle);
            //~---------Alone Coder
        }
        //---------------------------------------------------------------------
        return ok;
    }
    //-------------------------------------------------------------------------
    if (type == snSP)           return readSP();
    if (type == snSNA_48)       return readSNA48();
    if (type == snSNA_128)      return readSNA128();
    if (type == snZ80)          return readZ80();
    if (type == snTAP)          return readTAP();
    if (type == snTZX)          return readTZX();
    if (type == snCSW)          return readCSW();
    if (type == snPAL)          return readPAL();
    //-------------------------------------------------------------------------
    return 0;
}
//=============================================================================


//=============================================================================
int readSNA128()
{
    //-------------------------------------------------------------------------
    if ((conf.mem_model == MM_PENTAGON) && (conf.Sna128Lock))
    {
       conf.ramsize = 128;
       temp.ram_mask = u8((conf.ramsize-1) >> 4);
    }
    //-------------------------------------------------------------------------
    hdrSNA128 *hdr = (hdrSNA128*)snbuf;
    reset(hdr->trdos ?  RM_DOS :
                        RM_SOS);
    cpu.alt.af = hdr->altaf;
    cpu.alt.bc = hdr->altbc;
    cpu.alt.de = hdr->altde;
    cpu.alt.hl = hdr->althl;
    cpu.af = hdr->af;
    cpu.bc = hdr->bc;
    cpu.de = hdr->de;
    cpu.hl = hdr->hl;
    cpu.ix = hdr->ix;
    cpu.iy = hdr->iy;
    cpu.sp = hdr->sp;
    cpu.pc = hdr->pc;
    cpu.i = hdr->i;
    cpu.r_low = hdr->r;
    cpu.r_hi = hdr->r & 0x80;
    cpu.im = hdr->im;
    cpu.iff1 = cpu.iff2 = (hdr->iff >> 2) & 1;
    comp.p7FFD = hdr->p7FFD;
    comp.pFE = hdr->pFE;
    comp.border_attr = comp.pFE & 7;
    memcpy(memory + PAGE * 5,                   hdr->page5,             PAGE);
    memcpy(memory + PAGE * 2,                   hdr->page2,             PAGE);
    memcpy(memory + PAGE * (hdr->p7FFD & 7),    hdr->active_page,       PAGE);
    unsigned char *newpage = snbuf + 0xC01F;
    unsigned char mapped = u8(0x24U | (1 << (hdr->p7FFD & 7)));
    //-------------------------------------------------------------------------
    for (unsigned char i = 0; i < 8; i++)
    {
        if (!(mapped & (1 << i)))
        {
            memcpy(memory + PAGE*i, newpage, PAGE);
            newpage += PAGE;
        }
    }
    //-------------------------------------------------------------------------
    set_banks();
    return 1;
}
//=============================================================================


//=============================================================================
int readSNA48()
{
    //conf.mem_model = MM_PENTAGON; conf.ramsize = 128;  // molodcov_alex
    reset(RM_SOS);
    hdrSNA128 *hdr = (hdrSNA128*)snbuf;
    cpu.alt.af = hdr->altaf;
    cpu.alt.bc = hdr->altbc;
    cpu.alt.de = hdr->altde;
    cpu.alt.hl = hdr->althl;
    cpu.af = hdr->af;
    cpu.bc = hdr->bc;
    cpu.de = hdr->de;
    cpu.hl = hdr->hl;
    cpu.ix = hdr->ix;
    cpu.iy = hdr->iy;
    cpu.sp = hdr->sp;
    cpu.i = hdr->i;
    cpu.r_low = hdr->r;
    cpu.r_hi = hdr->r & 0x80;
    cpu.im = hdr->im;
    cpu.iff1 = cpu.iff2 = (hdr->iff >> 2) & 1;
    comp.p7FFD = 0x30;
    comp.pEFF7 |= EFF7_LOCKMEM; //Alone Coder
    comp.pFE = hdr->pFE;
    comp.border_attr = comp.pFE & 7;
    memcpy(memory + PAGE * 5, hdr->page5,       PAGE);
    memcpy(memory + PAGE * 2, hdr->page2,       PAGE);
    memcpy(memory + PAGE * 0, hdr->active_page, PAGE);
    cpu.pc = cpu.DirectRm(cpu.sp) + 0x100 * cpu.DirectRm(cpu.sp + 1);
    cpu.sp += 2;
    set_banks();
    return 1;
}
//=============================================================================


//=============================================================================
int readSP()
{
    //conf.mem_model = MM_PENTAGON; conf.ramsize = 128;  // molodcov_alex
    reset(RM_SOS);
    hdrSP *hdr = (hdrSP*)snbuf;
    cpu.alt.af = hdr->altaf;
    cpu.alt.bc = hdr->altbc;
    cpu.alt.de = hdr->altde;
    cpu.alt.hl = hdr->althl;
    cpu.af = hdr->af;
    cpu.bc = hdr->bc;
    cpu.de = hdr->de;
    cpu.hl = hdr->hl;
    cpu.ix = hdr->ix;
    cpu.iy = hdr->iy;
    cpu.sp = hdr->sp;
    cpu.pc = hdr->pc;
    cpu.i = hdr->i;
    cpu.r_low = hdr->r;
    cpu.r_hi = hdr->r & 0x80;
    cpu.iff1 = (hdr->flags & 1);
    cpu.im = 1 + ((hdr->flags >> 1) & 1);
    cpu.iff2 = (hdr->flags >> 2) & 1;
    comp.p7FFD = 0x30;
    comp.pEFF7 |= EFF7_LOCKMEM; //Alone Coder
    comp.pFE = hdr->pFE;
    comp.border_attr = comp.pFE & 7;
    for (unsigned i = 0; i < hdr->len; i++)
        cpu.DirectWm(hdr->start + i, snbuf[i + 0x26]);
    set_banks();
    return 1;
}
//=============================================================================


//=============================================================================
int writeSNA(FILE *ff)
{
/*  if (conf.ramsize != 128)
    {
        MessageBox(GetForegroundWindow(), "SNA format can hold only\r\n128kb memory models", "Save", MB_ICONERROR);
        return 0;
    }*/
//Alone Coder
    hdrSNA128 *hdr = (hdrSNA128*)snbuf;
    hdr->trdos = (comp.flags & CF_TRDOS)   ?    1 :
                                                0;
    hdr->altaf = u16(cpu.alt.af);
    hdr->altbc = u16(cpu.alt.bc);
    hdr->altde = u16(cpu.alt.de);
    hdr->althl = u16(cpu.alt.hl);
    hdr->af = u16(cpu.af);
    hdr->bc = u16(cpu.bc);
    hdr->de = u16(cpu.de);
    hdr->hl = u16(cpu.hl);
    hdr->ix = u16(cpu.ix);
    hdr->iy = u16(cpu.iy);
    hdr->sp = u16(cpu.sp);
    hdr->pc = u16(cpu.pc);
    hdr->i = cpu.i;
    hdr->r = (cpu.r_low & 0x7F)+cpu.r_hi;
    hdr->im = cpu.im;
    hdr->iff = cpu.iff2    ?    4 :
                                0;
    hdr->p7FFD = comp.p7FFD;
    hdr->pFE = comp.pFE;
    comp.border_attr = comp.pFE & 7;
    unsigned savesize = sizeof(hdrSNA128);
    unsigned char mapped = u8(0x24U | (1 << (comp.p7FFD & 7)));
    //-------------------------------------------------------------------------
    if (comp.p7FFD == 0x30)     //íî äëÿ ïåíòàãîíà ýòî íå çíà÷åò 48 lock !!!
    { // save 48k
        mapped = 0xFF;
        savesize = 0xC01B;
        hdr->sp -= 2;
        cpu.DirectWm(hdr->sp, cpu.pcl);
        cpu.DirectWm(hdr->sp+1, cpu.pch);
    }
    //-------------------------------------------------------------------------
    memcpy(hdr->page5,          memory+PAGE*5,                  PAGE);
    memcpy(hdr->page2,          memory+PAGE*2,                  PAGE);
    memcpy(hdr->active_page,    memory+PAGE*(comp.p7FFD & 7),   PAGE);
    //-------------------------------------------------------------------------
    if (fwrite(hdr, 1, savesize, ff) != savesize)
        return 0;
    //-------------------------------------------------------------------------
    for (unsigned char i = 0; i < 8; i++)
    {
        if (!(mapped & (1 << i)))
        {
            if (fwrite(memory + PAGE*i, 1, PAGE, ff) != PAGE)
                return 0;
        }
    }
    //-------------------------------------------------------------------------
    return 1;
}
//=============================================================================


//=============================================================================
static void unpack_page(unsigned char *dst, unsigned dstlen, unsigned char *src, unsigned srclen)
{
    memset(dst, 0, dstlen);
    while (srclen > 0 && dstlen > 0)
    {
        if (srclen >= 4 && src[0] == 0xED && src[1] == 0xED)
        {
            size_t len = src[2];
            memset(dst, src[3], len);
            dstlen -= len;
            srclen -= 4;
            src += 4;
            dst += len;
        }
        else
        {
            *dst++ = *src++;
            dstlen--;
            srclen--;
        }
    }
}
//=============================================================================


//=============================================================================
int readZ80()
{
    //conf.mem_model = MM_PENTAGON; conf.ramsize = 128;  // molodcov_alex
    hdrZ80 *hdr = (hdrZ80*)snbuf;
    unsigned char *ptr = snbuf + 30;
    unsigned char model48k = (hdr->model < 3);
    //-------------------------------------------------------------------------
    reset((model48k|(hdr->p7FFD & 0x10))   ?    RM_SOS :
                                                RM_128);
    //-------------------------------------------------------------------------
    if (hdr->flags == 0xFF)
        hdr->flags = 1;
    //-------------------------------------------------------------------------
    if (hdr->pc == 0)
    { // 2.01
        ptr += 2 + hdr->len;
        hdr->pc = hdr->newpc;
        memset(RAM_BASE_M, 0, PAGE*8); // clear 128k - first 8 pages

        unsigned char * const p48[] =
        {
            base_sos_rom,               nullptr,                nullptr,        nullptr,
            RAM_BASE_M + 2 * PAGE,      RAM_BASE_M + 0 * PAGE,  nullptr,        nullptr,
            RAM_BASE_M + 5 * PAGE,      nullptr,                nullptr,        nullptr
        };
        unsigned char * const p128[] =
        {
            base_sos_rom,               base_dos_rom,           base_128_rom,           RAM_BASE_M + 0 * PAGE,
            RAM_BASE_M + 1 * PAGE,      RAM_BASE_M + 2 * PAGE,  RAM_BASE_M + 3 * PAGE,  RAM_BASE_M + 4 * PAGE,
            RAM_BASE_M + 5 * PAGE,      RAM_BASE_M + 6 * PAGE,  RAM_BASE_M + 7 * PAGE,  nullptr
        };

        //---------------------------------------------------------------------
        while (ptr < snbuf+snapsize)
        {
            unsigned len = *(unsigned short*)ptr;
            //-----------------------------------------------------------------
            if (ptr[2] > 11)
                return 0;
            //-----------------------------------------------------------------
            unsigned char *dstpage = model48k ? p48[ptr[2]] :
                                                p128[ptr[2]];
            //-----------------------------------------------------------------
            if (!dstpage)
                return 0;
            //-----------------------------------------------------------------
            ptr += 3;
            //-----------------------------------------------------------------
            if (len == 0xFFFF)
            {
                len = PAGE;
                memcpy(dstpage, ptr, len);
            }
            else
            {
                unpack_page(dstpage, PAGE, ptr, len);
            }
            //-----------------------------------------------------------------
            ptr += len;
            //-----------------------------------------------------------------
        }
        //---------------------------------------------------------------------
    }
    else
    {
        unsigned len = snapsize - 30;
        unsigned char *mem48 = ptr;
        //---------------------------------------------------------------------
        if (hdr->flags & 0x20)
            unpack_page(mem48 = snbuf + 4*PAGE, 3*PAGE, ptr, len);
        //---------------------------------------------------------------------
        memcpy(memory + (PAGE * 5), mem48,              PAGE);
        memcpy(memory + (PAGE * 2), mem48 + PAGE,       PAGE);
        memcpy(memory + (PAGE * 0), mem48 + (2 * PAGE), PAGE);
        model48k = 1;
    }
    //-------------------------------------------------------------------------
    cpu.a = hdr->a;
    cpu.f = hdr->f;
    cpu.bc = hdr->bc;
    cpu.de = hdr->de; cpu.hl = hdr->hl;
    cpu.alt.bc = hdr->bc1;
    cpu.alt.de = hdr->de1;
    cpu.alt.hl = hdr->hl1;
    cpu.alt.a = hdr->a1;
    cpu.alt.f = hdr->f1;
    cpu.pc = hdr->pc;
    cpu.sp = hdr->sp;
    cpu.ix = hdr->ix;
    cpu.iy = hdr->iy;
    cpu.i = hdr->i;
    cpu.r_low = hdr->r & 0x7F;
    cpu.r_hi = u8((hdr->flags & 1U) << 7U);
    comp.pFE = (hdr->flags >> 1) & 7;
    comp.border_attr = comp.pFE;
    cpu.iff1 = hdr->iff1;
    cpu.iff2 = hdr->iff2;
    cpu.im = (hdr->im & 3);
    comp.p7FFD = (model48k)  ?  0x30 :
                                hdr->p7FFD;
    //-------------------------------------------------------------------------
    if (hdr->len == 55)                 // version 3.0 (with 1ffd)
        comp.p1FFD = hdr->p1FFD;
    //-------------------------------------------------------------------------
    if (model48k)
        comp.pEFF7 |= EFF7_LOCKMEM;     //Alone Coder
    //-------------------------------------------------------------------------
    set_banks();
    //-------------------------------------------------------------------------
    return 1;
}
//=============================================================================


//=============================================================================
static int readPAL()
{
    memcpy(comp.comp_pal, snbuf, snapsize);
    temp.comp_pal_changed = 1;
    if (conf.ula_plus)
    {
        // Åñëè ïðèñóòñòâóåò ULA+, òî ñðàçó è àêòèâèðóåì åå (÷òîáû èçìåíåíèÿ ïàëèòðû áûëè âèäíû)
        comp.ula_plus_en = true;
    }
    return 1;
}
//=============================================================================


//=============================================================================
static int writePAL(FILE *ff)
{
    if ( fwrite(        comp.comp_pal,
                        1,
                        sizeof(comp.comp_pal),
                        ff
                )
                != sizeof(comp.comp_pal)
      )
    {
        return 0;
    }
    return 1;
}
//=============================================================================

#define arctmp ((char*)rbuf)
static char *arc_fname;

//=============================================================================
static INT_PTR CALLBACK ArcDlg(HWND dlg, UINT msg, WPARAM wp, LPARAM lp)
{
    (void)lp;

    //-------------------------------------------------------------------------
    if (msg == WM_INITDIALOG)
    {
        for (char *dst = arctmp; *dst; dst += strlen(dst)+1)
            SendDlgItemMessage(dlg, IDC_ARCLIST, LB_ADDSTRING, 0, (LPARAM)dst);
           
        SendDlgItemMessage(dlg, IDC_ARCLIST, LB_SETCURSEL, 0, 0);
        return 1;
    }
    //-------------------------------------------------------------------------
    if (        ((msg == WM_COMMAND) && (wp == IDCANCEL))
                ||
                ((msg == WM_SYSCOMMAND) && ((wp & 0xFFF0) == SC_CLOSE))
      )
    {
        EndDialog(dlg, 0);
    }
    //-------------------------------------------------------------------------
    if (        (msg == WM_COMMAND)
                &&
                (       (LOWORD(wp) == IDOK)
                        ||
                        ((HIWORD(wp) == LBN_DBLCLK) && (LOWORD(wp) == IDC_ARCLIST))
                )
      )
    {
        int n = int(SendDlgItemMessage(dlg, IDC_ARCLIST, LB_GETCURSEL, 0, 0));
        char *dst = arctmp;
        for (int q = 0; q < n; q++)
            dst += strlen(dst) + 1;
        arc_fname = dst;
        EndDialog(dlg, 0);
    }
    return 0;
}
//=============================================================================


//=============================================================================
static bool filename_ok(char *fname)
{
    for (char *wc = skiparc; *wc; wc += strlen(wc) + 1)
        if (wcmatch(fname, wc))
            return 0;
    return 1;
}
//=============================================================================


//=============================================================================
int load_arc(char *fname)
{
    char *ext = strrchr(fname, '.');
    //-------------------------------------------------------------------------
    if (!ext)
        return 0;
    //-------------------------------------------------------------------------
    ext++;
    char *cmdtmp;
    char done = 0;
    //-------------------------------------------------------------------------
    for (char *x = arcbuffer; *x; x = cmdtmp + strlen(cmdtmp)+1)
    {
        cmdtmp = x + strlen(x) + 1;
        //---------------------------------------------------------------------
        if (stricmp(ext, x))
            continue;
        //---------------------------------------------------------------------
        char dir[0x200];
        GetCurrentDirectory(sizeof dir, dir);
        char tmp[0x200];
        GetTempPath(sizeof tmp, tmp);
        char d1[0x20];
        sprintf(d1, "us%08lX", GetTickCount());
        SetCurrentDirectory(tmp);
        CreateDirectory(d1, nullptr);
        SetCurrentDirectory(d1);
        //---------------------------------------------------------------------
        color();
        char cmdln[0x200]; sprintf(cmdln, cmdtmp, fname);
        STARTUPINFO si = { sizeof si };
        si.dwFlags = STARTF_USESHOWWINDOW; si.wShowWindow = SW_HIDE;
        PROCESS_INFORMATION pi;
        unsigned flags = CREATE_NEW_CONSOLE;
        HANDLE hc = CreateFile("CONOUT$", GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr);
        //---------------------------------------------------------------------
        if (hc != INVALID_HANDLE_VALUE)
        {
            CloseHandle(hc);
            flags = 0;
        }
        //---------------------------------------------------------------------
        if (CreateProcess(nullptr, cmdln, nullptr, nullptr, 0, flags, nullptr, nullptr, &si, &pi)) {
            WaitForSingleObject(pi.hProcess, INFINITE);
            DWORD code; GetExitCodeProcess(pi.hProcess, &code);
            CloseHandle(pi.hThread);
            CloseHandle(pi.hProcess);
            //-----------------------------------------------------------------
            if (!code || MessageBox(GetForegroundWindow(), "Broken archive", nullptr, MB_ICONERROR | MB_OKCANCEL) == IDOK)
            {
                WIN32_FIND_DATA fd;
                HANDLE h;
                char *dst = arctmp;
                unsigned nfiles = 0;
                //-------------------------------------------------------------
                if ((h = FindFirstFile("*.*", &fd)) != INVALID_HANDLE_VALUE)
                {
                    //---------------------------------------------------------
                    do
                    {
                        if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && filename_ok(fd.cFileName))
                        {
                            strcpy(dst, fd.cFileName);
                            dst += strlen(dst) + 1;
                            nfiles++;
                        }
                    }
                    while (FindNextFile(h, &fd));
                    //---------------------------------------------------------
                    FindClose(h);
                }
                //-------------------------------------------------------------
                *dst = 0;
                arc_fname = nullptr;
                //-------------------------------------------------------------
                if (nfiles == 1)
                    arc_fname = arctmp;
                //-------------------------------------------------------------
                if (nfiles > 1)
                    DialogBox(hIn, MAKEINTRESOURCE(IDD_ARC), GetForegroundWindow(), ArcDlg);
                //-------------------------------------------------------------
                if (!nfiles)
                    MessageBox(GetForegroundWindow(), "Empty archive!", nullptr, MB_ICONERROR | MB_OK);
                //-------------------------------------------------------------
                char buf[0x200]; strcpy(buf, tmp); strcat(buf, "\\");
                strcat(buf, d1);
                strcat(buf, "\\");
                //-------------------------------------------------------------
                if (arc_fname)
                {
                    strcat(buf, arc_fname);
                    arc_fname = buf;
                }
                //-------------------------------------------------------------
                if (arc_fname && !(done = (char)loadsnap(arc_fname)))
                    MessageBox(GetForegroundWindow(), "loading error", arc_fname, MB_ICONERROR);
                //-------------------------------------------------------------
                if (!done)
                    done = -1;
                //-------------------------------------------------------------
            }
            //-----------------------------------------------------------------
            // delete junk
            SetCurrentDirectory(tmp);
            SetCurrentDirectory(d1);
            WIN32_FIND_DATA fd;
            HANDLE h;
            //-----------------------------------------------------------------
            if ((h = FindFirstFile("*.*", &fd)) != INVALID_HANDLE_VALUE)
            {
                //-------------------------------------------------------------
                do
                {
                    DeleteFile(fd.cFileName);
                }
                while (FindNextFile(h, &fd));
                //-------------------------------------------------------------
                FindClose(h);
            }
        }
        SetCurrentDirectory(tmp);
        RemoveDirectory(d1);
        SetCurrentDirectory(dir);
        eat();
        //---------------------------------------------------------------------
        if (done)
            return done > 0  ?  1 :
                                0;
        //---------------------------------------------------------------------
    }
    eat();
    return 0;
}
//=============================================================================


//=============================================================================
void opensnap(unsigned index)
{
    char mask[0x200];
    *mask = 0;
    //-------------------------------------------------------------------------
    for (char *x = arcbuffer; *x; )
    {
        strcat(mask, ";*.");
        strcat(mask, x);
        x += strlen(x) + 1;
        x += strlen(x) + 1;
    }
    //-------------------------------------------------------------------------
    char fline[0x400];
    const char  *src =  "all (sna,z80,sp,tap,tzx,csw,trd,scl,fdi,td0,udi,isd,pro,dsk,ipf,hobeta,pal)\0"
                        "*.sna;*.z80;*.sp;*.tap;*.tzx;*.csw;*.trd;*.scl;*.td0;*.udi;*.fdi;*.isd;*.pro;*.dsk;*.ipf;*.$?;*.!?;*.pal<\0"
                        "Disk B (trd,scl,fdi,td0,udi,isd,pro,dsk,ipf,hobeta)\0*.trd;*.scl;*.fdi;*.udi;*.td0;*.isd;*.pro;*.dsk;*.ipf;*.$?<\0"
                        "Disk C (trd,scl,fdi,td0,udi,isd,pro,dsk,ipf,hobeta)\0*.trd;*.scl;*.fdi;*.udi;*.td0;*.isd;*.pro;*.dsk;*.ipf;*.$?<\0"
                        "Disk D (trd,scl,fdi,td0,udi,isd,pro,dsk,ipf,hobeta)\0*.trd;*.scl;*.fdi;*.udi;*.td0;*.isd;*.pro;*.dsk;*.ipf;*.$?<\0\0>";
    //-------------------------------------------------------------------------
    if (!conf.trdos_present)
                src =   "ZX files (sna,z80,tap,tzx,csw,pal)\0*.sna;*.z80;*.tap;*.tzx;*.csw;*.pal<\0\0>";
    //-------------------------------------------------------------------------
    for (char *dst = fline; *src != '>'; src++)
    {
        //---------------------------------------------------------------------
        if (*src == '<')
        {
            strcpy(dst, mask);
            dst += strlen(dst);
        }
        //---------------------------------------------------------------------
        else
        {
            *dst++ = *src;
        }
        //---------------------------------------------------------------------
    }
    //-------------------------------------------------------------------------
    OPENFILENAME ofn = { };
    char fname[0x200];
    *fname = 0;
    char dir[0x200];
    GetCurrentDirectory(sizeof dir, dir);

    ofn.lStructSize = (WinVerMajor < 5)    ?    OPENFILENAME_SIZE_VERSION_400 :
                                                sizeof(OPENFILENAME);
    ofn.hwndOwner = GetForegroundWindow();
    ofn.lpstrFilter = fline;
    ofn.lpstrFile = fname;
    ofn.nMaxFile = sizeof fname;
    ofn.lpstrTitle = "Load Snapshot / Disk / Tape";
    ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
    ofn.nFilterIndex = DWORD(index);
    ofn.lpstrInitialDir = dir;
//   __debugbreak();
    //-------------------------------------------------------------------------
    if (GetSnapshotFileName(&ofn, 0))
    {
        trd_toload = ofn.nFilterIndex - 1;
        if (!loadsnap(fname))
            MessageBox(GetForegroundWindow(), fname, "loading error", MB_ICONERROR);
    }
    //-------------------------------------------------------------------------
    eat();
}
//=============================================================================


//=============================================================================
static const int mx_typs = (1 + 4 * 6);
static unsigned char snaps[mx_typs];
static unsigned exts[mx_typs];
static unsigned drvs[mx_typs];
static unsigned snp;
//=============================================================================


//=============================================================================
static void addref(LPSTR &ptr, unsigned char sntype, const char *ref, unsigned drv, unsigned ext)
{
    strcpy(ptr, ref);
    ptr += strlen(ptr) + 1;
    strcpy(ptr, ref + strlen(ref) + 1);
    ptr += strlen(ptr) + 1;
    drvs[snp] = drv;
    exts[snp] = ext;
    snaps[snp++] = sntype;
}
//=============================================================================


//=============================================================================
void savesnap(int diskindex)
{
again:
    OPENFILENAME ofn = { };
    char fname[0x200];
    *fname = 0;
    //-------------------------------------------------------------------------
    if (diskindex >= 0)
    {
        strcpy(fname, comp.fdd[diskindex].name);
        size_t ln = strlen(fname);
        if (ln > 4 && (*(unsigned*)(fname+ln-4) | WORD4(0,0x20,0x20,0x20)) == WORD4('.','s','c','l'))
            *(unsigned*)(fname+ln-4) = WORD4('.','t','r','d');
    }
    //-------------------------------------------------------------------------
    snp = 1;
    char types[600], *ptr = types;
    //-------------------------------------------------------------------------
    if (diskindex < 0)
    {
        exts[snp] = WORD4('s','n','a',0);
        snaps[snp] = snSNA_128; // default
        addref(ptr, snSNA_128, "ZX-Spectrum 128K snapshot (SNA)\0*.sna", -1U, WORD4('s','n','a',0));

        exts[snp] = WORD4('p', 'a', 'l', 0);
        snaps[snp] = snPAL;
        addref(ptr, snPAL, "Palette (ULA+)\0*.pal", -1U, WORD4('p', 'a', 'l', 0));
    }
    //-------------------------------------------------------------------------
    ofn.lStructSize = (WinVerMajor < 5)    ?    OPENFILENAME_SIZE_VERSION_400 :
                                                sizeof(OPENFILENAME);
    ofn.nFilterIndex = 1;
    //-------------------------------------------------------------------------
    if (conf.trdos_present)
    {
        static char mask[] = "Disk A (TRD)\0*.trd";
        //---------------------------------------------------------------------
        static const char ex[][3] =
        {      
            {'T','R','D'},
            {'F','D','I'},
            {'T','D','0'},
            {'U','D','I'},
            {'I','S','D'},
            {'P','R','O'}
        };
        //---------------------------------------------------------------------
        static const unsigned ex2[] =
        {
            snTRD,
            snFDI,
            snTD0,
            snUDI,
            snISD,
            snPRO
        };
        //---------------------------------------------------------------------
        for (unsigned n = 0; n < 4; n++)
        {
            //-----------------------------------------------------------------
            if (!comp.fdd[n].rawdata)
                continue;
            //-----------------------------------------------------------------
            if (diskindex >= 0 && unsigned(diskindex) != n)
                continue;
            //-----------------------------------------------------------------
            mask[5] = char('A'+n);
            //-----------------------------------------------------------------
            for (size_t i = 0; i < sizeof ex/sizeof(ex[0]); i++)
            {
                //-------------------------------------------------------------
                if ((unsigned(diskindex) == n) && (ex2[i] == comp.fdd[n].snaptype))
                    ofn.nFilterIndex = snp;
                //-------------------------------------------------------------
                memcpy(mask+8,  ex[i]3);
                memcpy(mask+15, ex[i]3);
                addref( ptr,
                        u8(ex2[i]),
                        mask,
                        n,
                        (*(const unsigned*)ex[i] & 0xFFFFFF) | 0x202020
                      );
            }
            //-----------------------------------------------------------------
        }
        //---------------------------------------------------------------------
    } //conf.trdos_present
    //-------------------------------------------------------------------------
    ofn.lpstrFilter = types;
    *ptr = 0;
    ofn.lpstrFile = fname;
    ofn.nMaxFile = sizeof fname;
    ofn.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY;
    ofn.hwndOwner = GetForegroundWindow();
    char *path = strrchr(fname, '\\');
    //-------------------------------------------------------------------------
    if (path)
    { // check if directory exists (for files opened from archive)
        char x = *path;
        *path = 0;
        unsigned atr = GetFileAttributes(fname);
        *path = x;
        //---------------------------------------------------------------------
        if (atr == -1U || !(atr & FILE_ATTRIBUTE_DIRECTORY))
            *fname = 0;
        //---------------------------------------------------------------------
    }
    else
    {
        path = fname;
    }
    //-------------------------------------------------------------------------
    path = strrchr(path, '.');
    if (path)
        *path = 0; // delete extension
    //-------------------------------------------------------------------------
    if (GetSnapshotFileName(&ofn, 1))
    {
        //printf("get snapshot filename\n");    //òîëüêî ïðè çàïèñè
                                                //ïðè îòêðûòèè íå ñðàáàòûâàåò
        char *fn = strrchr(ofn.lpstrFile, '\\');
        fn = fn    ?    fn + 1 :
                        ofn.lpstrFile;
        char *extpos = strrchr(fn, '.');
        //---------------------------------------------------------------------
        if (!extpos || stricmp(extpos+1, (char*)&exts[ofn.nFilterIndex]))
        {
            char *dst = fn + strlen(fn);
            *dst++ = '.';
            *(unsigned*)dst = exts[ofn.nFilterIndex];
        }
        //---------------------------------------------------------------------
        if (    (GetFileAttributes(ofn.lpstrFile) != INVALID_FILE_ATTRIBUTES) &&
                (IDNO == MessageBox(GetForegroundWindow(), "File exists. Overwrite ?", "Save", MB_ICONQUESTION | MB_YESNO))
          )
        {
            goto again;
        }
        //---------------------------------------------------------------------
        FILE *ff = fopen(ofn.lpstrFile, "wb");
        //---------------------------------------------------------------------
        if (ff)
        {
            int res = 0;
            FDD *saveto = comp.fdd + drvs[ofn.nFilterIndex];
            //-----------------------------------------------------------------
            switch (snaps[ofn.nFilterIndex])
            {
                case snSNA_128: res = writeSNA(ff);             break;
                case snPAL:     res = writePAL(ff);             break;
                case snTRD:     res = saveto->write_trd(ff);    break;
                case snUDI:     res = saveto->write_udi(ff);    break;
                case snFDI:     res = saveto->write_fdi(ff);    break;
                case snTD0:     res = saveto->write_td0(ff);    break;
                case snISD:     res = saveto->write_isd(ff);    break;
                case snPRO:     res = saveto->write_pro(ff);    break;
            }
            //-----------------------------------------------------------------
            fclose(ff);
            //-----------------------------------------------------------------
            if (!res)
                MessageBox(GetForegroundWindow(), "write error", "Save", MB_ICONERROR);
            //-----------------------------------------------------------------
            else if (drvs[ofn.nFilterIndex]!=-1U)
            {
                comp.fdd[drvs[ofn.nFilterIndex]].optype=0;
                strcpy(comp.fdd[drvs[ofn.nFilterIndex]].name, ofn.lpstrFile);
                //---------Alone Coder
                char *name = ofn.lpstrFile;
                //printf("snaphot filename printing\n");
                //-------------------------------------------------------------
                for (char *x = name; *x; x++)
                {
                    if (*x == '\\')
                        name = x+1;
                }
                //-------------------------------------------------------------
                char wintitle[0x200];
                strcpy(wintitle,name);
//              strcat(wintitle," - UnrealSpeccy");
                strcat(wintitle," - Unreal_NS");        // äëÿ ñîõðàíåííîãî äèñêà
                SetWindowText(wnd, wintitle);
                //~---------Alone Coder
            }
            //-----------------------------------------------------------------
        }
        //---------------------------------------------------------------------
        else
        {
            MessageBox(GetForegroundWindow(), "Can't open file for writing", "Save", MB_ICONERROR);
        }
        //---------------------------------------------------------------------
    }
    //-------------------------------------------------------------------------
    eat();
}
//=============================================================================



//=============================================================================
void ConvPal8ToBgr24(u8 *dst, u8 *scrbuf, int dx)
{
    u8 *ds = dst;
    //-------------------------------------------------------------------------
    for(unsigned i = 0; i < temp.oy; i++)       // convert to BGR24 format
    {
        unsigned char *src = scrbuf + int(i) * dx;
        //---------------------------------------------------------------------
        for (unsigned y = 0; y < temp.ox; y++)
        {
            ds[0] = pal0[src[y]].peBlue;
            ds[1] = pal0[src[y]].peGreen;
            ds[2] = pal0[src[y]].peRed;
            ds += 3;
        }
        //---------------------------------------------------------------------
        ds = (PBYTE)(ULONG_PTR(ds + 3) & ~ULONG_PTR(3)); // êàæäàÿ ñòðîêà âûðàâíåíà íà 4
    }
    //-------------------------------------------------------------------------
}
//=============================================================================


//=============================================================================
void ConvRgb15ToBgr24(u8 *dst, u8 *scrbuf, int dx)
{
    u8 *ds = dst;
    //-------------------------------------------------------------------------
    for(unsigned i = 0; i < temp.oy; i++)       // convert to BGR24 format
    {
        unsigned char *src = scrbuf + int(i) * dx;
        //---------------------------------------------------------------------
        for (unsigned y = 0; y < temp.ox; y++)
        {
            unsigned xx;
            xx = *(unsigned*)(src + y*2);

            ds[0] = u8((xx & 0x1F)   << 3);
            ds[1] = u8((xx & 0x03E0) >> 2);
            ds[2] = u8((xx & 0x7C00) >> 7);
            ds += 3;
        }
        //---------------------------------------------------------------------
        ds = (PBYTE)(ULONG_PTR(ds + 3) & ~ULONG_PTR(3)); // êàæäàÿ ñòðîêà âûðàâíåíà íà 4
    }
    //-------------------------------------------------------------------------
}
//=============================================================================


//=============================================================================
void ConvRgb16ToBgr24(u8 *dst, u8 *scrbuf, int dx)
{
    u8 *ds = dst;
    //-------------------------------------------------------------------------
    for(unsigned i = 0; i < temp.oy; i++)       // convert to BGR24 format
    {
        unsigned char *src = scrbuf + int(i) * dx;
        //---------------------------------------------------------------------
        for (unsigned y = 0; y < temp.ox; y++)
        {
            unsigned xx;
            xx = *(unsigned*)(src + y*2);

            ds[0] = u8((xx&0x1F)   << 3);
            ds[1] = u8((xx&0x07E0) >> 3);
            ds[2] = u8((xx&0xF800) >> 8);
            ds += 3;
        }
        //---------------------------------------------------------------------
        ds = (PBYTE)(ULONG_PTR(ds + 3) & ~ULONG_PTR(3)); // êàæäàÿ ñòðîêà âûðàâíåíà íà 4
    }
    //-------------------------------------------------------------------------
}
//=============================================================================


//=============================================================================
void ConvYuy2ToBgr24(u8 *dst, u8 *scrbuf, int dx)
{
    u8 *ds = dst;
    //-------------------------------------------------------------------------
    for(unsigned i = 0; i < temp.oy; i++) // convert to BGR24 format
    {
        unsigned char *src = scrbuf + int(i) * dx;
        //---------------------------------------------------------------------
        for (unsigned y = 0; y < temp.ox; y++)
        {
            unsigned xx;
            xx = *(unsigned*)(src + y*2);

            int u = src[y / 2 * 4 + 1];
            int v = src[y / 2 * 4 + 3];
            int Y = src[y * 2];
            int r = (int)(.4732927654e-2 * u - 255.3076403 + 1.989858012 * v + .9803921569 * Y);
            int g = (int)(-.9756592292   * v + 186.0716700 - .4780256930 * u + .9803921569 * Y);
            int b = (int)(.9803921569    * Y + 2.004732928 * u - 255.3076403 - .1014198783e-1 * v); // mapple rulez!
           
            if (r < 0) r = 0; if (r > 255) r = 255;
            if (g < 0) g = 0; if (g > 255) g = 255;
            if (b < 0) b = 0; if (b > 255) b = 255;

            ds[0] = u8(b);
            ds[1] = u8(g);
            ds[2] = u8(r);
            ds += 3;
        }
        //---------------------------------------------------------------------
        ds = (PBYTE)(ULONG_PTR(ds + 3) & ~ULONG_PTR(3)); // êàæäàÿ ñòðîêà âûðàâíåíà íà 4
    }
    //-------------------------------------------------------------------------
}
//=============================================================================


//=============================================================================
void ConvBgr32ToBgr24(u8 *dst, u8 *scrbuf, int dx)
{
    u8 *ds = dst;
    //-------------------------------------------------------------------------
    for(unsigned i = 0; i < temp.oy; i++)       // convert to BGR24 format
    {
        unsigned char *src = scrbuf + int(i) * dx;
        //---------------------------------------------------------------------
        for (unsigned x = 0; x < temp.ox; x++)
        {
            ds[0] = src[0];
            ds[1] = src[1];
            ds[2] = src[2];
            src += 4;
            ds += 3;
        }
        //---------------------------------------------------------------------
        ds = (PBYTE)(ULONG_PTR(ds + 3) & ~ULONG_PTR(3)); // êàæäàÿ ñòðîêà âûðàâíåíà íà 4
    }
    //-------------------------------------------------------------------------
}
//=============================================================================

TColorConverter ConvBgr24 = nullptr;

//=============================================================================
static void SaveBmp(FILE *File, u8 *ds)
{
    //-------------------------------------------------------------------------
    static u8 bmpheader32[]=
    {
        // BITMAPFILEHEADER
        0x42, 0x4d,                     // Type
        0x36, 0x10, 0x0e, 0x00,         // Size
        0x00, 0x00,                     // Reserved1
        0x00, 0x00,                     // Reserved2
        0x36, 0x00, 0x00, 0x00,         // OffBits
        // BITMAPINFOHEADER
        0x28, 0x00, 0x00, 0x00,         // Size
        0x80, 0x02, 0x00, 0x00,         // Width
        0xe0, 0x01, 0x00, 0x00,         // Height
        0x01, 0x00,                     // Planes
        0x18, 0x00,                     // BitCount
        0x00, 0x00, 0x00, 0x00,         // Compression
        0x00, 0x10, 0x0e, 0x00,         // SizeImage
        0x00, 0x00, 0x00, 0x00,         // XPixelsPerMeter
        0x00, 0x00, 0x00, 0x00,         // YPixelsPerMeter
        0x00, 0x00, 0x00, 0x00,         // ClrUsed
        0x00, 0x00, 0x00, 0x00          // ClrImportant
    };
    //-------------------------------------------------------------------------
    *(unsigned*)(bmpheader32 + 2) = temp.ox * temp.oy * 3 + sizeof(bmpheader32); // filesize
    *(unsigned*)(bmpheader32 + 0x12) = temp.ox;
    *(unsigned*)(bmpheader32 + 0x16) = temp.oy;
    //-------------------------------------------------------------------------
    fwrite(bmpheader32, 1, sizeof(bmpheader32), File);
    //-------------------------------------------------------------------------
    for (int y = int(temp.oy - 1); y >= 0 ; y--)
    {
        fwrite(ds + ((unsigned(y) * temp.ox * 3 + 3) & ~3U), 1, temp.ox * 3, File);
    }
    //-------------------------------------------------------------------------
}
//=============================================================================


//=============================================================================
static void SavePng(FILE *File, u8 *ds)
{
    static png_color bkgColor = {127, 127, 127};

    if (!temp.PngSupport)
        return;

    PngSaveImage(File, ds, int(temp.ox), int(temp.oy), bkgColor);
}
//=============================================================================

#define MAKE_RGBQUAD(r,g,b) (ULONG) (u32(b) | (u32(g)<<8) | (u32(r)<<16))

//=============================================================================
static void SaveBmp16c(FILE *File, const u8 *ds)
{
    static u8 bmpheader32[]=
    {
        // BITMAPFILEHEADER
        0x42, 0x4d,             // Type
        0x36, 0x10, 0x0e, 0x00, // Size = 320*200/2 + sizeof(bmpheader32)
        0x00, 0x00,             // Reserved1
        0x00, 0x00,             // Reserved2
        0x76, 0x00, 0x00, 0x00, // OffBits
        // BITMAPINFOHEADER
        0x28, 0x00, 0x00, 0x00, // Size
        0x40, 0x01, 0x00, 0x00, // Width = 320
        0xc8, 0x00, 0x00, 0x00, // Height = 200
        0x01, 0x00,             // Planes
        0x04, 0x00,             // BitCount = 4
        0x00, 0x00, 0x00, 0x00, // Compression = BI_RGB
        0x00, 0x10, 0x0e, 0x00, // SizeImage
        0x00, 0x00, 0x00, 0x00, // XPixelsPerMeter
        0x00, 0x00, 0x00, 0x00, // YPixelsPerMeter
        0x00, 0x00, 0x00, 0x00, // ClrUsed
        0x00, 0x00, 0x00, 0x00, // ClrImportant
        // PALETTE
        0, 0, 0, 0,             //  0 bgra
        0, 0, 0, 0,             //  1 bgra
        0, 0, 0, 0,             //  2 bgra
        0, 0, 0, 0,             //  3 bgra
        0, 0, 0, 0,             //  4 bgra
        0, 0, 0, 0,             //  5 bgra
        0, 0, 0, 0,             //  6 bgra
        0, 0, 0, 0,             //  7 bgra
        0, 0, 0, 0,             //  8 bgra
        0, 0, 0, 0,             //  9 bgra
        0, 0, 0, 0,             // 10 bgra
        0, 0, 0, 0,             // 11 bgra
        0, 0, 0, 0,             // 12 bgra
        0, 0, 0, 0,             // 13 bgra
        0, 0, 0, 0,             // 14 bgra
        0, 0, 0, 0              // 15 bgra
    };

    *(unsigned*)(bmpheader32 + 2) = 320 * 200 / 2 + sizeof(bmpheader32); // filesize
    //-------------------------------------------------------------------------
    for(unsigned i = 0; i < 16; i++)
    {
        // Ôîðìàò äàííûõ ïàëèòðû Gg0Rr0Bb
        // Ðàñêëàäêà ïàëèòðû ýìóëÿòîðà - ULA+
        unsigned PalIdx = ((i & 8) << 1) | (i & 7);
        u8 r = u8(u32((comp.comp_pal[PalIdx] >> 3) & 3) * 255 / 3);
        u8 g = u8(u32((comp.comp_pal[PalIdx] >> 6) & 3) * 255 / 3);
        u8 b = u8(u32( comp.comp_pal[PalIdx]       & 3) * 255 / 3);

        *(PULONG)(bmpheader32 + 54 + 4 * i) = MAKE_RGBQUAD(r, g, b);
    }
    //-------------------------------------------------------------------------
    fwrite(bmpheader32, 1, sizeof(bmpheader32), File);
    fwrite(ds, 1, 320 * 200 / 2, File);
}
//=============================================================================


//=============================================================================
static void ConvPal16cAtm1(u8 *Buf)
{
    static const int ega0_ofs = -4 * PAGE;
    static const int ega1_ofs = 0;
    static const int ega2_ofs = -4 * PAGE + 0x2000;
    static const int ega3_ofs = 0x2000;
    //-------------------------------------------------------------------------
    for (int y = 200 - 1; y >= 0; y--)
    {
        const u8 *src = temp.base + y * 40;
        //---------------------------------------------------------------------
        for(unsigned x = 0; x < 320; x += 8)
        {
            u8 v0 = src[ega0_ofs];
            u8 v1 = src[ega1_ofs];
            u8 v2 = src[ega2_ofs];
            u8 v3 = src[ega3_ofs];
            Buf[0] = u8(((((v0 >> 3) & 8) | (v0 & 0x7)) << 4) | (((v0 & 0x80) | ((v0 << 1) & 0x70)) >> 4));
            Buf[1] = u8(((((v1 >> 3) & 8) | (v1 & 0x7)) << 4) | (((v1 & 0x80) | ((v1 << 1) & 0x70)) >> 4));
            Buf[2] = u8(((((v2 >> 3) & 8) | (v2 & 0x7)) << 4) | (((v2 & 0x80) | ((v2 << 1) & 0x70)) >> 4));
            Buf[3] = u8(((((v3 >> 3) & 8) | (v3 & 0x7)) << 4) | (((v3 & 0x80) | ((v3 << 1) & 0x70)) >> 4));
         
            src++;
            Buf += 4;
        }
        //---------------------------------------------------------------------
    }
    //-------------------------------------------------------------------------
}
//=============================================================================

#define ConvPal16cAtm2 ConvPal16cAtm1

typedef void (*TSaver)(FILE *File, u8 *ds);

//=============================================================================
void main_scrshot()
{
    char fname[FILENAME_MAX];
//  static unsigned sshot = 999990;//0; // ñòàðòîâûé íîìåð ñêðèíøîòà
    static unsigned int sshot = 0;      // [NS]
    //-------------------------------------------------------------------------
    static const char *Format[] =
    {
        "scr",
        "bmp",
        "png"
    };
    //-------------------------------------------------------------------------
    static const TSaver Saver[] =
    {
        SaveBmp,
        SavePng
    };
    //-------------------------------------------------------------------------

    const char *Ext = Format[conf.scrshot];

    //-------------------------------------------------------------------------
    if (    (conf.scrshot == 0)
            &&
            (
                (
                    ((conf.mem_model == MM_ATM710) || (conf.mem_model == MM_ATM3))
                    &&
                    ((comp.pFF77 & 7) == 0)
                )
                ||
                ((conf.mem_model == MM_ATM450) && (((comp.aFE >> 5) & 3) == 0))
            )
        )
    {
        Ext = Format[1];
    }
    //-------------------------------------------------------------------------
    // Ïåðâàÿ ïðîâåðêà èìåíè ôàéëà (êîãäà ïóñòàÿ ïàïêà èëè íîìåð ïîñëåäíåãî ôàéëà óæå èçâåñòåí) [NS] r0110
    // printf("%X\n",sshot);
    snprintf(   fname,
                _countof(fname),
                //"%s\\%s_%06u.%s",     conf.scrshot_dir,
                "%s\\%s_%08u.%s",       conf.scrshot_dir,
                                        temp.LastSnapName[0] ?  temp.LastSnapName :
                                                                "sshot",
                                        sshot,
                                        Ext
                );
   
    fname[FILENAME_MAX-1] = 0;
    //-------------------------------------------------------------------------
    // åñëè òàêè òàêîãî ôàéëà òàêè íåò òî ìîë÷à òàêè ñîõðàíÿåì  [NS] r0110
    if (access (fname, 0) != 0)
    {
        goto screenshot_name_valid;
    }
    //-------------------------------------------------------------------------
    // letz brute new name òîãäà                                [NS] r0110
    // íî òê áðóòèòü 9 ñåí ìàíîâ ôàéëîâ ýòî íå êàìèëüôî
    // à êàê ïðàâèëüíî ïîëó÷èòü íîìåð ïîñëåäíåãî ôàéëà ßÕÇ
    // òî
    //
    { // ïðîñòî îãðàíè÷åíèå ìåðñêîé âèäèìîñòè äëÿ íîðìàëüíîãî äæàìïàíüÿ íà screenshot_name_valid
        sshot = 0xFFFFFFFF;
        unsigned int roll_bit = 0x80000000;     //INT_MIN;      //8000 0000
        int temp_cnt = 0;
        bool valid_name_found = FALSE;
        unsigned int valid_name_cnt = 0;
        //---------------------------------------------------------------------
        // ñáðàñûâàåì êàæäûé áèò íîìåðà ÷èñëà îò d31 äî d0
        // è ñâåðÿåì åñòü ëè òàêîé ôàéë
        while (temp_cnt < 32)
        {
            sshot ^= roll_bit;
            //printf("%X - ",sshot);
            snprintf(   fname,
                        _countof(fname),
                        //"%s\\%s_%06u.%s",     conf.scrshot_dir,
                        "%s\\%s_%08u.%s",       conf.scrshot_dir,
                                                temp.LastSnapName[0] ?  temp.LastSnapName :
                                                                        "sshot",
                                                sshot,
                                                Ext
                    );
   
            fname[FILENAME_MAX-1] = 0;
            //-----------------------------------------------------------------
            // òàêîé ôàéë åñòü
            if (access (fname, 0) == 0)
            {
                // printf("invalid\n");
                sshot ^= roll_bit;      //
            }
            //-----------------------------------------------------------------
            // òàêîãî ôàéëà íåòó
            else
            {
                // printf("valid\n");
                valid_name_found = TRUE;
                valid_name_cnt = sshot;
            }
            //-----------------------------------------------------------------
            roll_bit = (roll_bit >> 1);
            //-----------------------------------------------------------------
            temp_cnt++;
            //system ("pause");
        }
        //---------------------------------------------------------------------
        if (valid_name_found)
        {
            sshot = valid_name_cnt;
            goto screenshot_name_valid;
        }
        //sshot++;
    } // ïðîñòî îãðàíè÷åíèå ìåðñêîé âèäèìîñòè äëÿ íîðìàëüíîãî äæàìïàíüÿ íà screenshot_name_valid
    //-------------------------------------------------------------------------

    //-------------------------------------------------------------------------
    printf("screenshot save error: to big sshot counter\n");
    return;
    //-------------------------------------------------------------------------
   
    //-------------------------------------------------------------------------
screenshot_name_valid:
    //printf("valid %X\n",sshot);
    snprintf(   fname,
                _countof(fname),
                //"%s\\%s_%06u.%s",     conf.scrshot_dir,
                "%s\\%s_%08u.%s",       conf.scrshot_dir,
                                        temp.LastSnapName[0] ?  temp.LastSnapName :
                                                                "sshot",
                                        sshot,
                                        Ext
            );
   
    fname[FILENAME_MAX-1] = 0;
    //-------------------------------------------------------------------------    
    FILE *fileShot = fopen(fname, "wb");
    if (!fileShot)
    {
        printf("screenshot save error\n");
        return;
    }
    //-------------------------------------------------------------------------
    if (conf.scrshot == 0)
    {
        //---------------------------------------------------------------------
        switch (conf.mem_model)
        {
            //-----------------------------------------------------------------
            case MM_ATM710:
            case MM_ATM3:
            {
                switch(comp.pFF77 & 7)
                {
                    //---------------------------------------------------------
                    case 0: // EGA 320x200 16c
                    {
                        u8 *Buf = (u8 *)malloc(320*200/2);
                        ConvPal16cAtm2(Buf);
                        SaveBmp16c(fileShot, Buf);
                        free(Buf);
                    }
                    break;
                    //---------------------------------------------------------
                    case 3:
                        goto standard_zx_mode;
                    //---------------------------------------------------------
                }
            }
            break;
            //-----------------------------------------------------------------
            case MM_ATM450:
                switch((comp.aFE >> 5) & 3)
                {
                    //---------------------------------------------------------
                    case 0: // EGA 320x200 16c
                    {
                        u8 *Buf = (u8 *)malloc(320*200/2);
                        ConvPal16cAtm1(Buf);
                        SaveBmp16c(fileShot, Buf);
                        free(Buf);
                    }
                    break;
                    //---------------------------------------------------------
                    case 3:
                        goto standard_zx_mode;
                    //---------------------------------------------------------
                }
            break;
            //-----------------------------------------------------------------
            default:
standard_zx_mode:;
                fwrite(temp.base, 1, 6912, fileShot);
        }
        //---------------------------------------------------------------------
    }
    //-------------------------------------------------------------------------
    else
    {
        unsigned dx = temp.ox * temp.obpp / 8;
        unsigned char *scrbuf_unaligned = (unsigned char*)malloc(dx * temp.oy + CACHE_LINE);
        unsigned char *scrbuf = (unsigned char*)align_by(scrbuf_unaligned, CACHE_LINE);
        memset(scrbuf, 0, dx * temp.oy);
        renders[conf.render].func(scrbuf, dx); // render to memory buffer (PAL8, YUY2, RGB15, RGB16, RGB32)

        u8 *ds = (u8 *)malloc(((temp.ox * 3 + 3) & ~3U) * temp.oy);
        ConvBgr24(ds, scrbuf, int(dx));

        Saver[conf.scrshot - 1](fileShot, ds);

        free(ds);
        free(scrbuf_unaligned);
    }
    //-------------------------------------------------------------------------
    fclose(fileShot);
    sprintf(statusline, "saving %s", strrchr(fname, '\\') + 1);
    statcnt = 30;
    sshot++;
}
//=============================================================================

/*
static void VideoFrameSaver()
{
   char fname[FILENAME_MAX];
   static unsigned FrameNum = 0;
   static const char *Format[] = { "scr", "bmp", "png" };
   static const TSaver Saver[] = { SaveBmp, SavePng };

   sprintf(fname, "video%06u.%s", FrameNum, Format[conf.scrshot]);
   addpath(fname);

   FILE *fileShot = fopen(fname, "wb");
   if (!fileShot)
      return;

   if (conf.scrshot == 0)
   {
      fwrite(temp.base, 1, 6912, fileShot);
   }
   else
   {
       unsigned dx = temp.ox * temp.obpp / 8;
       unsigned char *scrbuf_unaligned = (unsigned char*)malloc(dx * temp.oy + CACHE_LINE);
       unsigned char *scrbuf = (unsigned char*)align_by(scrbuf_unaligned, CACHE_LINE);
       memset(scrbuf, 0, dx * temp.oy);
       renders[conf.render].func(scrbuf, dx); // render to memory buffer (PAL8, YUY2, RGB15, RGB16, RGB32)

       u8 *ds = (u8 *)malloc(((temp.ox * 3 + 3) & ~3) * temp.oy);
       ConvBgr24(ds, scrbuf, dx);

       Saver[conf.scrshot - 1](fileShot, ds);

       free(ds);
       free(scrbuf_unaligned);
   }
   fclose(fileShot);
   FrameNum++;
}
//=============================================================================
static void VideoNullSaver()
{

}
//=============================================================================
TVideoSaver VideoSaver = VideoNullSaver;
//=============================================================================
void main_savevideo()
{
   static bool StartSave = false;

   if(!StartSave)
   {
       sprintf(statusline, "start saving video");
       StartSave = true;
       VideoSaver = VideoFrameSaver;
   }
   else
   {
       sprintf(statusline, "stop saving video");
       StartSave = false;
       VideoSaver = VideoNullSaver;
   }

   statcnt = 30;
}
*/

//=============================================================================