Subversion Repositories autosfx

Rev

Blame | Last modification | View Log | RSS feed

  1. #include "stdafx.h"
  2. #pragma hdrstop
  3. //#include <windows.h>
  4.  
  5. /* ZStrings.cpp
  6.  Copyright (C) 2009, 2010  by Russell J. Peters, Roger Aelbrecht
  7.  
  8.    This file is part of TZipMaster Version 1.9.
  9.  
  10.     TZipMaster is free software: you can redistribute it and/or modify
  11.     it under the terms of the GNU Lesser General Public License as published by
  12.     the Free Software Foundation, either version 3 of the License, or
  13.     (at your option) any later version.
  14.  
  15.     TZipMaster is distributed in the hope that it will be useful,
  16.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  17.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18.     GNU Lesser General Public License for more details.
  19.  
  20.     You should have received a copy of the GNU Lesser General Public License
  21.     along with TZipMaster.  If not, see <http://www.gnu.org/licenses/>.
  22.  
  23.     contact: problems@delphizip.org (include ZipMaster in the subject).
  24.     updates: http://www.delphizip.org
  25.     DelphiZip maillist subscribe at http://www.freelists.org/list/delphizip
  26. ************************************************************************/
  27.  
  28. #include "delzip.h"
  29. //#include "common.h"
  30. #include "ZStrings.h"
  31. #include "dz_errs.h"
  32.  
  33. #undef _DZ_FILE_
  34. #define _DZ_FILE_ DZ_ZSTRINGS_CPP
  35. //---------------------------------------------------------------------------
  36.  
  37. DZStrW __fastcall StrIncSep(const DZStrW &p)
  38. {
  39.     if (!p.IsEmpty() && p.LastChar() != _T('\\') && p.LastChar() != _T(':'))
  40.         return p + _T('\\');
  41.  
  42.     return p;
  43. }
  44.  
  45. DZStrW __fastcall StrExcSep(const DZStrW &p)
  46. {
  47.     if (!p.IsEmpty() && p.LastChar() == _T('\\'))
  48.         return p.Left(p.length() - 1);
  49.  
  50.     return p;
  51. }
  52.  
  53. DZStrW __fastcall StrIntSep(const DZStrW &str)
  54. {
  55.     DZStrW tmp(str);
  56.     if (!str)
  57.         return tmp;
  58.     wchar_t *buf = tmp.GetBuffer();
  59.     while (*buf)
  60.     {
  61.         if (*buf == L'\\')
  62.             *buf = L'/';
  63.         buf++;
  64.     }
  65.     return tmp;
  66. }
  67.  
  68. DZStrA __fastcall StrIntSep(const DZStrA &str)
  69. {
  70.     DZStrA tmp(str);
  71.     if (!str)
  72.         return tmp;
  73.     char *buf = tmp.GetBuffer();
  74.     while (*buf)
  75.     {
  76.         if (*buf == '\\')
  77.             *buf = '/';
  78.         buf++;
  79.     }
  80.     return tmp;
  81. }
  82.  
  83. DZStrW __fastcall StrExtSep(const DZStrW &str)
  84. {
  85.     DZStrW tmp(str);
  86.     if (!str)
  87.         return tmp;
  88.     wchar_t *buf = tmp.GetBuffer();
  89.     while (*buf)
  90.     {
  91.         if (*buf == L'/')
  92.             *buf = L'\\';
  93.         buf++;
  94.     }
  95.     return tmp;
  96. }
  97.  
  98. DZStrA __fastcall StrExtSep(const DZStrA &str)
  99. {
  100.     DZStrA tmp(str);
  101.     if (!str)
  102.         return tmp;
  103.     char *buf = tmp.GetBuffer();
  104.     while (*buf)
  105.     {
  106.         if (*buf == '/')
  107.             *buf = '\\';
  108.         buf++;
  109.     }
  110.     return tmp;
  111. }
  112.  
  113. //DZStrA __fastcall StrSafe(const DZStrA &str)
  114. //{
  115. //    DZStrA tmp(str);
  116. //    if (!str)
  117. //        return tmp;
  118. //    char *buf = tmp.GetBuffer();
  119. //    while (*buf)
  120. //    {
  121. //        if (*buf < 0x20)
  122. //            *buf = '_';
  123. //        if (Is_InA("<>|:;*?\"\'", *buf))
  124. //            *buf = '_';
  125. //        buf++;
  126. //    }
  127. //    return tmp;
  128. //}
  129.  
  130.  
  131.  
  132. const char hx[16] = "0123456789ABCDEF";
  133.  
  134. DZStrA __fastcall toHex(unsigned val, unsigned cnt)
  135. {
  136.     DZStrA tmp;
  137.     char* bp = tmp.GetBuffer(cnt) + cnt;
  138.     int x = cnt;
  139.     while (val && x-- > 0)
  140.     {
  141.         *--bp = hx[val & 0x0f];
  142.         val >>= 4;
  143.     }
  144.     while (x-- > 0)
  145.         *--bp = '0';
  146.     tmp.ReleaseBuffer(cnt);
  147.     return tmp;
  148. }
  149.  
  150. DZStrA __fastcall StrToOEM(const DZStrW &str)
  151. {
  152.     DZStrA ret;
  153.  
  154. //    if (!HasExtended(str))
  155.         if (!str.BadDOS())
  156.     {
  157.         ret = str;
  158.         return ret;
  159.     }
  160.  
  161.     DZStrW s(str);
  162.  
  163. //    int mx = 3 + str.length() * 4;   // allow worst case - all double
  164.     CharToOem(s, ret.GetBuffer(s.length()));
  165.     ret.ReleaseBuffer();
  166.     return ret;
  167. }
  168.  
  169. DZStrA __fastcall StrToOEM(const DZStrA &str)
  170. {
  171.     DZStrA ret;
  172.  
  173. //    if (!HasExtended(str))
  174.         if (!str.BadDOS())
  175.     {
  176.         ret = str;
  177.         return ret;
  178.     }
  179.  
  180.     DZStrW s(str);
  181.  
  182. //    int mx = 3 + s.length() * 4;   // allow worst case - all double
  183.     CharToOem(s, ret.GetBuffer(s.length()));
  184.     ret.ReleaseBuffer();
  185.     return ret;
  186. }
  187.  
  188. DZStrA __fastcall StrToUTF8(const DZStrW &str)
  189. {
  190.     DZStrA ret;
  191.     //  Convert to required
  192.     int cnt = WideCharToMultiByte(CP_UTF8, 0, str, str.length(), NULL, 0, NULL, NULL);
  193.  
  194.     if (cnt < 1)
  195.         return ret;  // invalid
  196.     char* bf = ret.GetBuffer(cnt);
  197.     cnt = WideCharToMultiByte(CP_UTF8, 0, str, str.length(), bf, cnt, NULL, NULL);
  198.     bf[cnt] = 0;
  199.     ret.ReleaseBuffer();
  200.  
  201.     if (cnt < 1)
  202.         ret.Empty();
  203.  
  204.     return ret;
  205. }
  206.  
  207. //DZStrW __fastcall ToStrW(const char *str, int len, UINT cp)
  208. //{
  209. //    DZStrW retval;
  210. //
  211. //    // convert to Unicode
  212. //    int wcnt = MultiByteToWideChar(cp, 0, str, len, NULL, 0);
  213. //
  214. //    if (wcnt > 0)
  215. //    {
  216. //        wchar_t *bf = retval.GetBuffer(wcnt);
  217. //        wcnt = MultiByteToWideChar(cp, 0, str, len, bf, wcnt);
  218. //        bf[wcnt] = 0;
  219. //        retval.ReleaseBuffer();
  220. //    }
  221. //
  222. //    if (wcnt < 1)
  223. //        retval.Empty();
  224. //
  225. //    return retval;
  226. //}
  227.  
  228.  
  229. //DZStrW __fastcall UTF8ToStr(const char *str, int len)
  230. //{
  231. ////    return ToStrW(str, len, CP_UTF8);
  232. //      return DZStrW(CP_UTF8, str, len);
  233. //}
  234.  
  235.  
  236. DZStrW __fastcall OEMToStr(const char *str)
  237. {
  238.     DZStrW tmp;
  239.     OemToChar(str, tmp.GetBuffer(strlen(str) * 5));
  240.     tmp.ReleaseBuffer();
  241.     DZStrW ret = tmp;
  242.     return ret;
  243. }
  244. /*
  245. bool __fastcall HasExtended(const TCHAR* str)
  246. {
  247.     TCHAR c;
  248.     if (!str)
  249.         return false;
  250.  
  251.     for (const TCHAR* p = str; *p; p++)
  252.         if ((c = *p) < 0x20 || (c > 0x7e))
  253.             return true;
  254.  
  255.     return false;
  256. }
  257.  
  258. bool __fastcall HasExtended(const DZStrA& str)
  259. {
  260.     char c;
  261.     if (!str)
  262.         return false;
  263.  
  264.     for (const char* p = str.c_str(); *p; p++)
  265.         if ((c = *p) < 0x20 || (c > 0x7e))
  266.             return true;
  267.  
  268.     return false;
  269. }
  270.  
  271. bool __fastcall HasExtended(const DZStrW& str)
  272. {
  273.     wchar_t c;
  274.  
  275.     if (!str)
  276.         return false;
  277.     for (const wchar_t* p = str.c_str(); *p; p++)
  278.         if ((c = *p) < 0x20 || (c > 0x7e))
  279.             return true;
  280.  
  281.     return false;
  282. }
  283. */
  284. int __fastcall UTF8SeqLen(char u8)
  285. {
  286.     if (u8 >= 0) //< 0x80)
  287.         return 0;
  288.  
  289.     if (((unsigned char)u8 & 0xFE) == 0xFC)
  290.         return 6;
  291.  
  292.     if (((unsigned char)u8 & 0xFC) == 0xF8)
  293.         return 5;
  294.  
  295.     if (((unsigned char)u8 & 0xF8) == 0xF0)
  296.         return 4;
  297.  
  298.     if (((unsigned char)u8 & 0xF0) == 0xE0)
  299.         return 3;
  300.  
  301.     if (((unsigned char)u8 & 0xE0) == 0xC0)
  302.         return 2;
  303.  
  304.     return -1;  // trailing byte - invalid
  305. }
  306. /*
  307. // test for valid UTF8 character(s)  > 0 _ some, 0 _ none, < 0 _ invalid
  308. int __fastcall ValidUTF8(const char *str, int len)
  309. {
  310.     int ret = 0;
  311.     char ch;
  312.  
  313.     if (len < 0)
  314.         len = strlen(str);
  315.  
  316.     int i = 0;
  317.  
  318.     while (i++ < len)
  319.     {
  320.         if ((ch = *str++) == 0)
  321.             return -2;
  322.  
  323.         int ul = UTF8SeqLen(ch);
  324.  
  325.         if (ul)
  326.         {
  327.             if (ul < 0)
  328.                 return -1;
  329.  
  330.             // first in seq
  331.             while (i++ < len && ul-- > 1)
  332.             {
  333.                 if ((*(const unsigned char*)str++ & 0xC0) != 0x80)
  334.                     return -1;
  335.             }
  336.  
  337.             ret++;
  338.         }
  339.     }
  340.  
  341.     return ret;
  342. }
  343.  */
  344. // test for valid UTF8 character(s)  > 0 _ some, 0 _ none, < 0 _ invalid
  345. int __fastcall ValidUTF8(const DZStrA &str)
  346. {
  347.         int ret = 0;
  348.         char ch;
  349.  
  350.         if (!str)
  351.                 return 0;//ret;
  352. //      return ValidUTF8(str.c_str());
  353.         const char* p = str.c_str();
  354.     const char* endp = p + str.length();
  355.  
  356.     while (p < endp)
  357.     {
  358.         if ((ch = *p++) == 0)
  359.             return -1;      // invalid
  360.  
  361.         int ul = UTF8SeqLen(ch);
  362.  
  363.         if (ul)
  364.         {
  365.             if (ul < 0)
  366.                 return -1;
  367.  
  368.             // first in seq
  369.             while (ul-- > 1)
  370.             {
  371.                 if (p >= endp)
  372.                     return -1;
  373.  
  374.                 ch = *p++;
  375.                 if (((unsigned char)ch & 0xC0) != 0x80)
  376.                     return -1;
  377.             }
  378.  
  379.             ret++;
  380.         }
  381.     }
  382.  
  383.         return ret;
  384. }
  385.  
  386.  
  387. // return >0 has drive, 0 no drive, -1 stream, -2 autostream
  388. int __fastcall Is_Drv(const DZStrW &spec)
  389. {
  390.     if (spec.length() < 2)
  391.         return 0;
  392.  
  393.     int colon = spec.Find(_T(':'));
  394.     if (colon < 1)
  395.         return 0;
  396.  
  397.     TCHAR c = spec[0];
  398.     if (colon == 1 && _istalpha(c))
  399.       return 1;
  400.  
  401.     int sno = 0;
  402.     for (int i = 0; i < colon; i++)
  403.     {
  404.         if (!_istdigit(spec[i]))
  405.             return 0; // invalid
  406.         sno = (sno * 10) + (spec[i] & 15);
  407.     }
  408.     return -(sno + 2);
  409. }
  410.  
  411. // return >0 has drive, 0 no drive, -1 stream, -2 autostream
  412. int __fastcall Is_DrvEx(const DZStrW &spec)
  413. {
  414.     int r = Is_Drv(spec);
  415.  
  416.     if (r)
  417.         return r;
  418.  
  419.     if (spec.length() >= 2)
  420.     {
  421.         TCHAR c = spec[0];
  422.  
  423.         if ((c == BSLASH && spec[1] == BSLASH) ||
  424.                 (c == SLASH && spec[1] == SLASH))
  425.             return 2;
  426.     }
  427.  
  428.     return 0;
  429. }
  430.  
  431. const TCHAR * __fastcall Is_In(const TCHAR *p, TCHAR c)
  432. {
  433.     for (; *p; p++)
  434.     {
  435.         if (*p == c)
  436.             return p;
  437.     }
  438.  
  439.     return NULL;
  440. }
  441.  
  442. const char * __fastcall Is_InA(const char *p, char c)
  443. {
  444.     for (; *p; p++)
  445.     {
  446.         if (*p == c)
  447.             return p;
  448.     }
  449.  
  450.     return NULL;
  451. }
  452.  
  453. //const int Z_BAD_DRIVE = 1;
  454. //const int Z_BAD_SEP = 2;
  455. //const int Z_BAD_SPACE = 4;      // lead/trail space
  456. //const int Z_BAD_CLEN = 8;       // component too long
  457. //const int Z_BAD_CHAR = 16;      // invalid char
  458. //const int Z_BAD_PARENT = 32;    // attempt to back below root
  459. int __fastcall CheckComponent(const DZStrW& c)
  460. {
  461.     int clen = c.length();
  462.  
  463.     if (clen < 1)
  464.         return Z_BAD_SEP;
  465.  
  466.     if (_istspace(c[0]) || _istspace(c.LastChar()))
  467.         return Z_BAD_SPACE;      // leading/trailing blanks not allowed
  468.  
  469.     if (clen > 255) //= MAX_PATH-3)
  470.         return Z_BAD_CLEN;
  471.  
  472. #ifdef UNICODE
  473.     for(int i=0;i<clen;i++)
  474.         if (c[i] < ' ')
  475.             return Z_BAD_CHAR;
  476. #else
  477.     for(int i=0;i<clen;i++)
  478.         if (c[i] < ' ' && c[i] >= 0)
  479.             return Z_BAD_CHAR;
  480. #endif
  481.  
  482.     if (c.FindOneOf(_T("<>:\"|"))  >= 0)
  483.         return Z_BAD_CHAR;
  484.  
  485.     if (!c.Compare(_T(".")))
  486.         return Z_IS_THIS;
  487.  
  488.     if (!c.Compare(_T("..")))
  489.         return Z_IS_PARENT;
  490.  
  491. //    if (c.Find(_T("..")) >= 0)
  492. //        return Z_BAD_CHAR;
  493.  
  494.     if (Is_In(_T("AaCcLlNnPp"), c[0]))
  495.     {
  496.         // check invalid names
  497.         int dt = c.Find(DOT);
  498.  
  499.         if (clen >= 3 && (dt > 3 || dt < 0))
  500.         {
  501.             DZStrW bads(_T("COM,LPT,AUX,CON,NUL,PRN"));
  502.             DZStrW f3(c, 3);
  503.             f3.ToUpper();
  504.             int m = bads.Find(f3);
  505.  
  506.             if (m >= 0 && !(m & 3))
  507.             {
  508.                 // starts with bad
  509.                 if (m > 7 && (clen == 3 || c[3] == DOT))
  510.                     return Z_BAD_NAME;
  511.  
  512.                 if (clen > 3 && Is_In(_T("123456789"), c[3]) &&
  513.                         (clen == 4 || c[4] == DOT))
  514.                     return Z_BAD_NAME;
  515.             }
  516.         }
  517.     }
  518.  
  519.     return 0; // good
  520. }
  521.  
  522. int __fastcall CleanPath(const DZStrW& pathin, DZStrW& pathout)
  523. {
  524.     int posn = DriveLen(pathin);
  525.  
  526.     if (posn < 0)
  527.         return Z_BAD_DRIVE;
  528.  
  529.     pathout = pathin.Left(posn);
  530.  
  531. //      if (posn > 2)
  532.                 pathout = StrExtSep(pathout);
  533. //    else
  534. //    {
  535.                 TCHAR ch = pathin[posn];
  536.  
  537.                 if (ch == BSLASH || ch == SLASH)
  538.         {
  539.             pathout += BSLASH;
  540.             posn++;
  541.         }
  542. //    }
  543.  
  544.     int len = pathin.length();
  545.  
  546.     if (len < 1)
  547.         return 0;
  548.  
  549.         int root = pathout.length() - 1;
  550.         int components = 0;
  551.  
  552.     while (posn < len)
  553.     {
  554.                 // find end of component
  555.                 int eoc = pathin.FindOneOf(_T("\\/"), posn);
  556.         DZStrW c;
  557.  
  558.         if (eoc < 0)
  559.             c = pathin.Mid(posn);  // rest of string
  560.         else
  561.         {
  562.             c = pathin.Mid(posn, eoc - posn);
  563.             posn = eoc + 1;    // next component
  564.         }
  565.  
  566.         int r = CheckComponent(c);
  567.                 if (r == Z_IS_THIS && !components)
  568.                         r = 0;
  569.  
  570.         if (r < 0)
  571.         {
  572.             if (r > Z_BAD_PARENT)
  573.                 return r;   // bad
  574.  
  575.                         if (r == Z_IS_THIS)
  576.                                 continue;   // '.'
  577.  
  578.             // backup
  579.             int pc = pathout.ReverseFind(BSLASH, pathout.length() - 2);
  580.  
  581.                         if (pc < 0 && pathout[root] != BSLASH)
  582.                 pc = root;
  583.  
  584.             if (pc < root)
  585.                 return Z_BAD_PARENT;
  586.  
  587.             pathout = pathout.Left(pc + 1);   // truncate
  588.             continue;
  589.         }
  590.  
  591.         pathout += c;
  592.  
  593.         if (eoc < 0)
  594.             break;
  595.  
  596.                 pathout += BSLASH;
  597.                 components++;
  598.     }
  599.  
  600.     if (pathout.FindOneOf(_T("*?")) >= 0)
  601.     {
  602.         return Z_WILD;
  603.     }
  604.  
  605.     return 0;
  606. }
  607.  
  608. // return length drive or //host/share/   return < 0 if invalid
  609. int __fastcall DriveLen(const DZStrW &fspec)
  610. {
  611.     int d = Is_DrvEx(fspec);
  612.  
  613.     if (d == 1)
  614.         return 2;
  615.  
  616.     if (!d)
  617.         return 0;
  618.  
  619.     if (d == -1)
  620.         return 2; // default stream
  621.  
  622.     if (d < 0)
  623.     {   // stream
  624.         d = 0;
  625.         while (_istdigit(fspec[d]))
  626.           d++;
  627.                 return fspec[d] == ':' ? d + 1 : 0;
  628.     }
  629.  
  630.     TCHAR c = fspec[0];
  631.     int eoh = fspec.Find(c, 2);
  632.  
  633.     if (eoh < 0)
  634.         return -1;  // invalid
  635.  
  636.     if (eoh == 4 && fspec[2] == _T('?'))
  637.     {
  638.         eoh = fspec.Find(c, 2);
  639.  
  640.                 if (eoh < 0)
  641.             return 4;  // nothing follows
  642.     }
  643.  
  644.     // find end of host
  645.     int eos = fspec.Find(c, eoh + 1);
  646.  
  647.     if (eos < 0)
  648.         return 0;//-2;  // no share
  649.  
  650. //      return ++eos; // count trailing slash
  651.         return eos; // don't count trailing slash
  652. }
  653.  
  654. DWORD __fastcall GetFileAttrs(const DZStrW& p)
  655. {
  656.     WIN32_FIND_DATA fdata;
  657.     HANDLE          fh;
  658.     DWORD           ret = -1; // no_file indicator
  659.  
  660.     fh = FindFirstFile(p, &fdata);
  661.  
  662.     if (fh != INVALID_HANDLE_VALUE)
  663.     {
  664.         ret = fdata.dwFileAttributes;
  665.         FindClose(fh);
  666.     }
  667.  
  668.     return ret;
  669. }
  670.  
  671. bool __fastcall IsWild(const DZStrW& p)
  672. {
  673.     int t = p.FindOneOf(_T("?*"));
  674.     return t >= 0;
  675. }
  676.  
  677. bool __fastcall Is_AbsPath(const DZStrW& pth)
  678. {
  679.     return Is_DrvEx(pth) == 0;
  680. }
  681. TCHAR __fastcall LastChar(const TCHAR *p)
  682. {
  683.     TCHAR ret = 0;
  684.  
  685.     if (p)
  686.     {
  687.         for (; *p; p = _tcsinc(p))
  688.             ret = *p;
  689.     }
  690.  
  691.     return ret;
  692. }
  693.  
  694. const char* DupStr(const DZStrA& from)
  695. {
  696.     char *tmp = NULL;
  697.  
  698.     if (!from.IsEmpty())
  699.     {
  700.         tmp = new char[from.length()+1];
  701.         strcpy(tmp, from.c_str());
  702.     }
  703.  
  704.     return tmp;
  705. }
  706.  
  707. const wchar_t* DupStr(const DZStrW& from)
  708. {
  709.     wchar_t* tmp = NULL;
  710.  
  711.     if (!from.IsEmpty())
  712.     {
  713.         tmp = new wchar_t[from.length()+1];
  714.         wcscpy(tmp, from.c_str());
  715.     }
  716.  
  717.     return tmp;
  718. }
  719.  
  720. DZStrW __fastcall GetArg(const DZStrW &CmdLine, unsigned &idx, bool AllowPW)
  721. {
  722.         DZStrW ret;
  723.         TCHAR ch;
  724.         if (CmdLine.IsEmpty() || idx >= CmdLine.length())
  725.                 return ret;
  726.         int Spaces = 0;
  727.         const TCHAR *first = CmdLine.c_str() + idx;
  728.         const TCHAR *start = first;
  729.         const TCHAR *cmd = first;
  730.         while (*cmd <= _T(' ') && *cmd)
  731.                 cmd = CharNext(cmd);
  732.   // advance to next, find the length ignoring trailing space
  733.         while ((ch = *cmd) != 0)
  734.         {
  735.                 if (ch == _T('/') && Spaces)
  736.                         break;  // at next switch
  737.                 if (AllowPW && ch == ZPasswordFollows)
  738.                         break;  // at next (Comment)
  739.                 if (ch <= ' ')
  740.                 {
  741.                         cmd = CharNext(cmd);
  742.                         Spaces++;
  743.                         continue;
  744.                 }
  745.  
  746.                 if (ch == '"')
  747.                 {
  748.                         // copy previous
  749.                         ret.Append(start, cmd - start);
  750.                         start = cmd;
  751.                         start++; // past leading quote
  752.                         // find end of quote
  753.                         do
  754.                         {
  755.                                 cmd = CharNext(cmd);
  756.                         }while (*cmd != _T('"') && *cmd);
  757.                         // copy between quotes
  758.                         ret.Append(start, cmd - start);
  759.  
  760.                         start = ++cmd;    // end quote
  761.                         Spaces = 0;
  762.                         continue;
  763.                 }
  764.  
  765.                 // just a character
  766.                 cmd = CharNext(cmd);
  767.                 Spaces = 0;
  768.         }
  769.         // copy previous
  770.         const TCHAR *lastchar = cmd;
  771.         lastchar -= Spaces;
  772.         if (lastchar > start)
  773.           ret.Append(start, lastchar - start);
  774.         idx += cmd - first;
  775.  
  776.         return ret;
  777. }
  778.  
  779. bool __fastcall DirExists(const DZStrW& path)
  780. {
  781.         if (path.IsEmpty())
  782.                 return true;
  783.         DWORD Code = ::GetFileAttributes(path.c_str());
  784.         return (Code != (unsigned)-1) && (FILE_ATTRIBUTE_DIRECTORY & Code);
  785. }
  786.  
  787. DZStrW __fastcall ExtractFilePath(const DZStrW path)
  788. {
  789.         int npos = path.ReverseFind(BSLASH);
  790.         DZStrW ret;
  791.         if (npos > 0)
  792.         {
  793.                 ret = path.Left(npos);
  794.         }
  795.         return ret;
  796. }
  797.  
  798. bool __fastcall ForceDirectories(const DZStrW Dir, int minlen)
  799. {
  800.         // never go below the root or server
  801.         if (minlen < 3)
  802.         {
  803.                 minlen = DriveLen(Dir);
  804.                 if (minlen > 0 && Dir[minlen] == BSLASH)
  805.                         minlen++;
  806.                 if (minlen < 3)
  807.                         minlen = 3;
  808.         }
  809.         DZStrW sDir = StrExcSep(Dir);
  810.         if (sDir.length() < (unsigned)minlen || DirExists(sDir))
  811.                 return true;
  812.         DZStrW parent = ExtractFilePath(sDir);
  813.         if (parent == sDir)
  814.                 return true; // avoid 'c:\xyz:\' problem.
  815.         if (!ForceDirectories(parent, minlen))
  816.                 return false;
  817.         // return true;
  818.         return CreateDirectory(sDir.c_str(), NULL);
  819. }
  820.  
  821.