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 "ZipFnc.h" |
||
5 | |||
6 | #include <assert.h> |
||
7 | #include "dz_errs.h" |
||
8 | |||
9 | #undef _DZ_FILE_ |
||
10 | #define _DZ_FILE_ DZ_ZIPFNC_CPP |
||
11 | |||
12 | /* ZGlobals.c |
||
13 | * Copyright (C) 1990-1996 Mark Adler, Richard B. Wales, Jean-loup Gailly, |
||
14 | * Kai Uwe Rommel, Onno van der Linden and Igor Mandrichenko. |
||
15 | * Permission is granted to any individual or institution to use, copy, or |
||
16 | * redistribute this software so long as all of the original files are included, |
||
17 | * that it is not sold for profit, and that this copyright notice is retained. |
||
18 | * This version modified by Chris Vleghert for BCB/Delphi Zip. |
||
19 | ** distributed under LGPL license ** see license.txt for details |
||
20 | |||
21 | Copyright (c) 1990-2007 Info-ZIP. All rights reserved. |
||
22 | |||
23 | See the accompanying file LICENSE, version 2007-Mar-4 or later |
||
24 | (the contents of which are also included in zip.h) for terms of use. |
||
25 | If, for some reason, all these files are missing, the Info-ZIP license |
||
26 | also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html |
||
27 | |||
28 | parts Copyright (C) 1997 Mike White, Eric W. Engler |
||
29 | ************************************************************************ |
||
30 | Copyright (C) 2009, 2010 by Russell J. Peters, Roger Aelbrecht |
||
31 | |||
32 | This file is part of TZipMaster Version 1.9. |
||
33 | |||
34 | TZipMaster is free software: you can redistribute it and/or modify |
||
35 | it under the terms of the GNU Lesser General Public License as published by |
||
36 | the Free Software Foundation, either version 3 of the License, or |
||
37 | (at your option) any later version. |
||
38 | |||
39 | TZipMaster is distributed in the hope that it will be useful, |
||
40 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
41 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
42 | GNU Lesser General Public License for more details. |
||
43 | |||
44 | You should have received a copy of the GNU Lesser General Public License |
||
45 | along with TZipMaster. If not, see <http://www.gnu.org/licenses/>. |
||
46 | |||
47 | contact: problems@delphizip.org (include ZipMaster in the subject). |
||
48 | updates: http://www.delphizip.org |
||
49 | DelphiZip maillist subscribe at http://www.freelists.org/list/delphizip |
||
50 | ************************************************************************/ |
||
51 | |||
52 | |||
53 | ZipFunc::ZipFunc(const DllCommands *C): ZipDflt(C)//, BaseOpts() |
||
54 | { |
||
55 | fndlist = NULL; // quicklist (internal) of found files |
||
56 | IntList = NULL; |
||
57 | // HdrList = NULL; |
||
58 | faction = ADD; // Must be ADD - the default action |
||
59 | fzipstate = -1; |
||
60 | fuser_key = NULL; |
||
61 | fglobal_error_code = 0; |
||
62 | ffiles_acted_on = 0; |
||
63 | CurPW = NULL; |
||
64 | CurBase = NULL; |
||
65 | fzcomlen = 0; |
||
66 | fSpecials = NULL; |
||
67 | fpcount = 0; |
||
68 | ffound = NULL; |
||
69 | fzfiles = NULL; |
||
70 | VerFiles = NULL; |
||
71 | fzfound = NULL; |
||
72 | fzcount = 0; |
||
73 | flatest = 0; |
||
74 | ffcount = 0; |
||
75 | faction = 0; |
||
76 | fversion = 0; |
||
77 | fjunk_sfx = 0; |
||
78 | frecurse = 0; |
||
79 | flinkput = 0; |
||
80 | fBatchStarted = 0; |
||
81 | fcenbeg = 0; |
||
82 | fzipbeg = 0; |
||
83 | fAllowGrow = 0; |
||
84 | |||
85 | fhwbuf = NULL; |
||
86 | fpathput = 1; |
||
87 | fdirnames = 1; |
||
88 | |||
89 | // linked list for new files to be added (not yet in ZIP) |
||
90 | ffnxt = &ffound; |
||
91 | fadjust = 1; |
||
92 | fEncodeAs = C->fEncodeAs; // write strings |
||
93 | fArchiveFiles = C->fOptions.ArchiveFilesOnly; |
||
94 | fResetArchiveBit = C->fOptions.ResetArchiveBit; |
||
95 | // build the conventional cmd line switches |
||
96 | if (C->fOptions.NoDirEntries) // Do not add directory entries -D |
||
97 | fdirnames = 0; |
||
98 | if (C->fOptions.Grow) // Allow appending to a zip file -g Normally TRUE |
||
99 | fAllowGrow = 255; |
||
100 | if (C->fOptions.JunkDir) // Junk directory names -j |
||
101 | fpathput = 0; |
||
102 | if (C->fOptions.JunkSFX) // Junk sfx prefix |
||
103 | fjunk_sfx = 1; |
||
104 | if (C->fOptions.Move) // Delete files added or updated in zip file -m |
||
105 | fdispose = 1; |
||
106 | if (C->fOptions.LatestTime) // Set zip file time to time of latest file in it -o |
||
107 | flatest = 1; |
||
108 | if (fNTFSStamps) |
||
109 | fdirnames = 0; |
||
110 | |||
111 | fHowToMove = C->fOptions.HowToMove; |
||
112 | fNoPrecalc = C->fOptions.NoPrecalc; |
||
113 | fGEncrypt = C->fOptions.Encrypt; |
||
114 | frecurse = C->fOptions.Recurse; |
||
115 | fbefore = C->fDate; |
||
116 | fversion = C->fOptions.Versioning; |
||
117 | VerDate = 0; |
||
118 | } |
||
119 | |||
120 | ZipFunc::~ZipFunc(void) |
||
121 | { |
||
122 | if (fSpecials) { |
||
123 | delete fSpecials; |
||
124 | fSpecials = NULL; |
||
125 | } |
||
126 | ZipCleanup(); // something may have failed |
||
127 | if (CurPW) { |
||
128 | PWRec* t, *p = CurPW; |
||
129 | CurPW = 0; |
||
130 | while (p) |
||
131 | { |
||
132 | t = p; |
||
133 | p = p->Next; |
||
134 | delete t; |
||
135 | } |
||
136 | } |
||
137 | if (CurBase) { |
||
138 | BaseRec* t, *p = CurBase; |
||
139 | CurBase = 0; |
||
140 | while (p) |
||
141 | { |
||
142 | t = p; |
||
143 | p = p->Next; |
||
144 | delete t; |
||
145 | } |
||
146 | } |
||
147 | |||
148 | if (IntList) |
||
149 | { |
||
150 | delete IntList; |
||
151 | IntList = NULL; |
||
152 | } |
||
153 | |||
154 | if (fndlist) |
||
155 | { |
||
156 | delete fndlist; |
||
157 | fndlist = NULL; |
||
158 | } |
||
159 | |||
160 | FndItem *f; // steps through found list |
||
161 | ZipItem *z; // pointer to next entry in zfiles list |
||
162 | while (ffound != NULL) |
||
163 | { |
||
164 | f = ffound; |
||
165 | ffound = f->nxt; |
||
166 | delete f; |
||
167 | } |
||
168 | |||
169 | while (fzfiles != NULL) |
||
170 | { |
||
171 | z = fzfiles; |
||
172 | fzfiles = z->nxt; |
||
173 | delete z; |
||
174 | } |
||
175 | |||
176 | while (VerFiles != NULL) |
||
177 | { |
||
178 | z = VerFiles; |
||
179 | VerFiles = z->nxt; |
||
180 | delete z; |
||
181 | } |
||
182 | |||
183 | while (fzfound != NULL) |
||
184 | { |
||
185 | z = fzfound; |
||
186 | fzfound = z->nxt; |
||
187 | delete z; |
||
188 | } |
||
189 | } |
||
190 | |||
191 | int ZipFunc::Init(void) // after construction |
||
192 | { |
||
193 | int r = ZipDflt::Init(); |
||
194 | if (r) |
||
195 | return r; |
||
196 | // do active initialisation |
||
197 | |||
198 | DZStrW cd = CB->UserArg(zcbRootDir, 0, 0); |
||
199 | if (cd.IsEmpty()) |
||
200 | cd = _T(".\\"); // use current |
||
201 | |||
202 | if (!GetFullPathName(cd, MAX_PATH, fRootDir.GetBuffer(MAX_PATH), NULL)) |
||
203 | { |
||
204 | throw DZFatalException(DZ_ERM_MEMORY); |
||
205 | } |
||
206 | fRootDir.ReleaseBuffer(); |
||
207 | if (fRootDir.LastChar() != BSLASH) |
||
208 | fRootDir += BSLASH; |
||
209 | AddBase(fRootDir, true); |
||
210 | |||
211 | fGPassword = CB->UserArg(zcbPassword, 0, 0); |
||
212 | AddPW(fGPassword, true); |
||
213 | |||
214 | return 0; |
||
215 | } |
||
216 | |||
217 | PWRec::PWRec(const DZStrA &pw) |
||
218 | { |
||
219 | fpw = NULL; |
||
220 | if (!pw.IsEmpty()) |
||
221 | fpw = DupStr(pw); |
||
222 | fnext = NULL; |
||
223 | } |
||
224 | |||
225 | PWRec::~PWRec() |
||
226 | { |
||
227 | delete[] fpw; |
||
228 | } |
||
229 | |||
230 | |||
231 | BaseRec::BaseRec(const DZStrW &base) |
||
232 | { |
||
233 | fbase = DupStr(base); |
||
234 | fnext = NULL; |
||
235 | } |
||
236 | |||
237 | BaseRec::~BaseRec() |
||
238 | { |
||
239 | delete[] fbase; |
||
240 | } |
||
241 | |||
242 | XItem::XItem() |
||
243 | { |
||
244 | finame = NULL; |
||
245 | fxname = NULL; |
||
246 | fhname = NULL; |
||
247 | options._opts = 0; |
||
248 | Base = NULL; |
||
249 | Passw = NULL; |
||
250 | len = 0; |
||
251 | } |
||
252 | |||
253 | XItem::~XItem() |
||
254 | { |
||
255 | if (fhname) |
||
256 | delete[] fhname; |
||
257 | if (finame) |
||
258 | delete[] finame; |
||
259 | if (fxname) |
||
260 | delete[] fxname; |
||
261 | // does not own Base or Passw |
||
262 | } |
||
263 | |||
264 | XItem::XItem(const XItem& other) |
||
265 | { |
||
266 | fhname = NULL; |
||
267 | finame = NULL; |
||
268 | fxname = NULL; |
||
269 | options._opts = 0; |
||
270 | if (other.hname) |
||
271 | fhname = zstrdupB(other.hname); |
||
272 | if (other.iname) |
||
273 | finame = zstrdup(other.iname); |
||
274 | if (other.xname) |
||
275 | fxname = zstrdup(other.xname); |
||
276 | // how = other.how; |
||
277 | Base = other.Base; |
||
278 | Passw = other.Passw; |
||
279 | // does not copy options or cextra |
||
280 | } |
||
281 | |||
282 | XItem& XItem::operator=(const XItem& other) |
||
283 | { |
||
284 | if (&other != this) { |
||
285 | if (fhname) |
||
286 | delete[] fhname; |
||
287 | if (finame) |
||
288 | delete finame; |
||
289 | if (fxname) |
||
290 | delete[] fxname; |
||
291 | fhname = NULL; |
||
292 | finame = NULL; |
||
293 | fxname = NULL; |
||
294 | if (other.hname) |
||
295 | fhname = zstrdupB(other.hname); |
||
296 | if (other.iname) |
||
297 | finame = zstrdup(other.iname); |
||
298 | if (other.xname) |
||
299 | fxname = zstrdup(other.xname); |
||
300 | Base = other.Base; |
||
301 | Passw = other.Passw; |
||
302 | // does not copy options or cextra |
||
303 | options._opts = other.options._opts; |
||
304 | } |
||
305 | return *this; |
||
306 | } |
||
307 | |||
308 | DZStrW __fastcall XItem::FullPath(void) const |
||
309 | { |
||
310 | if (!Is_DrvEx(xname)) |
||
311 | { |
||
312 | DZStrW tmp(Base); |
||
313 | tmp += xname; |
||
314 | return tmp; |
||
315 | } |
||
316 | return DZStrW(xname); |
||
317 | } |
||
318 | |||
319 | void __fastcall XItem::Setxname(const TCHAR *value) |
||
320 | { |
||
321 | if (fxname) |
||
322 | delete[] fxname; |
||
323 | fxname = NULL; |
||
324 | if (value) |
||
325 | fxname = zstrdup(value); |
||
326 | } |
||
327 | |||
328 | |||
329 | void __fastcall XItem::Setiname(const TCHAR *value) |
||
330 | { |
||
331 | if (finame) |
||
332 | delete[] finame; |
||
333 | finame = NULL; |
||
334 | if (value) |
||
335 | finame = zstrdup(value); |
||
336 | } |
||
337 | |||
338 | void __fastcall XItem::Sethname(const char* value) |
||
339 | { |
||
340 | if (fhname) |
||
341 | delete[] fhname; |
||
342 | fhname = NULL; |
||
343 | if (value) |
||
344 | fhname = zstrdupB(value); |
||
345 | } |
||
346 | |||
347 | bool __fastcall XItem::GetIsFolder(void) const |
||
348 | { |
||
349 | return finame[_tcslen(finame)- 1] == BSLASH; |
||
350 | } |
||
351 | |||
352 | HL_node::HL_node() |
||
353 | { |
||
354 | nxt = NULL; |
||
355 | hash = 0; |
||
356 | xdata = NULL; |
||
357 | }; |
||
358 | |||
359 | HL_block::HL_block(HL_block *prev) |
||
360 | { |
||
361 | prv = prev; |
||
362 | memset(nodes, 0, sizeof(nodes)); |
||
363 | } |
||
364 | |||
365 | HL_block::~HL_block(void) |
||
366 | { |
||
367 | if (prv) |
||
368 | { |
||
369 | HL_block *tmp = prv; |
||
370 | prv = NULL; |
||
371 | delete tmp; |
||
372 | } |
||
373 | } |
||
374 | |||
375 | typedef HL_node* PHL_node; |
||
376 | |||
377 | HashList::HashList(int siz) |
||
378 | { |
||
379 | int size = 512; // smallest allowing MAX_PATH strings |
||
380 | while (size < 16384 && size < siz) |
||
381 | size += size; |
||
382 | Mask = size - 1; |
||
383 | Table = new PHL_node[size]; |
||
384 | memset(Table, 0, size * sizeof(PHL_node)); |
||
385 | blocks = NULL; |
||
386 | nno = 0; |
||
387 | } |
||
388 | |||
389 | HashList::~HashList(void) |
||
390 | { |
||
391 | if (blocks) |
||
392 | delete blocks; |
||
393 | delete [] Table; |
||
394 | } |
||
395 | |||
396 | |||
397 | HL_node * HashList::NewNode(const XItem *x, ulg hash) |
||
398 | { |
||
399 | if (!blocks || nno >= NODE_BLOCK_SIZE) |
||
400 | { |
||
401 | blocks = new HL_block(blocks); |
||
402 | nno = 0; |
||
403 | } |
||
404 | HL_node *ret = &blocks->nodes[nno++]; |
||
405 | ret->nxt = NULL; |
||
406 | ret->hash = hash; |
||
407 | ret->xdata = x; |
||
408 | return ret; |
||
409 | } |
||
410 | |||
411 | const XItem *HashList::AddANode(const XItem *xname) |
||
412 | { |
||
413 | HL_node *lr, *lt; |
||
414 | lr = Prepare(); |
||
415 | if (!lr) |
||
416 | { |
||
417 | // no entries |
||
418 | Table[Index] = NewNode(xname, Hash); // add it |
||
419 | return NULL; |
||
420 | } |
||
421 | lt = NULL; |
||
422 | while (lr) |
||
423 | { |
||
424 | if (Hash == lr->hash && Matches(lr)) |
||
425 | { |
||
426 | // exists |
||
427 | return lr->xdata; // return existing |
||
428 | } |
||
429 | |||
430 | lt = lr; |
||
431 | lr = lr->nxt; |
||
432 | } |
||
433 | // chain it to lt |
||
434 | if (lt) |
||
435 | lt->nxt = NewNode(xname, Hash); |
||
436 | |||
437 | return NULL; |
||
438 | } |
||
439 | |||
440 | XItem *HashList::FindAName(void) |
||
441 | { |
||
442 | HL_node* lr = Prepare(); |
||
443 | while (lr) // search chain |
||
444 | { |
||
445 | if (Hash == lr->hash && Matches(lr)) |
||
446 | break; // exists @lr |
||
447 | lr = lr->nxt; |
||
448 | } |
||
449 | if (lr) |
||
450 | return (XItem*)lr->xdata; |
||
451 | return NULL; |
||
452 | } |
||
453 | |||
454 | HashListExt::~HashListExt(void) |
||
455 | { |
||
456 | // |
||
457 | } |
||
458 | |||
459 | XItem *HashListExt::FindName(const DZStrW& name) |
||
460 | { |
||
461 | fxname = name; |
||
462 | return FindAName(); |
||
463 | } |
||
464 | |||
465 | // returns pointer to existing entry if duplicate |
||
466 | const XItem *HashListExt::AddNode(const XItem *xname) |
||
467 | { |
||
468 | fxname = xname->XName; |
||
469 | return AddANode(xname); |
||
470 | } |
||
471 | |||
472 | bool HashListExt::Matches(const HL_node *node) const |
||
473 | { |
||
474 | return fxname.CompareNoCase(node->xdata->XName) == 0; |
||
475 | } |
||
476 | |||
477 | HL_node* HashListExt::Prepare(void) |
||
478 | { |
||
479 | fxname.ToUpper(); |
||
480 | int len = fxname.length(); |
||
481 | Hash = crc32(0, (uch*)fxname.c_str(), len * sizeof(TCHAR)); |
||
482 | Index = Hash & Mask; |
||
483 | Hash = (Hash & ~Mask) | (len & Mask); |
||
484 | return Table[Index]; |
||
485 | } |
||
486 | |||
487 | HashListInt::~HashListInt(void) |
||
488 | { |
||
489 | // |
||
490 | } |
||
491 | |||
492 | XItem *HashListInt::FindName(const DZStrW& name) |
||
493 | { |
||
494 | finame = name; |
||
495 | return FindAName(); |
||
496 | } |
||
497 | |||
498 | // returns pointer to existing entry if duplicate |
||
499 | const XItem *HashListInt::AddNode(const XItem *xname) |
||
500 | { |
||
501 | finame = xname->IName; |
||
502 | return AddANode(xname); |
||
503 | } |
||
504 | |||
505 | bool HashListInt::Matches(const HL_node *node) const |
||
506 | { |
||
507 | return finame.CompareNoCase(node->xdata->IName) == 0; |
||
508 | } |
||
509 | |||
510 | HL_node* HashListInt::Prepare(void) |
||
511 | { |
||
512 | finame.ToUpper(); |
||
513 | int len = finame.length(); |
||
514 | Hash = crc32(0, (uch*)finame.c_str(), len * sizeof(TCHAR)); |
||
515 | Index = Hash & Mask; |
||
516 | Hash = (Hash & ~Mask) | (len & Mask); |
||
517 | return Table[Index]; |
||
518 | } |
||
519 | |||
520 | ZipItem::ZipItem() : XItem() |
||
521 | { |
||
522 | vem = 0; |
||
523 | ver = 0; |
||
524 | flg = 0; |
||
525 | how = 0; |
||
526 | nam = 0; |
||
527 | ext = 0; |
||
528 | cext = 0; |
||
529 | com = 0; |
||
530 | dsk = 0; |
||
531 | att = 0; |
||
532 | lflg = 0; |
||
533 | atx = 0; |
||
534 | tim = 0; |
||
535 | crc = 0; |
||
536 | siz = 0; |
||
537 | off = 0; |
||
538 | fextra = NULL; |
||
539 | fcextra = NULL; |
||
540 | fcomment = NULL; |
||
541 | fntfs = NULL; |
||
542 | mark = 0; |
||
543 | trash = 0; |
||
544 | nxt = NULL; |
||
545 | } |
||
546 | |||
547 | ZipItem::ZipItem(const ZipItem& other): XItem(other) |
||
548 | { |
||
549 | Copy(other); |
||
550 | } |
||
551 | |||
552 | ZipItem& ZipItem::operator=(const ZipItem& other) |
||
553 | { |
||
554 | if (&other != this) |
||
555 | { |
||
556 | *((XItem*)this) = (const XItem&)other; |
||
557 | Copy(other); |
||
558 | nxt = other.nxt; |
||
559 | } |
||
560 | return *this; |
||
561 | } |
||
562 | |||
563 | ZipItem::ZipItem(const FndItem* f): XItem(*f) |
||
564 | { |
||
565 | vem = 0; |
||
566 | ver = 0; |
||
567 | flg = 0; |
||
568 | how = 0; |
||
569 | nam = 0; |
||
570 | ext = 0; |
||
571 | cext = 0; |
||
572 | com = 0; |
||
573 | dsk = 0; |
||
574 | att = 0; |
||
575 | lflg = 0; |
||
576 | atx = 0; |
||
577 | tim = 0; |
||
578 | crc = 0; |
||
579 | siz = 0; |
||
580 | off = 0; |
||
581 | fntfs = NULL; |
||
582 | fcomment = NULL; |
||
583 | mark = 0; |
||
584 | trash = 0; |
||
585 | nxt = NULL; |
||
586 | options = f->options; |
||
587 | len = f->len; // RCV added. |
||
588 | } |
||
589 | |||
590 | ZipItem::~ZipItem() |
||
591 | { |
||
592 | if (fcomment) |
||
593 | delete[] fcomment; |
||
594 | if (fntfs) |
||
595 | delete fntfs; |
||
596 | } |
||
597 | |||
598 | void __fastcall ZipItem::Copy(const ZipItem& other) |
||
599 | { |
||
600 | if (&other != this) |
||
601 | { |
||
602 | vem = other.vem; |
||
603 | ver = other.ver; |
||
604 | flg = other.flg; |
||
605 | how = other.how; |
||
606 | nam = other.nam; |
||
607 | ext = other.ext; |
||
608 | cext = other.cext; |
||
609 | com = other.com; |
||
610 | dsk = other.dsk; |
||
611 | att = other.att; |
||
612 | lflg = other.lflg; |
||
613 | atx = other.atx; |
||
614 | tim = other.tim; |
||
615 | crc = other.crc; |
||
616 | siz = other.siz; |
||
617 | len = other.len; |
||
618 | off = other.off; |
||
619 | mark = other.mark; |
||
620 | trash = other.trash; |
||
621 | nxt = NULL; |
||
622 | fextra = NULL; |
||
623 | fcextra = NULL; |
||
624 | fcomment = NULL; |
||
625 | extra = other.extra; |
||
626 | cextra = other.cextra; |
||
627 | Comment = other.Comment; |
||
628 | |||
629 | fntfs = NULL; |
||
630 | if (other.fntfs) |
||
631 | { |
||
632 | fntfs = new XNTFSData; |
||
633 | memcpy(fntfs, other.ntfs, sizeof(XNTFSData)); |
||
634 | } |
||
635 | } |
||
636 | } |
||
637 | |||
638 | void __fastcall ZipItem::SetComment(const DZStrW& value) |
||
639 | { |
||
640 | if (fcomment) |
||
641 | delete[] fcomment; |
||
642 | fcomment = NULL; |
||
643 | if (value) |
||
644 | { |
||
645 | fcomment = (wchar_t*) DupStr(value); |
||
646 | com = value.length(); |
||
647 | } |
||
648 | else |
||
649 | com = 0; |
||
650 | } |
||
651 | |||
652 | FndItem::FndItem(): XItem() |
||
653 | { |
||
654 | nxt = NULL; |
||
655 | } |
||
656 | |||
657 | FndItem::FndItem(const XItem& other) : XItem(other) |
||
658 | { |
||
659 | nxt = NULL; |
||
660 | } |
||
661 | |||
662 | FndItem::~FndItem() |
||
663 | { |
||
664 | // |
||
665 | } |
||
666 | |||
667 | |||
668 | // ? CompNameExt compare ends of strings for name.ext |
||
669 | int __fastcall SameNameExt(const DZStrW& fname, const DZStrW& oname) |
||
670 | { |
||
671 | if (fname.IsEmpty() || oname.IsEmpty()) |
||
672 | return 0; // cannot do it |
||
673 | int fs, os; |
||
674 | if (fname.LastChar() != oname.LastChar()) |
||
675 | return 0; |
||
676 | fs = fname.ReverseFind(_T('\\')); |
||
677 | os = oname.ReverseFind(_T('\\')); |
||
678 | DZStrW f = fs >= 0 ? fname.Mid(fs+1) : fname; |
||
679 | DZStrW o = os >= 0 ? oname.Mid(os+1) : oname; |
||
680 | return (f.length() == o.length()) ? f.CompareNoCase(o) == 0 : 0; |
||
681 | } |
||
682 |