Subversion Repositories autosfx

Rev

Blame | Last modification | View Log | RSS feed

  1. #include "stdafx.h"
  2. #pragma hdrstop
  3. /*
  4.  
  5.   Copyright (c) 1990-2007 Info-ZIP.  All rights reserved.
  6.  
  7.   See the accompanying file LICENSE, version 2007-Mar-4 or later
  8.   (the contents of which are also included in zip.h) for terms of use.
  9.   If, for some reason, all these files are missing, the Info-ZIP license
  10.   also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
  11.  
  12.   parts Copyright (C) 1997 Mike White, Eric W. Engler
  13. ************************************************************************
  14.  Copyright (C) 2009, 2010  by Russell J. Peters, Roger Aelbrecht
  15.  
  16.    This file is part of TZipMaster Version 1.9.
  17.  
  18.     TZipMaster is free software: you can redistribute it and/or modify
  19.     it under the terms of the GNU Lesser General Public License as published by
  20.     the Free Software Foundation, either version 3 of the License, or
  21.     (at your option) any later version.
  22.  
  23.     TZipMaster is distributed in the hope that it will be useful,
  24.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  25.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  26.     GNU Lesser General Public License for more details.
  27.  
  28.     You should have received a copy of the GNU Lesser General Public License
  29.     along with TZipMaster.  If not, see <http://www.gnu.org/licenses/>.
  30.  
  31.     contact: problems@delphizip.org (include ZipMaster in the subject).
  32.     updates: http://www.delphizip.org
  33.     DelphiZip maillist subscribe at http://www.freelists.org/list/delphizip
  34. ************************************************************************/
  35. #include <stdio.h>
  36. #include <shellapi.h>
  37. #include <sys\stat.h>
  38. //#ifndef __BORLANDC__
  39. //#define stati64 _stati64
  40. //#endif
  41. #include "common.h"
  42. #include "ZStrings.h"
  43. #include "dzframe.h"
  44. #include "DZOper.h"
  45. #include "version.h"
  46. #include "helpers.h"
  47. #include "dz_errs.h"
  48.  
  49. #undef _DZ_FILE_
  50. #define _DZ_FILE_ DZ_DZOPER_CPP
  51. //---------------------------------------------------------------------------
  52.  
  53. DZStrW SystemMsg(DWORD Error, const TCHAR* arg1)
  54. {
  55.     LPVOID lpMsgBuf;
  56.  
  57.     DWORD flags = FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM;
  58.     void *mdl = 0;
  59.  
  60.     if (Error & (DWORD)0x40000000L)
  61.         {
  62.         flags = FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE;
  63.         mdl = ModuleInst;
  64.     }                          
  65. #if defined(UNICODE) && defined(ALLOW_WIN98)
  66.     FormatMessageA(flags, mdl, Error, 0, (LPSTR) &lpMsgBuf, 1000, NULL);  
  67.     DZStrW t((const char *)lpMsgBuf);
  68. #else
  69.     FormatMessage(flags, mdl, Error, 0, (LPTSTR) &lpMsgBuf, 1000, NULL);
  70.     DZStrW t((const TCHAR *)lpMsgBuf);
  71. #endif
  72.     if (t[t.Length() -2] == '\r')
  73.                 t.Delete(t.Length()-2, 2);
  74.  
  75.     // Free the buffer.
  76.     LocalFree(lpMsgBuf);
  77.     DZStrW tmp;
  78.     tmp.Format(t, arg1);
  79.  
  80.         return tmp;
  81. }
  82.  
  83. DZStrW LastSystemMsg(void)
  84. {
  85.     DWORD err = GetLastError();
  86.     return SystemMsg(err);
  87. }
  88.  
  89. void DZOp::SendInfo(unsigned err, const DZStrW& info)
  90. {
  91.         int     typ = 0;
  92.         DZStrW buf;
  93.  
  94.     if (err > 0)
  95.     {
  96.         typ = DZ_MSGTYP(err);
  97.  
  98.         if (typ == DZM_Trace)
  99.             buf = _T("Trace: ");
  100.         else
  101.             if (typ == DZM_Verbose)
  102.                 buf = _T("Info: ");
  103.  
  104.         buf += info;
  105.     }
  106.     else
  107.         buf = info;
  108.  
  109. //#ifdef DZ_LOGGING
  110. //    if (LogName && *(LogName))
  111. //        LogString(err, buf);
  112. //#endif
  113.     CB->UserMsg(err, buf);
  114.  
  115.     if ((IERROR & typ) && Verbose < -10)
  116.     {
  117.         Verbose++;
  118.         MsgBox(buf, true);
  119.     }
  120. }
  121.  
  122. DZOp::DZOp(const DllCommands *C): DZFrame((OperKeys)C,
  123.                 C->fOptions.OpIsZip || C->fOptions.OpIsZip), Command(C)
  124. {
  125.     Verbose = C->fVerbosity;
  126.  
  127.     if (Verbose > 1)
  128.         Verbose = -1;
  129.  
  130.     fEncodedAs = C->fEncodedAs;
  131.     fQuiet = C->fOptions.Quiet;
  132.     fglobal_error_code = 0;
  133.     fdll_handles_errors = 0;
  134.     fuser_notified_of_abort = 0;
  135.         CallerVersion = C->fVersion;
  136.     fNTFSStamps = C->fOptions.NTFSStamps;
  137.  
  138.     fFromPage = C->fFromPage;
  139.     fSS = C->fSS;         // used stream-stream
  140.         Abort_Flag = 0;
  141. //      NoSkipping = C->fOptions.NoSkip;   //<<
  142.  
  143.     // Copy the window handle and context of caller to our global vars
  144.     global_handle = C->fHandle;
  145.     global_caller = C->fCaller;
  146.  
  147.     // point to the C++Builder/Delphi callback function
  148.     callb = C->ZCallbackFunc;
  149.     ZStreamFunc = C->ZStreamFunc;
  150.     ZSData.Check = STREAM_CHECK;
  151.     ZSData.Caller = global_caller; // object instance pointer of caller
  152.     CB = new UserCallback(this, C->fOptions.OpIsZip || C->fOptions.OpIsZip);
  153.  
  154.     CurPW = NULL;
  155.     CurBase = NULL;
  156.     fBytesWritten = 0;
  157. }
  158.  
  159. DZOp::~DZOp(void)
  160. {
  161.  
  162.     PWRec *tp, *tmpp = CurPW;
  163.     CurPW = NULL;
  164.  
  165.     while (tmpp)
  166.     {
  167.         tp = tmpp;
  168.         tmpp = tmpp->Next;
  169.         delete tp;
  170.     }
  171.  
  172.     BaseRec *tb, *tmpb = CurBase;
  173.     CurBase = NULL;
  174.  
  175.     while (tmpb)
  176.     {
  177.         tb = tmpb;
  178.         tmpb = tmpb->Next;
  179.         delete tb;
  180.     }
  181.  
  182.     delete CB;
  183. }
  184.  
  185. int DZOp::Init(void) // after construction
  186. {
  187.     // do active initialisation    
  188.     if (Command->fVersion != DZ_VER_VERSION)
  189.     {
  190.         // see version.h
  191.         DZStrW tmp;
  192.         tmp.Format(_T("Warning: %s version %s is %s than required (%i.%i.%i) - Please use correct version!"),
  193.             _T(DLLNAME), _T(DZ_VER), (Command->fVersion < DZ_VER_VERSION) ? _T("newer") : _T("older"),
  194.             Command->fVersion / 100, (Command->fVersion / 10) % 10, Command->fVersion % 10);
  195.  
  196.         // This message won't appear if user did pass us a zero Window handle.
  197.         if (!Command->fOptions.Quiet)
  198.             MsgBox(tmp, true);
  199.  
  200.         // Also report this fact via the C++Builder/Delphi callback.
  201.         Notify(IERROR, tmp);
  202.         return DZ_ERM_BAD_OPTIONS;
  203.     }
  204.     return 0;
  205. }
  206.  
  207. void DZOp::ShowSysMsg(DWORD Error)
  208. {
  209.     if (Verbose)
  210.     {
  211.         Notify(0, _T("System Error (%lX) %s"), Error, SystemMsg(Error).c_str());
  212.     }
  213. }
  214.  
  215. // If we do not have a full path then FOF_ALLOWUNDO does not work!
  216. int DZOp::EraseFile(const DZStrW &Fname, bool safe)
  217. {                            
  218.     SHFILEOPSTRUCT  fop;
  219.     TCHAR           *sb;
  220.     int             ls,
  221.     r;
  222.     if (Fname.IsEmpty())  
  223.         return ENOENT;
  224.  
  225.     if (Verbose < 0)
  226.         Notify(IVERBOSE, _T("destroying '%s'"), Fname.c_str());
  227.     else
  228.       CB->UserCB(zacTick);  // take a little time
  229.     if (GetFileAttrs(Fname) == (DWORD) - 1)
  230.     {
  231.         if (Verbose < 0)
  232.             Notify(IVERBOSE, _T("did not exist '%s'"), Fname.c_str());
  233.         return DZ_ERR_GOOD;
  234.     }
  235.     fop.hwnd = global_handle;
  236.     fop.wFunc = FO_DELETE;
  237.     fop.pTo = NULL;
  238.     fop.fFlags = FOF_NOCONFIRMATION | FOF_NOCONFIRMMKDIR | FOF_NORECURSION;
  239.     if (safe)
  240.         fop.fFlags |= FOF_ALLOWUNDO;
  241.     fop.fAnyOperationsAborted = 0;
  242.     fop.hNameMappings = NULL;
  243.     fop.lpszProgressTitle = NULL;
  244.     DZStrW tmp(Fname);
  245.     ls = tmp.length();
  246.     sb = tmp.GetBuffer(ls + 2);
  247.     sb[ls + 1] = 0;
  248.     fop.pFrom = sb;
  249.     r = SHFileOperation(&fop);
  250.     if (r)
  251.     {
  252.         Notify(DZ_ERM_TEMP_FAILED, _T(" DestroyFile: Delete failed [%X]"), GetLastError());
  253.         return -1;
  254.     }
  255.  
  256.     return DZ_ERR_GOOD;
  257. }
  258.  
  259. // cached call to 'stat' - return true if not found
  260. bool DZOp::ZStat(const DZStrW &fn, struct stati64 *res)
  261. {
  262.     if (lastStatName && ZMatch(lastStatName, fn))
  263. //      if (!fn.Compare(lastStatName.c_str()))
  264.         {
  265.         memcpy(res, &lastStat, sizeof(struct stati64));
  266.                 return false;
  267.     }
  268.  
  269.     lastStatName.empty();
  270.  
  271.     bool ok;
  272.  
  273.         int drv = Is_Drv(fn);
  274.     if (drv < 0)
  275.     {
  276.                 memset(res, 0, sizeof(struct stati64));
  277.         ZSData.Number = (-drv) - 2;   // stream number
  278.         ZSData.OpCode = zsaIdentify;
  279.         int r = StreamCB();
  280.         ok = (r == CALLBACK_TRUE);
  281.  
  282.         if (ok)
  283.         {
  284.             res->st_size = ZSData.ArgLL;
  285.             res->st_atime = res->st_mtime = res->st_ctime = dos2unixtime(ZSData.ArgD);
  286.             long attr = ZSData.ArgA;
  287.             res->st_mode = S_IREAD;
  288.  
  289.             if (attr & FILE_ATTRIBUTE_DIRECTORY)
  290.                 res->st_mode |= (S_IFDIR | S_IWRITE | S_IEXEC) ;
  291.             else
  292.             {
  293.                 res->st_mode |= (mode_t)S_IFREG;
  294.                 if ((attr & FILE_ATTRIBUTE_READONLY) == 0)
  295.                     res->st_mode |= S_IWRITE;
  296.             }
  297.  
  298.             res->st_nlink = 1;
  299.         }
  300.     }
  301.     else
  302.         ok = !_tstati64(fn, res);
  303.  
  304.     if (ok)
  305.     {
  306.         lastStatName = fn;
  307.         memcpy(&lastStat, res, sizeof(struct stati64));
  308.     }
  309.  
  310.     return ok ? false : true;
  311. }
  312.  
  313. void DZOp::GiveTime(void)
  314. {
  315.     SYSTEMTIME SystemT;
  316.  
  317.     if (!Verbose)
  318.         return;
  319.  
  320.     GetSystemTime(& SystemT);
  321.  
  322.     Notify(IVERBOSE, _T("Time Hour %d, min %d, sec %d msec %d"),
  323.            SystemT.wHour, SystemT.wMinute, SystemT.wSecond, SystemT.wMilliseconds);
  324. }
  325.  
  326.  
  327. const char* DZOp::AddPW(const DZStrA& pw, bool toFront)
  328. {
  329.     PWRec *prv, *t, *root = CurPW;
  330.     prv = NULL;
  331.     t = root;
  332.         // find it
  333.     while (t)
  334.     {
  335.         if (!t->Passw && pw.IsEmpty())
  336.             break;   // same
  337.  
  338.         if (t->Passw && !pw.Compare(t->Passw))
  339.             break;   // found
  340.  
  341.         prv = t;
  342.         t = t->Next;
  343.     }
  344.  
  345.     if (!t)
  346.     {
  347.         // new entry
  348.         t = new PWRec(pw);
  349.  
  350.         if (toFront || !prv)
  351.         {
  352.             t->Next = root;
  353.                         CurPW = t;
  354.         }
  355.         else
  356.             prv->Next = t;  // append it
  357.     }
  358.     else
  359.         if (toFront && prv)
  360.         {
  361.             // move it
  362.             prv->Next = t->Next;
  363.             t->Next = root;
  364.                         CurPW = t;
  365.         }
  366.  
  367.     return t->Passw;
  368. }
  369.  
  370. const BaseRec* DZOp::AddBase(const DZStrW& base, bool toFront)
  371. {
  372.     DZStrW tmp = base;
  373.  
  374.     if (tmp.LastChar() != BSLASH)
  375.         tmp += BSLASH;
  376.  
  377.     BaseRec *prv, *t, *root = CurBase;
  378.     prv = NULL;
  379.     t = root;
  380.     // find it
  381.     while (t)
  382.     {
  383.         if (!tmp.CompareNoCase(t->Base))
  384.             break;   // found
  385.  
  386.         prv = t;
  387.         t = t->Next;
  388.     }
  389.  
  390.     if (!t)
  391.     {
  392.         // new entry
  393.         t = new BaseRec(tmp);
  394.  
  395.         if (toFront || !prv)
  396.         {
  397.             t->Next = root;
  398.             CurBase = t;
  399. //            root = t;
  400.         }
  401.         else
  402.             prv->Next = t;  // append it
  403.     }
  404.     else
  405.         if (toFront && prv)
  406.         {
  407.             // move it
  408.             prv->Next = t->Next;
  409.             t->Next = root;
  410.                         CurBase = t;
  411.         }
  412.  
  413.         return (const BaseRec*)t;
  414. }
  415.  
  416. DZStrW __fastcall DZOp::FullPath(const DZStrW &Filename, const BaseRec* base) const
  417. {
  418.     return base->FullPath(Filename);
  419. }
  420.  
  421. DZStrW __fastcall DZOp::GetFullPath(const DZStrW &Filename) const
  422. {
  423.     return CurBase->FullPath(Filename);
  424. }
  425.  
  426. /* ===================================================================== */
  427. void DZOp::MsgBox(const DZStrW& msg, bool CanCancel)
  428. {
  429.     DZStrW tmp;
  430.         tmp.Format(_T("Message From DelZip dll (%s)"), TypStr());
  431.     HWND wHandle = global_handle;
  432.  
  433.     /* Did the user pass us a good window handle? if not, we can't pop-up a box. */
  434.     if (!wHandle)
  435.         wHandle = GetDesktopWindow(); // v1.6021
  436.  
  437.     unsigned int flg = CanCancel ? MB_OKCANCEL | MB_ICONEXCLAMATION : MB_OK;
  438.  
  439.     /* bring up a dialog box */
  440.     if (MessageBox(wHandle, msg, tmp, flg) == IDCANCEL && CanCancel)
  441.         Abort_Flag |= GA_CANCEL;  // abort
  442. }
  443.  
  444.  
  445. int __fastcall DZOp::DZError(int err, const TCHAR *msg)
  446. {
  447.     DZStrW errmsg;
  448.  
  449.     if (fuser_notified_of_abort)
  450.         return err;
  451.  
  452.     fuser_notified_of_abort = 1;
  453.     int eno = err & 0xff;
  454.     fglobal_error_code = eno;
  455.     if (fdll_handles_errors)
  456.     {
  457.         /* I'm passing the error via the callback just to get it logged in
  458.         * the status box - I'm sending it in with a 0 error code to avoid
  459.         * a dialog box from the application program. */
  460.         if (err & DZM_MessageBit)
  461.         {
  462.             if (msg)
  463.                 DZErrMsg = msg;
  464.  
  465.             errmsg = DZErrMsg;
  466.         }
  467.         else    // load from resources
  468.             errmsg = SystemMsg((DZ__GOOD + eno), msg);
  469.  
  470.         Notify(0, errmsg);
  471.         errmsg.AppendFormat(_T("  code=%x"), err);
  472.         MsgBox(errmsg, false);
  473.     }
  474.     else
  475.     {
  476.         if (err & DZM_MessageBit)
  477.             errmsg = DZErrMsg;
  478.  
  479.         Notify(err, errmsg);
  480.     }
  481.  
  482.     /* Only application program handles errors. */
  483.     return err;
  484. }
  485.  
  486. //#define DZ_ERR_CANCELLED  1
  487. //#define DZ_ERR_ABORT   2
  488. //#define DZ_ERR_CALLBACK  3
  489. //// abort flag values
  490. //#define GA_NONE 0               // no error
  491. //#define GA_ERROR 1              // processing error
  492. //#define GA_CANCEL 2             // callback signalled cancel
  493. //#define GA_ABORT 4              // Abort requested
  494. //#define GA_EXCEPT 0x10          // callback caught exception
  495. //#define GA_EXCEPT2 0x20         // callback caused exception
  496. int __fastcall DZOp::Fatal(int err, unsigned flag, bool raise)
  497. {
  498.     const TCHAR* errs[3] = {_T("User cancelled"), _T("User Abort"), _T("Callback exception")};
  499.     const TCHAR* erm = 0;
  500.     int e = DZ_ERR(err);
  501.     if (e && e <= DZ_ERR_CALLBACK)
  502.     {
  503.         if (e <= DZ_ERR_CALLBACK)
  504.         {
  505.             if (!flag)
  506.                 flag = Abort_Flag;
  507.             e = DZ_ERR_CANCELLED;
  508.             if (flag & 4)
  509.                 e = DZ_ERR_ABORT;
  510.             if (flag > 4)
  511.                 e = DZ_ERR_CALLBACK;
  512.             err &= ~3;
  513.             err |= e;
  514.             erm = errs[--e];
  515.         }
  516.     }
  517.     DZError(err, erm);
  518.     if (raise)
  519.         throw DZException(err, erm);
  520.     return err;
  521. }
  522.  
  523. /* ===========================================================================
  524.  * This calls the application program and passes status info.
  525.  */
  526. int __fastcall DZOp::StreamCB(void)
  527. {
  528.     int ret;
  529.  
  530.     if (ZStreamFunc)
  531.     {
  532.         ZSData.Check = STREAM_CHECK;
  533.         ZSData.Caller = global_caller; // object instance pointer of caller
  534.         try
  535.         {
  536.             ret = ZStreamFunc(&ZSData);  // call user's program
  537.         }
  538.         __except(1)
  539.         {
  540.             Abort_Flag = GA_EXCEPT2;
  541.         }
  542.     }
  543.  
  544.     return ret;
  545. }
  546.  
  547. bool DZOp::Skipping(const DZStrW& fn, int err, int typ)
  548. {
  549.  
  550.         CB->Arg1 = err;
  551.         CB->Arg2 = typ;
  552.         return CB->UserCB(zacSkipped, fn) == CALLBACK_TRUE;
  553. //      int usr = CB->UserCB(zacSkipped, fn);
  554. //      return /*NoSkipping ? true :*/ usr == CALLBACK_TRUE;   //<<
  555. }
  556.  
  557. /*
  558.   Encoded as OEM for
  559.         DOS (default)                       FS_FAT
  560.         OS/2                                FS_HPFS
  561.         Win95/NT with Nico Mak's WinZip     FS_NTFS && host = 5.0
  562.   UTF8 is flag is set
  563.   except (someone always has to be different)
  564.         PKZIP (Win) 2.5, 2.6, 4.0 - mark as FS_FAT but local is Windows ANSI (1252)
  565.         PKZIP (Unix) 2.51 - mark as FS_FAT but are current code page
  566. */
  567. unsigned __fastcall DZOp::IsEncoded(ush made, unsigned utf) const
  568. {
  569. const WZIP = (FS_NTFS * 256) + 50;
  570.         if (fEncodedAs == zeoAuto)
  571.         {
  572.                 if (utf)
  573.                         return zeoUTF8;
  574.  
  575.                 if (!(made & 0xff00) || (made & 0xff00) == 0x0600 || made == WZIP)
  576.                         return zeoOEM; // FAT OS/2 or WinZip 5.0
  577.  
  578.                 return zeoNone;
  579.         }
  580.  
  581.         return fEncodedAs;
  582. }
  583.  
  584. ZFilter::ZFilter(DZStrW &spec)
  585. {
  586.     fspec = spec;
  587.     flevel = 0;
  588.     fnext = NULL;
  589. }
  590.  
  591. ZFilter::~ZFilter()
  592. {
  593.     if (fnext)
  594.         delete fnext;
  595. }
  596.  
  597. bool __fastcall ZFilter::ISEmpty(void) const
  598. {
  599.     return fspec.IsEmpty();
  600. }
  601.  
  602. ZFilter * __fastcall ZFilter::Find(const DZStrW &spec)
  603. {
  604.     ZFilter *l = this;
  605.     if (!l || spec.IsEmpty())
  606.         return NULL;
  607.     while (l)
  608.     {
  609.         if (ZMatch(l->fspec, spec))
  610.             return l;
  611.         l = l->Next;
  612.     }
  613.     return NULL;
  614. };
  615.  
  616.  
  617. PWRec::PWRec(const DZStrA &pw)
  618. {
  619.     fpw = DupStr(pw);
  620.     fnext = NULL;
  621. }
  622.  
  623. PWRec::~PWRec()
  624. {
  625.     delete[] fpw;
  626. }
  627.  
  628. BaseRec::BaseRec(const DZStrW &base)
  629. {
  630.     DZStrW tmp(base);
  631.     TCHAR lc = tmp.LastChar();
  632.  
  633.     if (lc != _T(':') && lc != BSLASH)
  634.         tmp += BSLASH;
  635.  
  636.     fbase = DupStr(tmp);
  637.  
  638.     fnext = NULL;
  639. }
  640.  
  641. BaseRec::~BaseRec()
  642. {
  643.     delete[] fbase;
  644. }
  645.  
  646. DZStrW __fastcall BaseRec::FullPath(const DZStrW& filename) const
  647. {
  648.     if (!Is_DrvEx(filename))
  649.     {
  650.         DZStrW tmp(fbase);
  651.         tmp += filename;
  652.         return tmp;
  653.     }
  654.  
  655.     return filename;
  656. }
  657.  
  658. UserCallback::UserCallback(DZOp *theOwner, bool OpIsZip) : Owner(theOwner)
  659. {
  660.     callb = Owner->callb;
  661.     CBData.HaveWide = 0;
  662.     CBData.Caller = Owner->global_caller; // object instance pointer of caller
  663.     CBData.Version = DZ_VER_VERSION;
  664.     CBData.IsOperationZip = OpIsZip;
  665. }
  666.  
  667. UserCallback::~UserCallback(void)
  668. {
  669.  
  670. }
  671.  
  672. DZStrA __fastcall UserCallback::GetZCmnt(void) const
  673. {
  674.     DZStrA tmp;
  675.     if (CBData.HaveWide == 0)
  676.     {
  677.         const char* p = (const char*)CBData.MsgP;
  678.         if (p && *p)
  679.                 {
  680.             char *buf = tmp.GetBuffer(CBData.Arg1);
  681.             memmove(buf, p, CBData.Arg1);
  682.             tmp.ReleaseBuffer(CBData.Arg1);
  683.         }
  684.     }
  685.     return tmp;
  686. }
  687.  
  688. DZStrW __fastcall UserCallback::RetMsg(const void *_msg) const
  689. {
  690.     DZStrW tmp;
  691.     if (CBData.HaveWide == 1)
  692.     {
  693.         const wchar_t* wp = (const wchar_t*)_msg;
  694.         if (wp && *wp)
  695.             tmp = wp;
  696.         return tmp;
  697.     }
  698.     const char* p = (const char*)_msg;
  699.     if (p && *p)
  700.     {
  701.         if (CBData.HaveWide == 2)
  702.                         tmp = DZStrW(CP_UTF8, p, -1);
  703. //            tmp = UTF8ToStr(p, -1);
  704.         else
  705.             tmp = p;
  706.     }
  707.     return tmp;
  708. }
  709.  
  710. DZStrW __fastcall UserCallback::GetMsg(void) const
  711. {
  712.     return RetMsg(CBData.MsgP);
  713. }
  714.  
  715. void __fastcall UserCallback::SetMsg(const DZStrW& value)
  716. {
  717.     hold = value;
  718.     CBData.MsgP = hold.c_str();
  719. #ifdef UNICODE
  720.     CBData.HaveWide = 1;
  721. #else
  722.     CBData.HaveWide = 0;
  723. #endif;
  724. }
  725.  
  726. DZStrW __fastcall UserCallback::GetMsg2(void) const
  727. {
  728.     return RetMsg(CBData.MsgP2);
  729. }
  730.  
  731. void __fastcall UserCallback::SetMsg2(const DZStrW& value)
  732. {
  733.     hold2 = value;
  734.     CBData.MsgP2 = hold2.c_str();
  735. #ifdef UNICODE
  736.     CBData.HaveWide = 1;
  737. #else
  738.     CBData.HaveWide = 0;
  739. #endif;
  740. }
  741.  
  742.  
  743. /* This provides the calling program with updated info on what the DLL
  744. * is doing.  Regardless of the type of call being made, the user's
  745. * function must have a spin of the Windows message loop.  In fact, even
  746. * if user isn't using a progress bar, he should still spin the msg
  747. * loop upon getting these callbacks (but he doesn't need to do anything
  748. * else).  In Delphi, "Application.ProcessMessages;" or
  749. *         in BCPPB   "Application->ProcessMessages(); spins the loop.
  750. * Here are the types of calls:
  751. *
  752. *
  753. *   ActionCode = 0, zacTick, just roll the loop
  754. *
  755. *   ActionCode = 1, zacItem,
  756. *      we're starting a zip operation on a new file
  757. *   (O) FileSize(u64) = filesize of file we're going to operate on
  758. *   (O) MsgP = pathname of file
  759. *   (O) Written (u64) = [Zip] Bytes written
  760. *   IMPORTANT: The user's function must do the math for the progress
  761. *   bar upon getting this call.  See the Delphi sample application.
  762. *
  763. *   ActionCode = 2, zacProgress,
  764. *      increment the progress bar
  765. *      These calls will occur after every 32K of input file has been
  766. *      processed. One additional call is made at the end of each file,
  767. *      just to make sure the progress bar is max'ed out - this is also
  768. *      critical for files less than 32K in size (this last one will be
  769. *      their only one).
  770. *   (O) FileSize(u64) = filesize of file we're going to operate on
  771. *   (O) Written (u64) = [Zip] Bytes written
  772. *
  773. *   ActionCode = 3, zacEndOfBatch,
  774. *      we're done with a batch of files
  775. *          - program flow will quickly return to the user's program.
  776. *   NOTE: the end of a every file will always be followed by an
  777. *         action of 1 or 3, so a separate call for end of one file
  778. *         isn't needed.
  779. *   (O) Written (u64) = [Zip] Bytes written
  780. *
  781. *   ActionCode = 4, zacComment, a routine message is being passed
  782. *   (O) Arg1 = error_code - code corresponding to message (not widely used yet)
  783. *   (O) MsgP = text of message
  784. *
  785. *   ActionCode = 5, zacCount,
  786. *          the total number of files is being passed.
  787. *   (O) Arg1 = The total number of files.
  788. *
  789. *   ActionCode = 6, zacSize,
  790. *      the total file size is being passed.
  791. *   (O) FileSize (u64) = The total file size
  792. *
  793. *   ActionCode = 7, zacNewName,
  794. *      the internal filename is being passed.
  795. *   (O) MsgP2 = pointer to full filespec
  796. *   (O) MsgP = the internal filename as the dll thinks it should be.
  797. *   (I) ActionCode = -1 if changed
  798. *   (I) MsgP => new internal fileanme
  799. //*   (I) Msg = the new internal filename
  800. *
  801. *   ActionCode = 8, zacPassword,
  802. *      get Password
  803. *   (O) Arg1 = request count
  804. *   (O) MsgP = filename
  805. *   (I) ActionCode = -1 if has password
  806. *       (I) MsgP => password
  807. //*       (I) Msg = password
  808. *       (I) Arg1 = request count
  809. *   (I) ActionCode = -2 if responded 'cancel'
  810. *       (I) Arg1 = request count
  811. *   (I) ActionCode = -3 if responded 'cancel all'
  812. *       (I) Arg1 = request count
  813. *
  814. *   Actioncode = 9, zacCRCError,
  815. *      CRC32 error during Extract
  816. *   (O) Arg1 = Found CRC
  817. *   (O) Arg2 = Stored/Expected CRC
  818. *   (O) MsgP = File for which the CRC check went wrong.
  819. *   (I) ActionCode -1 = extract quietly
  820. *                  -2 = extract with warning [default]
  821. *                  -3 = delete
  822. *
  823. *   Actioncode = 10, zacOverwrite,
  824. *      Extract(UnZip) Overwrite ask.
  825. *   (O) Arg3 = 'older'
  826. *   (O) Arg2 = Index
  827. *   (O) Arg1 = Overwrite_All
  828. *   (O) MsgP = filename
  829. *   (I) ActionCode -1 = overwrite
  830. *          -2 = don't overwrite
  831. *
  832. *   Actioncode = 11, zacSkipped,
  833. *      Skipped during Extract
  834. *   (O) Arg1 = error code
  835. *   (O) Arg2 = type
  836. *   (O) MsgP = filename
  837. *
  838. *   Actioncode = 12, zacComment,
  839. *      FileComment while adding (ZipDll only)
  840. *   (O) MsgP = filename
  841. *   (O) MsgP2 = old comment
  842. *   (I) ActionCode = -1 if comment changed
  843. *       (I) Arg1 = length of new comment
  844. *       (I) MsgP = new comment
  845. //*       (I) Msg = new comment
  846. *
  847. *   Actioncode = 13, zacStream,
  848. *      Adjust unzip stream size
  849. *   (O) FileSize (u64) = required size
  850. *   (I) ActionCode = -1 if ok
  851. *       (I) MsgP = Memory
  852. //*       (I) Msg2P = Memory
  853. *
  854. *   Actioncode = 14, zacData,
  855. *      Set Extra Data  or Compression level
  856. *   (O) Arg1 = size of data
  857. *   (O) Arg2 = Compression level
  858. *   (O) MsgP = filename
  859. *   (O) MsgP2 = pointer to data
  860. *   (I) ActionCode & 0xff0f = 0xff0f if data changed
  861. *       (I) Arg1 = new size of data
  862. *       (I) MsgP => new data (data must remain until next callback)
  863. //*       (I) Msg = new data (< 512 bytes)
  864. //*       (I) MsgP2 = new data (> 512 bytes) (data must remain until next callback)
  865. *   (I) ActionCode &0xff0e = 0xff0e if level changed
  866. *       (I) (ActionCode & 0xf0) >> 4 = new level (0..9)
  867. *
  868. *   ActionCode = 15, zacXItem, we're starting a zip operation on a new file
  869. *   (O) Arg1 = type - 1 = archive bit 2 = move file
  870. *   (O) Filesize = filesize of file we're going to operate on
  871. *   (O) MsgP = pathname of file
  872. *
  873. *   ActionCode = 16, zacXProgress, increment the progress bar
  874. *      These calls will occur after every 32K of input file has been
  875. *      processed. One additional call is made at the end of each file,
  876. *      just to make sure the progress bar is max'ed out - this is also
  877. *      critical for files less than 32K in size (this last one will be
  878. *      their only one).
  879. *   (O) Arg1 = type
  880. *   (O) FileSize (u64) = size
  881. *
  882. *   ActionCode = 17, zacExtName,
  883. *      change extract name
  884. *   (O) MsgP2 = ? null
  885. *   (O) MsgP = filename
  886. *   (I) ActionCode = -1 if changed
  887. *      (I) MsgP => new name
  888. //*      (I) Msg = new name
  889. *
  890. *   ActionCode = 18, zacNone
  891. *
  892. *   ActionCode = 19, zacKey
  893. *      set or clear operation key
  894. *   (O) Arg1 = key
  895. *
  896. *   ActionCode = 20, zacArg
  897. *      Get string argument
  898. *
  899. *   ActionCode = 21, zacWinErr
  900. *      report windows error
  901. *   (O) Arg1 = Operation
  902. *   (O) Arg2 = Error code
  903. *   (O) MsgP = target filespec
  904. *   (I) return = 0, give error then abort (default)
  905. *              = 1, abort without error
  906. *              = 2, retry - presume error fixed
  907. *
  908. */
  909.  
  910. /* ===========================================================================
  911.  * This calls the application program and passes status info.
  912.  */
  913. int __fastcall UserCallback::UserCB(unsigned Action)
  914. {
  915.     int ret;
  916. //    OutputDebugString(L"UserCB - IN");
  917.  
  918.     if (callb && Abort_Flag <= GA_ABORT)
  919.     {
  920.         CBData.Written = Owner->fBytesWritten;
  921. #ifdef UNICODE
  922.         CBData.HaveWide = 1;
  923. #else
  924.         CBData.HaveWide = 0;
  925. #endif;
  926.         CBData.ActionCode = Action;
  927.         CBData.check = CALLBACK_CHECK;
  928.         try
  929.         {
  930.             ret = callb(&CBData);  // call user's program
  931.         }
  932.         __except(1)
  933.         {
  934.             Abort_Flag = GA_EXCEPT2;
  935.             ret = CALLBACK_EXCEPTION;
  936.     OutputDebugString(L"UserCB - exception");
  937.         }
  938.  
  939.         if (ret < CALLBACK_IGNORED)
  940.         {
  941.             switch (ret)
  942.             {
  943.  
  944.                 case CALLBACK_CANCEL:
  945.                     Abort_Flag |= GA_CANCEL;
  946.                     break;
  947.  
  948.                 case CALLBACK_ABORT:
  949.                     Abort_Flag |= GA_CANCEL;
  950.                     break;
  951.  
  952.                 case CALLBACK_EXCEPTION:
  953.                     Abort_Flag |= GA_EXCEPT;
  954.             }
  955.         }
  956.     }
  957.  
  958.         hold.Empty();
  959.     hold2.Empty();
  960. //    OutputDebugString(L"UserCB - OUT");
  961.     return ret;
  962. }
  963.  
  964. int __fastcall UserCallback::UserCB(unsigned Action, const DZStrW& msg)
  965. {
  966.     Msg = msg;
  967.     return UserCB(Action);
  968. }
  969.  
  970. int UserCallback::UserCB(unsigned Action, const DZStrW& msg, const DZStrW& msg2)
  971. {
  972.     Msg2 = msg2;
  973.     Msg = msg;
  974.     return UserCB(Action);
  975. }
  976.  
  977. int __fastcall UserCallback::UserMsg(int err, const DZStrW& msg)
  978. {
  979.     CBData.Arg1 = err;    // error
  980.     return UserCB(zacMessage, msg);
  981. }
  982.  
  983. int __fastcall UserCallback::UserProgress(__int64 adv)
  984. {
  985.     CBData.FileSize = adv;
  986.     return UserCB(zacProgress);
  987. }
  988.  
  989. int UserCallback::UserItem(__int64 cnt, const DZStrW& msg)
  990. {
  991.     CBData.FileSize = cnt;
  992.     return UserCB(zacItem, msg);
  993. }
  994.  
  995. int UserCallback::UserXProgress(__int64 adv, int typ)
  996. {
  997.     CBData.Arg1 = typ;    // type
  998.     CBData.FileSize = adv;
  999.     return UserCB(zacXProgress);
  1000. }
  1001.  
  1002. int UserCallback::UserXItem(__int64 cnt, int typ, const DZStrW& msg)
  1003. {
  1004.     CBData.Arg1 = typ;
  1005.     CBData.FileSize = cnt;
  1006.     return UserCB(zacXItem, msg);
  1007. }
  1008.  
  1009. DZStrW UserCallback::UserArg(int arg, int idx, int *cnt)
  1010. {
  1011.     DZStrW tmp;
  1012.     bool raw = arg > 0x1f;
  1013.  
  1014.     if (raw)
  1015.         arg &= 0x1f;
  1016.  
  1017.     CBData.Arg1 = arg;    // type
  1018.     CBData.Arg3 = idx;
  1019.     int r = UserCB(zacArg);
  1020.     if (r >= CALLBACK_UNHANDLED)
  1021.     {
  1022.         if (cnt && (arg == zcbFSpecArgs || arg == zcbFSpecArgsExcl))
  1023.             *cnt = CBData.Arg3;
  1024.  
  1025.         if (r == CALLBACK_TRUE)
  1026.         {
  1027.             tmp = Msg;
  1028.             if (!raw)
  1029.             {
  1030.                 tmp.TrimLeft();  // trim trailing unless password
  1031.  
  1032.                 if (arg != zcbPassword && !tmp.Find(ZPasswordFollows))
  1033.                     tmp.TrimRight();
  1034.             }
  1035.         }
  1036.     }
  1037.  
  1038.     return tmp;
  1039. }
  1040.  
  1041. DZStrA UserCallback::UserZCmnt(void)
  1042. {
  1043.     DZStrA tmp;
  1044.     CBData.Arg1 = zcbComment;    // type
  1045.     CBData.Arg3 = 0;
  1046.     int r = UserCB(zacArg);
  1047.     if (r == CALLBACK_TRUE)
  1048.     {
  1049.         tmp = GetZCmnt();
  1050.     }
  1051.  
  1052.     return tmp;
  1053. }
  1054.  
  1055. void __cdecl  DZOp::Notify(unsigned err, const TCHAR* szFmt, ...)
  1056. {
  1057.     DZStrW ret;
  1058.     va_list argList;
  1059.     va_start(argList, szFmt);
  1060.     ret.FormatV(szFmt, argList);
  1061.     va_end(argList);
  1062.     if (!ret.IsEmpty())
  1063.         SendInfo(err, ret);
  1064. }
  1065.  
  1066. DZStrW DZOp::ConvExclFilters(const DZStrW & filters)
  1067. {
  1068.     DZStrW exc;
  1069.     if (filters.IsEmpty())
  1070.         return exc;
  1071.     int n = 0;
  1072.     if (filters[0] == _T('|'))
  1073.     {
  1074.                 exc = _T("|");
  1075.         n++;
  1076.     }
  1077.     int len = filters.length();
  1078.     while (n < len)
  1079.     {
  1080.         int nx = filters.Find(_T('|'), n+1);
  1081.         if (nx < 0)
  1082.             nx = len + 1;
  1083.         DZStrW comp = filters.Mid(n, nx - n);
  1084.         n = nx + 1;
  1085.         comp.Trim();
  1086.                 DZStrW p = ex2IntForm(comp, true);
  1087.  
  1088.         if (!p.IsEmpty())
  1089.         {
  1090.             if (!exc.IsEmpty())
  1091.                 exc += _T('|');
  1092.             exc += p;
  1093.         }
  1094.     }
  1095.     return exc;
  1096. }
  1097.  
  1098. DZStrW DZOp::MakeExclFilters(void)
  1099. {
  1100.     DZStrW exc;
  1101.     int n = 0;
  1102.     while (true)
  1103.     {
  1104.         DZStrW arg = CB->UserArg(zcbFSpecArgsExcl, n, 0);
  1105.  
  1106.         if (arg.IsEmpty())
  1107.             break;
  1108.  
  1109.         if (!exc.IsEmpty())
  1110.             exc += _T('|');
  1111.         exc += arg;
  1112.         n++;
  1113.     }
  1114.  
  1115.         return ConvExclFilters(exc);
  1116. }
  1117.  
  1118.  
  1119. // Convert the external file name to an "internal" file name form,
  1120. //   returning the malloc'ed string, or NULL if not enough memory.
  1121. //   I.e. Strip the drive if present, strip the path
  1122. //if we
  1123. //   don't want one and change the name to 8.3 if needed. Not implemented, but
  1124. //   also 'put in' change the short path to a long path.
  1125. DZStrW DZOp::ex2IntForm(const DZStrW &exname, bool ignore)
  1126. {
  1127.     bool  pathput;
  1128.  
  1129.     if (ignore)
  1130.         {
  1131.         pathput = true;
  1132.     }
  1133.     else
  1134.         {
  1135.         pathput = fpathput;
  1136.     }
  1137.  
  1138.         DZStrW XName(exname);
  1139.  
  1140.     if (XName.IsEmpty())
  1141.         return XName;
  1142.  
  1143.         DZStrW nname = StrExtSep(XName);
  1144.     int p = DriveLen(nname);
  1145.  
  1146.     int len = nname.length();
  1147.     // Strip leading "\" to convert an absolute path into a relative path
  1148.  
  1149.     while (p < len && nname[p] == BSLASH)
  1150.         p++;
  1151.  
  1152.     // Strip leading "./" as well as drive letter v1.6017
  1153.     while ((p + 2) < len && (nname[p] == _T('.') && nname[p + 1] == BSLASH))
  1154.         p += 2;
  1155.  
  1156.     // This is where the dirname gets stripped if user doesn't want it
  1157.     if (!pathput)
  1158.     {
  1159.         int t = nname.ReverseFind(BSLASH);
  1160.  
  1161.         if (t >= p)
  1162.             p = ++t;
  1163.     }
  1164.  
  1165.     if (p)
  1166.     {
  1167.         nname = nname.Mid(p);
  1168.     }
  1169.  
  1170.     if (nname.length() > MAX_PATH)
  1171.     {
  1172.         int t = nname.length();
  1173.         XName = nname.Left(MAX_PATH);
  1174.  
  1175.         if (Verbose) // < 0)
  1176.             Notify(IWARNING, _T("File name %s is too long [%d]. Truncated to %s"),
  1177.                    nname.c_str(), t, XName.c_str());
  1178.  
  1179.         nname = XName;
  1180.     }
  1181.  
  1182.     return nname;
  1183. }
  1184.  
  1185.