Subversion Repositories autosfx

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 daniel-mar 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