Subversion Repositories autosfx

Rev

Blame | Last modification | View Log | RSS feed

  1. #include "stdafx.h"
  2. #pragma hdrstop
  3.  
  4. #include "DZ_StrW.h"
  5. #include <stdio.h>
  6. #include <tchar.h>
  7. //#include "common.h"
  8. #include "dz_errs.h"
  9. #include "DivMod64.h"
  10.  
  11. #undef _DZ_FILE_
  12. #define _DZ_FILE_ DZ_DZ_STRW_CPP
  13.  
  14. /* DZ_StrW.cpp
  15. ************************************************************************
  16.  Copyright (C) 2009, 2010  by Russell J. Peters, Roger Aelbrecht
  17.  
  18.    This file is part of TZipMaster Version 1.9.
  19.  
  20.     TZipMaster is free software: you can redistribute it and/or modify
  21.     it under the terms of the GNU Lesser General Public License as published by
  22.     the Free Software Foundation, either version 3 of the License, or
  23.     (at your option) any later version.
  24.  
  25.     TZipMaster is distributed in the hope that it will be useful,
  26.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  27.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  28.     GNU Lesser General Public License for more details.
  29.  
  30.     You should have received a copy of the GNU Lesser General Public License
  31.     along with TZipMaster.  If not, see <http://www.gnu.org/licenses/>.
  32.  
  33.     contact: problems@delphizip.org (include ZipMaster in the subject).
  34.     updates: http://www.delphizip.org
  35.     DelphiZip maillist subscribe at http://www.freelists.org/list/delphizip
  36. ************************************************************************/
  37. #ifndef WC_NO_BEST_FIT_CHARS
  38. #  define WC_NO_BEST_FIT_CHARS 0x00000400
  39. #endif
  40.  
  41.  
  42. #ifdef DEBUG_COUNT
  43. int AliveCountW = 0;
  44. #endif
  45.                          
  46.  
  47. int DZ_MIN(int arg1, int arg2)
  48. {
  49.         return arg2 < arg1 ? arg2 : arg1;
  50. }
  51.  
  52. int DZ_MAX(int arg1, int arg2)
  53. {
  54.         return arg2 > arg1 ? arg2 : arg1;
  55. }
  56.  
  57. // min capacity = 25 chars, grow n * 32
  58. dzstrw_imp* __fastcall DZStrW::NewImp(unsigned siz)
  59. {
  60.     unsigned datasize = siz * sizeof(wchar_t);
  61.     unsigned rawsize = sizeof(dzstrw_imp) + datasize;
  62.     if (rawsize & 63)
  63.         rawsize = (rawsize | 63) + 1;
  64.  
  65.         dzstrw_imp* _imp = (dzstrw_imp*) (new char[rawsize]);
  66.         if (! _imp)
  67.                 throw DZException(DZ_ERM_MEMORY);
  68.  
  69.     _imp->refs      = 1;
  70.     _imp->capacity  = (rawsize - sizeof(dzstrw_imp)) / sizeof(wchar_t);
  71.     _imp->len       = 0;
  72.     _imp->data[0]   = 0;
  73. #ifdef DEBUG_COUNT
  74.     AliveCountW++;
  75. #endif
  76.     return _imp;
  77. }
  78.  
  79. dzstrw_imp* __fastcall DZStrW::NewImp(const wchar_t* src, int maxLen)
  80. {
  81.     int len = 0;
  82.     if (src)
  83.         len = wcslen(src);
  84.  
  85.     if (maxLen >= 0 && len > maxLen)
  86.         len = maxLen;
  87.  
  88.     if (!len)
  89.         return NULL;    // empty
  90.  
  91.     dzstrw_imp* nimp = NewImp(len >= maxLen ? len : maxLen); // make new
  92.     wcsncpy(nimp->data, src, len);
  93.     nimp->data[len] = 0;         // mark end - in case
  94.     nimp->len = wcslen(nimp->data);
  95.     return nimp;
  96. }
  97.  
  98. dzstrw_imp* __fastcall DZStrW::NewImp(const char* src, int maxLen)
  99. {
  100.     int len = 0;
  101.     if (src)
  102.         len = strlen(src);
  103.  
  104.     if (maxLen >= 0 && len > maxLen)
  105.         len = maxLen;
  106.  
  107.     if (!len)
  108.         return NULL;    // empty
  109.     int space = len + (len / 2);    // generous
  110.  
  111.     dzstrw_imp* nimp = NewImp(space >= maxLen ? space : maxLen); // make new
  112.         int wcnt = MultiByteToWideChar(0, 0, src, len, nimp->data, nimp->capacity);
  113.         nimp->data[wcnt] = 0;
  114.     nimp->len = wcslen(nimp->data);
  115.     return nimp;
  116.  
  117. }
  118.  
  119. unsigned __fastcall DZStrW::_Capacity(dzstrw_imp* _imp) const
  120. {
  121.     if (_imp)
  122.         return _imp->capacity;
  123.     return 0;
  124. }
  125.  
  126. unsigned __fastcall DZStrW::Capacity(void) const
  127. {
  128.     return _Capacity(_IMP_Ptr(imp));
  129. }
  130.  
  131. unsigned __fastcall DZStrW::_Length(dzstrw_imp* _imp) const
  132. {
  133.     if (_imp)
  134.         return _imp->len;
  135.     return 0;
  136. }
  137.  
  138. unsigned __fastcall DZStrW::Length(void) const
  139. {
  140.     return _Length(_IMP_Ptr(imp));
  141. }
  142.  
  143. unsigned __fastcall DZStrW::_IncImpRefs(dzstrw_imp* _imp)
  144. {
  145.     if (_imp)
  146.         return InterlockedIncrement(& (_imp->refs));
  147.     return 0;
  148. }
  149.  
  150. unsigned __fastcall DZStrW::_DecImpRefs(dzstrw_imp* _imp)
  151. {
  152.         if (_imp->refs)
  153.         return InterlockedDecrement(& (_imp->refs));
  154.     return 0;
  155. }
  156.  
  157. void __fastcall DZStrW::_ReleaseImp(dzstrw_imp* _imp)
  158. {
  159.     if (_imp && !_DecImpRefs(_imp))
  160.     {
  161.         delete [] _imp;
  162. #ifdef DEBUG_COUNT
  163.         AliveCountW--;
  164. #endif
  165.     }
  166. }
  167.  
  168. void __fastcall DZStrW::Release(void)
  169. {
  170.     if (imp)
  171.     {
  172.         dzstrw_imp* _imp = _IMP_Ptr(imp);
  173.         imp = NULL;
  174.         _ReleaseImp(_imp);
  175.     }
  176. }
  177.  
  178. int __fastcall DZStrW::IncRefs(void)
  179. {
  180.     if (imp)
  181.         return _IncImpRefs(_IMP_Ptr(imp));
  182.     return 0;
  183. }
  184.  
  185. int __fastcall DZStrW::DecRefs(void)
  186. {
  187.     if (imp)
  188.         return _DecImpRefs(_IMP_Ptr(imp));
  189.     return -1;
  190. }
  191.  
  192. // maxSpace is max characters
  193. void __fastcall DZStrW::_Assign(const wchar_t* src, int maxLen)
  194. {
  195.     Release();
  196.     imp = _IMP_Data(NewImp(src, maxLen));
  197. }
  198.  
  199. void __fastcall DZStrW::_Assign(const char* src, int maxLen)
  200. {
  201.     Release();
  202.     imp = _IMP_Data(NewImp(src, maxLen));
  203. }
  204.  
  205. void __fastcall DZStrW::_Append(const wchar_t* src, int maxLen)
  206. {
  207.     dzstrw_imp* _imp = _IMP_Ptr(imp);
  208.  
  209.     unsigned len = 0;
  210.     if (src)
  211.         len = wcslen(src);
  212.     if (maxLen >= 0 && len > (unsigned)maxLen)
  213.         len = maxLen;
  214.     // check something to append
  215.     if (len)
  216.     {
  217.         if (!imp)
  218.             imp = _IMP_Data(NewImp(src, len));
  219.         else
  220.         {
  221.             unsigned oldlen = _imp->len;
  222.             unsigned nlen = oldlen + len;
  223.  
  224.             // do we need a new one
  225.             if (_imp->refs > 1 || nlen > _imp->capacity)
  226.             {
  227.                 // need new imp - make copy with enough space
  228.                 dzstrw_imp* nimp = NewImp(_imp->data, nlen);
  229.                 Release();              // out with the old
  230.                 imp = _IMP_Data(nimp);  // in with the new
  231.                 _imp = nimp;
  232.             }
  233.             // append data
  234.             wchar_t *bf = &_imp->data[_imp->len];
  235.                         wcsncpy(bf, src, len);
  236.             _imp->data[nlen] = 0;
  237.             _imp->len = wcslen(_imp->data);
  238.         }
  239.     }
  240. }
  241.  
  242. void __fastcall DZStrW::_Append(const char* src, int maxSpace)
  243. {
  244.     DZStrW Asrc(src, maxSpace);
  245.     _Append(Asrc.imp, maxSpace);
  246. }
  247.  
  248. void __fastcall DZStrW::_Append(wchar_t ch)
  249. {
  250.     wchar_t chr[2];
  251.     chr[0] = ch;
  252.     chr[1] = 0;
  253.     _Append(chr, 1);
  254. }
  255.  
  256. __fastcall DZStrW::DZStrW(const DZStrW& other)
  257. {
  258.     if (other.IsEmpty())
  259.         imp = NULL;
  260.     else
  261.     {
  262.         imp = other.imp;
  263.         IncRefs();
  264.     }
  265. }
  266.  
  267. __fastcall DZStrW::DZStrW(const DZStrA& other)
  268. {
  269.     if (other.IsEmpty())
  270.         imp = NULL;
  271.     else
  272.         imp = _IMP_Data(NewImp(other.c_str(), other.Length()));
  273. }
  274.  
  275. __fastcall DZStrW::DZStrW(const wchar_t* str, int len)
  276. {
  277.     imp = _IMP_Data(NewImp(str, len));
  278. }
  279.  
  280. __fastcall DZStrW::DZStrW(const char* str, int len)
  281. {
  282.     imp = _IMP_Data(NewImp(str, len));
  283. }
  284.  
  285. __fastcall DZStrW::DZStrW(UINT cp, const char* str, int len)
  286. {
  287.         imp = NULL;
  288.         if (str && *str && len && len < (32 * 1024))
  289.         {
  290.                 if (len < 0)
  291.                         len = strlen(str);
  292.                 // convert to Unicode
  293.                 int wcnt = MultiByteToWideChar(cp, 0, str, len, NULL, 0);
  294.                 if (wcnt > 0)
  295.                 {
  296.                         dzstrw_imp* nimp = NewImp(wcnt);
  297.                         imp = _IMP_Data(nimp);
  298.                         wcnt = MultiByteToWideChar(cp, 0, str, len, imp, wcnt);
  299.                         imp[wcnt] = 0;
  300.                 nimp->len = wcnt;
  301.                 }
  302.         }
  303. }
  304.  
  305. __fastcall DZStrW::DZStrW(wchar_t ch, unsigned cnt)
  306. {
  307.     if (cnt) {
  308.         dzstrw_imp* nimp = NewImp(cnt);
  309.         imp = _IMP_Data(nimp);
  310.         wchar_t* bf = imp;
  311.         for (unsigned i = cnt; i < cnt; i++)
  312.             *bf++ = ch;
  313.         *bf = 0;
  314.         nimp->len = cnt;
  315.     }
  316.     else
  317.         imp = NULL;
  318. }
  319.  
  320. DZStrW& __fastcall DZStrW::operator =(const DZStrW& other)
  321. {
  322.     if (this != &other)
  323.     {
  324.         Release();
  325.         if (!other.IsEmpty())
  326.         {
  327.             imp = other.imp;
  328.             IncRefs();
  329.         }
  330.     }
  331.     return *this;
  332. }
  333.  
  334. DZStrW& __fastcall DZStrW::operator =(const wchar_t* str)
  335. {
  336.     Release();
  337.     imp = _IMP_Data(NewImp(str, -1));
  338.     return *this;
  339. }
  340.  
  341. DZStrW& __fastcall DZStrW::operator =(const char* str)
  342. {
  343.     Release();
  344.     imp = _IMP_Data(NewImp(str, -1));
  345.     return *this;
  346. }
  347.  
  348. DZStrW __fastcall DZStrW::operator +(const DZStrW& other)
  349. {
  350.     DZStrW res(*this);
  351.     res._Append(other.c_str(), -1);
  352.     return res;
  353. }
  354.  
  355. DZStrW __fastcall DZStrW::operator +(const wchar_t* str)
  356. {
  357.     DZStrW res(*this);
  358.     res._Append(str, -1);
  359.     return res;
  360. }
  361.  
  362. DZStrW& __fastcall DZStrW::operator +=(const DZStrW& other)
  363. {
  364.     _Append(other.c_str(), -1);
  365.     return *this;
  366. }
  367.  
  368. DZStrW& __fastcall DZStrW::operator +=(const wchar_t* str)
  369. {
  370.     _Append(str, -1);
  371.     return *this;
  372. }
  373.  
  374.  
  375. __fastcall DZStrW::~DZStrW(void)
  376. {
  377.     Release();
  378. }
  379.  
  380. DZStrW& __fastcall DZStrW::operator +=(wchar_t ch)
  381. {
  382.     wchar_t buf[2];
  383.     buf[0] = ch;
  384.     buf[1] = 0;
  385.     _Append(buf, 1);
  386.     return *this;
  387. }
  388.                        
  389. wchar_t __fastcall DZStrW::operator [](unsigned idx) const
  390. {
  391.     if (!imp || idx >= Length())
  392.         return 0;
  393.     return *(imp + idx);
  394. }
  395.  
  396. wchar_t * __fastcall DZStrW::GetBuffer(int minsize)
  397. {
  398.     dzstrw_imp* _imp = _IMP_Ptr(imp);
  399.  
  400.     int nlen = _imp ? _imp->len : 0;
  401.     if (minsize >= 0)
  402.         nlen = minsize;
  403.     // need new imp - make copy with enough space
  404.     dzstrw_imp* nimp;
  405.     if (!_imp)
  406.         nimp = NewImp(nlen);
  407.     else
  408.     {
  409.         nimp = NewImp(_imp->data, nlen);
  410.         Release();              // out with the old
  411.     }
  412.         imp = _IMP_Data(nimp);  // in with the new
  413.     return imp;
  414. }
  415.  
  416. void __fastcall DZStrW::ReleaseBuffer(int newlen)
  417. {
  418.     if (imp)
  419.     {
  420.         dzstrw_imp* _imp = _IMP_Ptr(imp);
  421.         _imp->data[_imp->capacity] = 0; //ensure end marked
  422.         int len = wcslen(imp);
  423.         if (newlen >=0 && newlen < len) {
  424.             len = newlen;
  425.             _imp->data[len] = 0; // truncate
  426.         }
  427.         _imp->len = len;
  428.     }
  429. }
  430.  
  431. dzstrw_imp* DZStrW::Unique(void)
  432. {  
  433.     dzstrw_imp* _imp = _IMP_Ptr(imp);
  434.     if (imp && _imp->refs > 1)
  435.     {                                          
  436.         dzstrw_imp* nimp = NewImp(imp, Capacity());
  437.         Release();
  438.         imp = _IMP_Data(nimp);
  439.         return nimp;    
  440.     }
  441.     return _imp;
  442. }
  443.  
  444. void __cdecl  DZStrW::AppendFormat(const wchar_t *fmt, ...)
  445. {
  446.     if (fmt)
  447.     {
  448.         DZStrW tmp;
  449.         va_list argList;
  450.         va_start(argList, fmt);
  451.         tmp.FormatV(fmt, argList);
  452.         va_end(argList);
  453.         if (!tmp.IsEmpty())
  454.             _Append(tmp.c_str());
  455.     }
  456. }
  457.  
  458. bool __fastcall DZStrW::BadDOS(void) const
  459. {
  460.         if (IsEmpty())
  461.                 return false;
  462.  
  463. //    int Bad;
  464. //      WideCharToMultiByte(CP_ACP, 0, c_str(), Length(), NULL, 0, 0, &Bad);
  465. //      return Bad;
  466.         wchar_t tmp;
  467.         for (const wchar_t* p = imp; (tmp = *p) != 0; p++)
  468.                 if (tmp < 32 || tmp > 126)
  469.                         return true;
  470.         return false;
  471. }
  472.  
  473. int __fastcall DZStrW::Compare(const wchar_t *other) const
  474. {
  475.     if (!imp)
  476.         return (other && *other)? -1 : 0;
  477.     if (!other || !*other)
  478.         return -1;
  479.         return wcscmp(imp, other);
  480. }
  481.  
  482. int __fastcall DZStrW::CompareNoCase(const wchar_t *other) const
  483. {
  484.     if (!imp)
  485.         return (other && *other)? -1 : 0;
  486.     if (!other || !*other)
  487.         return -1;
  488.  
  489.     DZStrW me(*this);
  490.     me.ToUpper();
  491.     DZStrW theOther(other);
  492.     theOther.ToUpper();
  493.         return wcscmp(me.imp, theOther.imp);
  494. }
  495.  
  496. int __fastcall DZStrW::Delete(unsigned pos, unsigned cnt)
  497. {
  498.     if (!imp || pos >= Length())
  499.         return 0;
  500.     dzstrw_imp* _imp = Unique();
  501.     wchar_t* p = _imp->data + pos;
  502.     if (pos + cnt < _imp->len)
  503.     {  
  504.         for (wchar_t* q = p + cnt; *q; q++)
  505.             *p++ = *q;
  506.     }                  
  507.     *p = 0;    
  508.     _imp->len = wcslen(_imp->data);        
  509.     return (int)_imp->len;
  510. }
  511.  
  512. int __fastcall DZStrW::Find(const wchar_t *sub, unsigned start) const
  513. {
  514.     if (!imp || start > Length() || !sub || !*sub)
  515.         return -1;
  516.     int slen = wcslen(sub);
  517.     if (start + slen > Length())
  518.         return -1;
  519.     const wchar_t* si = wcsstr(imp + start, sub);
  520.     if (!si)
  521.         return -1;
  522.     return si - imp;
  523. }
  524.  
  525. int __fastcall DZStrW::Find(wchar_t ch, unsigned start) const
  526. {
  527.     if (!imp || start > Length())
  528.         return -1;
  529.  
  530.     int i = start;
  531.     for (const wchar_t* p = &imp[start]; *p && *p != ch; p++)
  532.         i++;
  533.     return (unsigned)i >= Length() ? -1 : i;
  534. }
  535.  
  536. int __fastcall DZStrW::FindOneOf(const wchar_t *chars, unsigned start) const
  537. {
  538.     if (!imp || start > Length())
  539.         return -1;
  540.  
  541.     int i = start;
  542.     for (const wchar_t* p = &imp[start]; *p; p++)
  543.     {
  544.         bool found = false;
  545.         wchar_t ch = *p;
  546.         for (const wchar_t* q = chars; *q; q++)
  547.         {
  548.             if (*q == ch)
  549.             {
  550.                 found = true;
  551.                 break;
  552.             }
  553.         }
  554.         if (found)
  555.             break;
  556.         i++;
  557.     }
  558.     return (unsigned)i >= Length() ? -1 : i;
  559. }
  560.  
  561. int __cdecl  DZStrW::Format(const wchar_t *fmt, ...)
  562. {
  563.     Release();
  564.     int r = 0;
  565.     if (fmt)
  566.     {
  567.         va_list argList;
  568.         va_start(argList, fmt);
  569.         r = FormatV(fmt, argList);
  570.         va_end(argList);
  571.     }
  572.     return r;
  573. }
  574.  
  575. #if 0
  576. // arg = arg / divisor , returns remainder
  577. unsigned  DivMod64(unsigned __int64& arg, unsigned divisor)
  578. {
  579.     asm
  580.     {
  581.         mov ecx, [ebp + 8]  // arg
  582.         mov eax, [ebp + 12] // divisor
  583.         or eax, eax
  584.         jnz @@ok
  585.                 // / 0   _ return 0, 0 _ not correct but safer
  586.         mov [ecx + 4] ,eax  // arg hi
  587.         mov [ecx + 0] ,eax  // arg lo
  588.         jmp @@done
  589.     @@ok:
  590.         xor edx, edx
  591.         mov eax, [ecx + 4]  // arg hi
  592.         or eax, eax         // zero?
  593.         jz @@nohi
  594.         div dword ptr [ebp + 12]
  595.     @@nohi:
  596.         mov [ecx + 4], eax  // quot hi
  597.         mov eax, [ecx]      // _dividend[0]
  598.         div dword ptr [ebp + 12]
  599.         mov [ecx], eax      // quot lo
  600.         mov eax, edx        // remainder
  601.     @@done:
  602.     }
  603. #pragma warn -rvl
  604. #pragma warn -par
  605. }
  606. #endif
  607.  
  608. #define MAXDIGITS  64
  609.  
  610. //static const wchar_t digits[] = L"0123456789abcdefghijklmnopqrstuvwxyz";
  611. static const wchar_t zeros[] = L"00000000000000000000000000000000";
  612. static const wchar_t spaces[] = L"                                ";
  613.  
  614. static
  615. int convert(unsigned __int64 value, int radix, wchar_t *buffer, bool upper)
  616. {
  617.     wchar_t buf[MAXDIGITS + 2];
  618.         int i;
  619.         wchar_t aA = upper ? L'A' : L'a';
  620.  
  621.     i = 0;
  622.  
  623.     if (radix == -10) {
  624.         if ((int)value < 0) {
  625.             buffer[i++] = '-';
  626.             value = 0-value;
  627.         }
  628.         radix = 10;
  629.     }
  630.  
  631.         if (radix != 10 && radix != 16 && radix != 8 && radix != 2 && radix != 36)
  632.                 radix = 16;
  633.  
  634.     wchar_t* p = &buf[MAXDIGITS + 1];
  635.     *p = 0;
  636.     while (value)
  637.         {
  638.                 int cv = DivMod64(value, radix);
  639.                 wchar_t c;// = digits[DivMod64(value, radix) & 15];
  640.                 if (cv <= 9)
  641.                         c = (wchar_t)(L'0' + cv);
  642.                 else
  643.                         c = (wchar_t)(aA + (cv - 10));
  644.         *--p = c;
  645.  
  646.                 if (++i > MAXDIGITS)
  647.             break;
  648.     }
  649.     if (!i)
  650.     {
  651.         *--p = L'0';
  652.         i++;
  653.     }
  654.     wcsncpy(buffer, p, i);
  655.         buffer[i] = 0;
  656.     return i;
  657. }
  658.  
  659. #define FORMAT_BUFFER_SIZE 2048
  660. int __cdecl DZStrW::FormatV(const wchar_t *fmt, void *argList)
  661. {
  662.     int i;
  663.     int j;
  664.     __int64 n;
  665.     int arg;
  666.     wchar_t c;
  667.     int zero;
  668.     bool right;
  669.     wchar_t flag;
  670.     int width;
  671.     int prec;
  672.     const wchar_t *p;
  673.     wchar_t temp[MAXDIGITS+1+55];
  674.  
  675.     Release();
  676.     if (!fmt)
  677.         return 0;
  678.     dzstrw_imp* _imp = NewImp(FORMAT_BUFFER_SIZE + 1);
  679.     imp = _IMP_Data(_imp);
  680.  
  681.     i = 0;
  682.     for (p = fmt; *p; p++)
  683.     {
  684.                 c = *p;
  685.         if (c != L'%')
  686.         {
  687.             _Append(c);
  688.             i++;
  689.             continue;
  690.                 }
  691.                 zero = 0;
  692.                 width = 0;
  693.                 right = false;
  694.                 flag = 0;
  695.                 c = *++p;
  696.                 if (c == L'%')
  697.                 {
  698.                         _Append(c);
  699.                         i++;
  700.                         continue;
  701.                 }
  702.  
  703.                 if (c == L'-')
  704.                 {
  705.                         right = true;
  706.                         c = *++p;
  707.                 }
  708.  
  709.                 if (c == L'0')
  710.                 {
  711.                         zero = 1;
  712.                         c = *++p;
  713.                 }
  714.                 if (iswdigit(c))
  715.                 {
  716.                         width = c - L'0';
  717.                         c = *++p;
  718.                         if (iswdigit(c))
  719.                         {
  720.                                 width = (width*10) + (c - L'0');
  721.                                 c = *++p;
  722.                         }
  723.                 }
  724.  
  725.                 prec = 0x7fffffff;
  726.                 if (c == L'.')
  727.                 {
  728.                         prec = 0;
  729.                         c = *++p;
  730.                         while (iswdigit(c))
  731.                         {
  732.                                 prec = (prec*10) + (c - L'0');
  733.                                 c = *++p;
  734.                         }
  735.                 }
  736.  
  737.                 if (c == L'h' || c == L'l' || c == L'L')
  738.                 {
  739.                         flag = c;
  740.                         c = *++p;
  741.                 }
  742.  
  743.                 if (flag == L'L' && (c == L'd' || c == L'u' || c == L'x' || c == L'X'))
  744.                 {
  745.                         n = va_arg(argList, __int64);
  746.                 }
  747.                 else
  748.                 {
  749.                         arg = va_arg(argList, int);
  750.                         n = arg;
  751.                 }
  752.                 bool upperXZ = false;
  753.                 switch (c)
  754.                 {
  755.                         case L'b':
  756.                                 j = convert(n, 2, temp, false);
  757.                                 break;
  758.                         case L'c':
  759.                                 temp[0] = (wchar_t)n;
  760.                                 temp[1] = L'\0';
  761.                                 j = 1;
  762.                                 break;
  763.                         case L'i':
  764.                         case L'd':
  765.                                 j = convert(n, -10, temp, false);
  766.                                 break;
  767.                         case L'u':
  768.                                 j = convert(n, 10, temp, false);
  769.                                 break;
  770.                         case L'o':
  771.                                 j = convert(n, 8, temp, false);
  772.                                 break;
  773.                         case L's':
  774.                                 j = 0;
  775.                                 if (arg)
  776.                                 {
  777.                                         if (flag == L'h')
  778.                                                 j = DZ_MIN((int)strlen((const char *)arg), prec);
  779.                                         else
  780.                                                 j = DZ_MIN((int)wcslen((const wchar_t *)arg), prec);
  781.                                 }
  782.                                 break;
  783.                         case L'X':
  784.                                 upperXZ = true;
  785.                         case L'x':
  786.                                 j = convert(n, 16, temp, upperXZ);
  787.                                 break;
  788.                         case L'Z':
  789.                                 upperXZ = true;
  790.                         case L'z':
  791.                                 j = convert(n, 36, temp, upperXZ);
  792.                                 break;
  793.                         default:
  794. //OutputDebugString(L"FormatV - error");
  795.                                 wcscpy(temp, L"<<error>>");
  796.                                 j = wcslen(temp);
  797.                 }
  798.  
  799.                 if (!right && j < width)
  800.                 {
  801.                         if (zero)
  802.                         {
  803.                                 _Append(zeros, width-j);
  804.                         }
  805.                         else
  806.                         {
  807.                                 _Append(spaces, width-j);
  808.                         }
  809.                         i += width-j;
  810.                 }
  811.  
  812.                 if (c == L's')
  813.                 {
  814.                         if (arg)
  815.                         {
  816.                                 if (flag == L'h')
  817.                                         _Append((const char*)arg, j);
  818.                                 else
  819.                                         _Append((const wchar_t*)arg, j);
  820.                         }
  821.                 }
  822.                 else
  823.                 {
  824.                         _Append(temp, j);
  825.                 }
  826.                 if (right)
  827.                         _Append(spaces, width-j);
  828.                 i += j;
  829.     }
  830.     return i;
  831. }
  832.  
  833. int __fastcall DZStrW::Insert(unsigned pos, wchar_t ch)
  834. {
  835.     if (!imp)
  836.         imp = _IMP_Data(NewImp(1));
  837.  
  838.     pos = DZ_MIN(pos, Length());  // limit to appending      
  839.  
  840.     wchar_t* bf = GetBuffer(Length() + 1);
  841.     wchar_t* stop = bf + pos;
  842.     wchar_t* p = bf + Length() + 2;
  843.     while (--p > stop)
  844.         *p = *(p - 1);
  845.     *p = ch;                        
  846.     dzstrw_imp* _imp = _IMP_Ptr(imp);
  847.     _imp->len = wcslen(_imp->data);        
  848.     return (int)_imp->len;
  849. }
  850.  
  851. wchar_t DZStrW::LastChar(void) const
  852. {
  853.     if (!imp)
  854.         return 0;
  855.     return imp[Length()-1];
  856. }
  857.  
  858. DZStrW __fastcall DZStrW::Left(unsigned len) const
  859. {                
  860.     if (!imp)
  861.         return DZStrW();
  862.     return DZStrW(imp, DZ_MIN(len, Length()));
  863. }
  864.  
  865. DZStrW __fastcall DZStrW::Mid(unsigned pos, unsigned len) const
  866. {
  867.     if (!imp || pos > Length())
  868.         return DZStrW();
  869.     return DZStrW(imp + pos, DZ_MIN(len, Length() - pos));
  870. }
  871.  
  872.  
  873. int __fastcall DZStrW::ReverseFind(wchar_t ch, unsigned int pos) const
  874. {
  875.     if (!imp)
  876.         return -1;
  877.     int i = Length();
  878.     if (pos < (unsigned)i)
  879.         i = pos;
  880.     const wchar_t* p = &imp[i];
  881.     while (i >= 0 && *p != ch)
  882.     {
  883.         i--;
  884.         p--;
  885.     }
  886.     return i;
  887. }
  888.  
  889. DZStrA __fastcall DZStrW::SafeAnsi(void) const
  890. {
  891.         int tmp;
  892.         return SafeAnsi(tmp);
  893. }
  894.  
  895. DZStrA __fastcall DZStrW::SafeAnsi(int &bad) const
  896. {
  897.         DZStrA tmp;
  898.     if (IsEmpty())
  899.         return tmp;
  900.  
  901.         bad = 0;
  902.         int subst = 0x1b; // substitute char - escape
  903.         int cnt = WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, c_str(), Length(), NULL, 0,
  904.         (char*)&subst, &bad);
  905.     if (cnt > 0)
  906.     {
  907.         cnt = WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, c_str(), Length(),
  908.                         tmp.GetBuffer(cnt), cnt, (char*)&subst, &bad);
  909.         tmp.ReleaseBuffer(cnt);
  910.         }
  911.         if (!bad || !tmp)
  912.         return tmp;
  913.  
  914.     DZStrA ret;
  915.     const char *pa = tmp.c_str();
  916.     const char *good = 0;
  917.     cnt = 0;
  918.     int i = 0;
  919.     wchar_t wc = 0;
  920.         char c;
  921.     int wlen = Length();
  922.     while ((c= *pa) != 0)
  923.     {
  924.         if (i < wlen)
  925.             wc = (*this)[i++];
  926.                 if (((unsigned char)c) < 0x20)
  927.         {
  928.             if (cnt)
  929.             {
  930.                 ret._Append(good, cnt);
  931.                 cnt = 0;
  932.             }
  933.             ret += "#$";
  934.                         ret += DZStrA(wc, 4);
  935.         }
  936.         else
  937.         {
  938.             if (!cnt)
  939.                 good = pa;
  940.             cnt++;
  941.                 }
  942.         pa = CharNextA(pa);
  943.     }
  944.     if (cnt)
  945.     {
  946.                 ret._Append(good, cnt);
  947.     }
  948.     return ret;
  949. }
  950.  
  951. DZStrA __fastcall DZStrW::SafeNarrow(unsigned cp) const
  952. {
  953.         int tmp;
  954.         return SafeNarrow(cp, tmp);
  955. }
  956.  
  957. DZStrA __fastcall DZStrW::SafeNarrow(unsigned cp, int &bad) const
  958. {
  959.         DZStrA tmp;
  960.     if (IsEmpty())
  961.         return tmp;
  962.  
  963.         bad = 0;
  964.         int subst = 0x1b; // substitute char - escape
  965.         int cnt = WideCharToMultiByte(cp, WC_NO_BEST_FIT_CHARS, c_str(), Length(), NULL, 0,
  966.         (char*)&subst, &bad);
  967.         if (cnt > 0)
  968.         {
  969.                 cnt = WideCharToMultiByte(cp, WC_NO_BEST_FIT_CHARS, c_str(), Length(),
  970.                         tmp.GetBuffer(cnt), cnt, (char*)&subst, &bad);
  971.         tmp.ReleaseBuffer(cnt);
  972.         }
  973.         if (!bad || !tmp)
  974.         return tmp;
  975.  
  976.     DZStrA ret;
  977.     const char *pa = tmp.c_str();
  978.     const char *good = 0;
  979.     cnt = 0;
  980.     int i = 0;
  981.     wchar_t wc = 0;
  982.         char c;
  983.     int wlen = Length();
  984.     while ((c= *pa) != 0)
  985.     {
  986.         if (i < wlen)
  987.             wc = (*this)[i++];
  988.                 if (((unsigned char)c) < 0x20)
  989.         {
  990.             if (cnt)
  991.             {
  992.                 ret._Append(good, cnt);
  993.                 cnt = 0;
  994.             }
  995.             ret += "#$";
  996.                         ret += DZStrA(wc, 4);
  997.         }
  998.         else
  999.         {
  1000.             if (!cnt)
  1001.                 good = pa;
  1002.             cnt++;
  1003.                 }
  1004.         pa = CharNextA(pa);
  1005.     }
  1006.     if (cnt)
  1007.     {
  1008.                 ret._Append(good, cnt);
  1009.     }
  1010.     return ret;
  1011. }
  1012.  
  1013. DZStrW& __fastcall DZStrW::ToUpper(void)
  1014. {
  1015.     if (imp)
  1016.     {
  1017.                 wchar_t * bf = GetBuffer();
  1018.                 CharUpperBuffW(bf, Length());
  1019.         ReleaseBuffer();
  1020.     }
  1021.     return *this;
  1022. }
  1023.  
  1024. DZStrW& __fastcall DZStrW::Trim(void)
  1025. {
  1026.     return TrimLeft().TrimRight();
  1027. }
  1028.  
  1029. DZStrW& __fastcall DZStrW::TrimLeft(void)
  1030. {
  1031.     return TrimLeft(L' ');
  1032. }
  1033.  
  1034. DZStrW& __fastcall DZStrW::TrimLeft(wchar_t ch)
  1035. {
  1036.     if (imp && ch && *imp == ch)
  1037.     {
  1038.         // something to trim
  1039.         wchar_t* bf = GetBuffer(); // will make unique
  1040.         const wchar_t* p = bf;
  1041.         while (*p == ch)
  1042.             p++;
  1043.         if (!*p)
  1044.         {
  1045.             // we empty it
  1046.             Release();
  1047.         }
  1048.         else
  1049.         {
  1050.             // move rest
  1051.             wchar_t tc;
  1052.             do
  1053.             {
  1054.                 tc = *bf++ = *p++;
  1055.             }
  1056.             while (tc);
  1057.             // get new length
  1058.             dzstrw_imp* _imp = _IMP_Ptr(imp);
  1059.             _imp->len = wcslen(_imp->data);
  1060.         }
  1061.     }
  1062.     return *this;
  1063. }
  1064.  
  1065. DZStrW& __fastcall DZStrW::TrimRight(void)
  1066. {
  1067.     if (imp && imp[Length()-1] == ' ')
  1068.     {
  1069.         // something to trim
  1070.         wchar_t* bf = GetBuffer(); // will make unique
  1071.         wchar_t* p = bf + Length() - 1;
  1072.         while (p >= bf && *p == ' ')
  1073.             --p;
  1074.         // truncate it
  1075.         *++p = 0;
  1076.         if (p == bf)
  1077.         {
  1078.             // we empty it
  1079.             Release();
  1080.         }
  1081.         else
  1082.         {
  1083.             // set new length
  1084.             dzstrw_imp* _imp = _IMP_Ptr(imp);
  1085.             _imp->len = wcslen(_imp->data);
  1086.         }
  1087.     }
  1088.     return *this;
  1089. }
  1090.  
  1091. #ifdef DEBUG_COUNT
  1092. int AliveCountA = 0;
  1093. #endif
  1094.  
  1095. // min capacity = 25 chars, grow n * 32
  1096. dzstra_imp* __fastcall DZStrA::NewImp(unsigned siz)
  1097. {
  1098.     unsigned datasize = siz * sizeof(char);
  1099.     unsigned rawsize = sizeof(dzstra_imp) + datasize;
  1100.     if (rawsize & 63)
  1101.         rawsize = (rawsize | 63) + 1;
  1102.  
  1103.     dzstra_imp* _imp = (dzstra_imp*) (new char[rawsize]);
  1104.     if (! _imp)
  1105.         throw DZException(DZ_ERM_MEMORY);
  1106.  
  1107.     _imp->refs      = 1;
  1108.     _imp->capacity  = (rawsize - sizeof(dzstra_imp)) / sizeof(char);
  1109.     _imp->len       = 0;
  1110.     _imp->data[0]   = 0;
  1111. #ifdef DEBUG_COUNT
  1112.     AliveCountA++;
  1113. #endif
  1114.     return _imp;
  1115. }
  1116.  
  1117. dzstra_imp* __fastcall DZStrA::NewImp(const char* src, int maxLen)
  1118. {
  1119.     int len = 0;
  1120.     if (src)
  1121.         len = strlen(src);
  1122.  
  1123.     if (maxLen >= 0 && len > maxLen)
  1124.         len = maxLen;
  1125.  
  1126.     if (!len)
  1127.         return NULL;    // empty
  1128.  
  1129.     dzstra_imp* nimp = NewImp(len >= maxLen ? len : maxLen); // make new
  1130.     strncpy(nimp->data, src, len);
  1131.     nimp->data[len] = 0;         // mark end - in case
  1132.     nimp->len = strlen(nimp->data);
  1133.     return nimp;
  1134. }
  1135.  
  1136. unsigned __fastcall DZStrA::_Capacity(dzstra_imp* _imp) const
  1137. {
  1138.     if (_imp)
  1139.         return _imp->capacity;
  1140.     return 0;
  1141. }
  1142.  
  1143. unsigned __fastcall DZStrA::Capacity(void) const
  1144. {
  1145.     return _Capacity(_IMP_Ptr(imp));
  1146. }
  1147.  
  1148. unsigned __fastcall DZStrA::_Length(dzstra_imp* _imp) const
  1149. {
  1150.     if (_imp)
  1151.         return _imp->len;
  1152.     return 0;
  1153. }
  1154.  
  1155. unsigned __fastcall DZStrA::Length(void) const
  1156. {
  1157.     return _Length(_IMP_Ptr(imp));
  1158. }
  1159.  
  1160. unsigned __fastcall DZStrA::_IncImpRefs(dzstra_imp* _imp)
  1161. {
  1162.     if (_imp)
  1163.         return InterlockedIncrement(& (_imp->refs));
  1164.     return 0;
  1165. }
  1166.  
  1167. unsigned __fastcall DZStrA::_DecImpRefs(dzstra_imp* _imp)
  1168. {
  1169.     if (_imp && _imp->refs)
  1170.         return InterlockedDecrement(& (_imp->refs));
  1171.     return 0;
  1172. }
  1173.  
  1174. void __fastcall DZStrA::_ReleaseImp(dzstra_imp* _imp)
  1175. {
  1176.     if (!_DecImpRefs(_imp))
  1177.         {
  1178.         delete[] _imp;
  1179. #ifdef DEBUG_COUNT
  1180.     AliveCountA--;
  1181. #endif
  1182.     }
  1183. }
  1184.  
  1185. void __fastcall DZStrA::Release(void)
  1186. {
  1187.     if (imp)
  1188.     {
  1189.         dzstra_imp* _imp = _IMP_Ptr(imp);
  1190.         imp = NULL;
  1191.         _ReleaseImp(_imp);
  1192.     }
  1193. }
  1194.  
  1195. int __fastcall DZStrA::IncRefs(void)
  1196. {
  1197.     if (imp)
  1198.         return _IncImpRefs(_IMP_Ptr(imp));
  1199.     return 0;
  1200. }
  1201.  
  1202. int __fastcall DZStrA::DecRefs(void)
  1203. {
  1204.     if (imp)
  1205.         return _DecImpRefs(_IMP_Ptr(imp));
  1206.     return -1;
  1207. }
  1208.  
  1209. // maxSpace is max characters
  1210. void __fastcall DZStrA::_Assign(const char* src, int maxLen)
  1211. {
  1212.     Release();
  1213.     imp = _IMP_Data(NewImp(src, maxLen));
  1214. }
  1215.  
  1216. void __fastcall DZStrA::_Append(const char* src, int maxLen)
  1217. {
  1218.     dzstra_imp* _imp = _IMP_Ptr(imp);
  1219.  
  1220.     unsigned len = 0;
  1221.     if (src)
  1222.         len = strlen(src);
  1223.     if (maxLen >= 0 && len > (unsigned)maxLen)
  1224.         len = maxLen;
  1225.     // check something to append
  1226.     if (len)
  1227.     {
  1228.         if (!imp)
  1229.             imp = _IMP_Data(NewImp(src, len));
  1230.         else
  1231.         {
  1232.             unsigned oldlen = _imp->len;
  1233.             unsigned nlen = oldlen + len;
  1234.  
  1235.             // do we need a new one
  1236.             if (_imp->refs > 1 || nlen > _imp->capacity)
  1237.             {
  1238.                 // need new imp - make copy with enough space
  1239.                 dzstra_imp* nimp = NewImp(_imp->data, nlen);
  1240.                 Release();              // out with the old
  1241.                 imp = _IMP_Data(nimp);  // in with the new
  1242.                 _imp = nimp;
  1243.             }
  1244.             // append data
  1245.             char *bf = &_imp->data[_imp->len];
  1246.             strncpy(bf, src, len);
  1247.             bf[len] = 0;                // mark end
  1248.             _imp->len = strlen(_imp->data);
  1249.         }
  1250.     }
  1251. }
  1252.  
  1253. __fastcall DZStrA::DZStrA(const DZStrA& other)
  1254. {
  1255.     imp = other.imp;
  1256.     IncRefs();
  1257. }
  1258.  
  1259. __fastcall DZStrA::DZStrA(const DZStrW& other)
  1260. {
  1261.     imp = 0;
  1262.     int len;// = other.Length();
  1263.     if (other && ((len = other.length()) >0))
  1264.     {
  1265.         int alen = len + (len / 2); // just in case
  1266.         // make new imp with enough space
  1267.         dzstra_imp* _imp = NewImp(alen);
  1268.         imp = _IMP_Data(_imp);  // new
  1269.                 int cnt = WideCharToMultiByte(0, WC_NO_BEST_FIT_CHARS, other.c_str(),
  1270.                         len, imp, alen, NULL, NULL);
  1271.         _imp->data[cnt] = 0;
  1272.         _imp->len = strlen(_imp->data);
  1273.     }
  1274. }
  1275.  
  1276. __fastcall DZStrA::DZStrA(const char* str, int len)
  1277. {
  1278.     imp = _IMP_Data(NewImp(str, len));
  1279. }
  1280.  
  1281. __fastcall DZStrA::DZStrA(const wchar_t* wstr)
  1282. {
  1283.         int len;
  1284.         imp = 0;
  1285.     if (wstr && ((len = wcslen(wstr)) > 0))
  1286.     {
  1287.         int alen = len + (len / 2); // just in case
  1288.         // make new imp with enough space
  1289.         dzstra_imp* nimp = NewImp(alen);
  1290.         imp = _IMP_Data(nimp);  // new
  1291.                 int cnt = WideCharToMultiByte(0, WC_NO_BEST_FIT_CHARS, wstr, len, imp,
  1292.                         alen, NULL, NULL);
  1293.         nimp->data[cnt] = 0;
  1294.         nimp->len = strlen(nimp->data);
  1295.     }
  1296. }
  1297.  
  1298. const char hx[16] = "0123456789ABCDEF";
  1299. __fastcall DZStrA::DZStrA(unsigned val, unsigned cnt)
  1300. {
  1301.     imp = _IMP_Data(NewImp(cnt));
  1302.  
  1303.     char* bp = imp + cnt;
  1304.     int x = cnt;
  1305.     *bp = 0;
  1306.     while (val && x-- > 0)
  1307.     {
  1308.         *--bp = hx[val & 0x0f];
  1309.         val >>= 4;
  1310.     }
  1311.     while (bp > imp)
  1312.         *--bp = '0';
  1313. }
  1314.  
  1315. DZStrA& __fastcall DZStrA::operator =(const DZStrA& other)
  1316. {
  1317.     if (this != &other)
  1318.     {
  1319.         Release();
  1320.         imp = other.imp;
  1321.         IncRefs();
  1322.     }
  1323.     return *this;
  1324. }
  1325.  
  1326. DZStrA& __fastcall DZStrA::operator =(const char* str)
  1327. {
  1328.     Release();
  1329.     imp = _IMP_Data(NewImp(str, -1));
  1330.     return *this;
  1331. }
  1332.  
  1333. DZStrA __fastcall DZStrA::operator +(const DZStrA& other)
  1334. {
  1335.     DZStrA res(*this);
  1336.     res._Append(other.c_str(), -1);
  1337.     return res;
  1338. }
  1339.  
  1340. DZStrA __fastcall DZStrA::operator +(const char* str)
  1341. {
  1342.     DZStrA res(*this);
  1343.     res._Append(str, -1);
  1344.     return res;
  1345. }
  1346.  
  1347. DZStrA& __fastcall DZStrA::operator +=(const DZStrA& other)
  1348. {
  1349.     _Append(other.c_str(), -1);
  1350.     return *this;
  1351. }
  1352.  
  1353. DZStrA& __fastcall DZStrA::operator +=(const char* str)
  1354. {
  1355.     _Append(str, -1);
  1356.     return *this;
  1357. }
  1358.  
  1359. DZStrA& __fastcall DZStrA::operator +=(char ch)
  1360. {
  1361.     char buf[2];
  1362.     buf[0] = ch;
  1363.     buf[1] = 0;
  1364.     _Append(buf, 1);
  1365.     return *this;
  1366. }
  1367.  
  1368. char __fastcall DZStrA::operator [](unsigned idx) const
  1369. {
  1370.     if (!imp || idx >= Length())
  1371.         return 0;
  1372.     return *(imp + idx);
  1373. }
  1374.  
  1375. __fastcall DZStrA::~DZStrA(void)
  1376. {
  1377.     Release();
  1378. }
  1379.  
  1380. char * __fastcall DZStrA::GetBuffer(int minsize)
  1381. {
  1382.     dzstra_imp* _imp = _IMP_Ptr(imp);
  1383.  
  1384.     int nlen = _imp ? _imp->len : 0;
  1385.     if (minsize >= 0)
  1386.         nlen = minsize;
  1387.     // need new imp - make copy with enough space
  1388.     dzstra_imp* nimp;
  1389.     if (!_imp)
  1390.         nimp = NewImp(nlen);
  1391.     else
  1392.     {
  1393.         nimp = NewImp(_imp->data, nlen);
  1394.         Release();              // out with the old
  1395.     }
  1396.     imp = _IMP_Data(nimp);  // in with the new
  1397.     return imp;
  1398. }
  1399.  
  1400. void __fastcall DZStrA::ReleaseBuffer(int newlen)
  1401. {
  1402.     if (imp)
  1403.     {
  1404.         dzstra_imp* _imp = _IMP_Ptr(imp);
  1405.         _imp->data[_imp->capacity] = 0; //ensure end marked
  1406.         int len = strlen(imp);
  1407.         if (newlen >=0 && newlen < len) {
  1408.             len = newlen;
  1409.             _imp->data[len] = 0; // truncate
  1410.         }
  1411.         _imp->len = len;
  1412.     }
  1413. }
  1414.  
  1415. bool __fastcall DZStrA::BadDOS(void) const
  1416. {
  1417.         if (IsEmpty())
  1418.                 return false;
  1419.  
  1420.         char tmp;
  1421.         for (const char* p = imp; (tmp = *p) != 0; p++)
  1422.                 if (tmp < 32 || tmp > 126)
  1423.                         return true;
  1424.         return false;
  1425. }
  1426.  
  1427. int __fastcall DZStrA::Compare(const char* other) const
  1428. {
  1429.     if (!imp)
  1430.         return (other && *other)? -1 : 0;
  1431.     if (!other || !*other)
  1432.         return -1;
  1433.  
  1434.     return strcmp(imp, other);
  1435. }
  1436.  
  1437.  
  1438.  
  1439. int __fastcall DZStrA::CompareNoCase(const char* other) const
  1440. {
  1441.     if (!imp)
  1442.         return (other && *other)? -1 : 0;
  1443.     if (!other || !*other)
  1444.         return -1;
  1445.  
  1446.     DZStrA me(*this);
  1447.     me.ToUpper();
  1448.     DZStrA theOther(other);
  1449.     theOther.ToUpper();
  1450.     return strcmp(me.imp, theOther.imp);
  1451. }
  1452.  
  1453.  
  1454. int __fastcall DZStrA::Find(char ch) const
  1455. {
  1456.     if (!imp)
  1457.         return -1;
  1458.  
  1459.     int i = 0;
  1460.     for (const char* p = imp; *p && *p != ch; p++)
  1461.         i++;
  1462.     return (unsigned)i >= Length() ? -1 : i;
  1463. }
  1464.  
  1465. int __fastcall DZStrA::FindOneOf(const char *chars, unsigned start) const
  1466. {
  1467.     if (!imp || start > Length())
  1468.         return -1;
  1469.  
  1470.     int i = start;
  1471.     for (const char* p = &imp[start]; *p; p++)
  1472.     {
  1473.         bool found = false;
  1474.         char ch = *p;
  1475.         for (const char* q = chars; *q; q++)
  1476.         {
  1477.             if (*q == ch)
  1478.             {
  1479.                 found = true;
  1480.                 break;
  1481.             }
  1482.         }
  1483.         if (found)
  1484.             break;
  1485.         i++;
  1486.     }
  1487.     return (unsigned)i >= Length() ? -1 : i;
  1488. }
  1489.  
  1490.  
  1491. DZStrA __fastcall DZStrA::Left(unsigned len) const
  1492. {
  1493.     if (!imp)
  1494.         return DZStrA();
  1495.     return DZStrA(imp, DZ_MIN(len, Length()));
  1496. }
  1497.  
  1498. DZStrA __fastcall DZStrA::Mid(unsigned pos, unsigned len) const
  1499. {
  1500.     if (!imp || pos > Length())
  1501.         return DZStrA();
  1502.     return DZStrA(imp + pos, DZ_MIN(len, Length() - pos));
  1503. }
  1504.  
  1505. int __fastcall DZStrA::ReverseFind(char ch, unsigned int pos) const
  1506. {
  1507.     if (!imp)
  1508.         return -1;
  1509.     int i = Length();
  1510.     if (pos < (unsigned)i)
  1511.         i = pos;
  1512.     const char* p = &imp[i];
  1513.     while (i >= 0 && *p != ch)
  1514.     {
  1515.         i--;
  1516.         p--;
  1517.     }
  1518.     return i;
  1519. }
  1520.  
  1521.  
  1522. DZStrA& __fastcall DZStrA::ToUpper(void)
  1523. {
  1524.         if (imp)
  1525.     {
  1526.         char * bf = GetBuffer();    // make unique
  1527.         CharUpperBuffA(bf, Length());
  1528.         ReleaseBuffer();
  1529.     }
  1530.     return *this;
  1531. }
  1532.  
  1533.