1 | /*********** File AM Zip C++ Program Source Code File (.CPP) ***********/ |
2 | /* PROGRAM NAME: FILAMZIP */ |
3 | /* ------------- */ |
4 | /* Version 1.3 */ |
5 | /* */ |
6 | /* COPYRIGHT: */ |
7 | /* ---------- */ |
8 | /* (C) Copyright to the author Olivier BERTRAND 2016-2017 */ |
9 | /* */ |
10 | /* WHAT THIS PROGRAM DOES: */ |
11 | /* ----------------------- */ |
12 | /* This program are the ZIP file access method classes. */ |
13 | /* */ |
14 | /***********************************************************************/ |
15 | |
16 | /***********************************************************************/ |
17 | /* Include relevant sections of the System header files. */ |
18 | /***********************************************************************/ |
19 | #include "my_global.h" |
20 | #if !defined(__WIN__) |
21 | #if defined(UNIX) |
22 | #include <fnmatch.h> |
23 | #include <errno.h> |
24 | #include <dirent.h> |
25 | #include <unistd.h> |
26 | #else // !UNIX |
27 | #include <io.h> |
28 | #endif // !UNIX |
29 | #include <fcntl.h> |
30 | #endif // !__WIN__ |
31 | #include <time.h> |
32 | |
33 | /***********************************************************************/ |
34 | /* Include application header files: */ |
35 | /* global.h is header containing all global declarations. */ |
36 | /* plgdbsem.h is header containing the DB application declarations. */ |
37 | /***********************************************************************/ |
38 | #include "global.h" |
39 | #include "plgdbsem.h" |
40 | #include "osutil.h" |
41 | #include "filamtxt.h" |
42 | #include "tabfmt.h" |
43 | //#include "tabzip.h" |
44 | #include "filamzip.h" |
45 | |
46 | #define WRITEBUFFERSIZE (16384) |
47 | |
48 | bool ZipLoadFile(PGLOBAL g, PCSZ zfn, PCSZ fn, PCSZ entry, bool append, bool mul); |
49 | |
50 | /***********************************************************************/ |
51 | /* Compress a file in zip when creating a table. */ |
52 | /***********************************************************************/ |
53 | static bool ZipFile(PGLOBAL g, ZIPUTIL *zutp, PCSZ fn, PCSZ entry, char *buf) |
54 | { |
55 | int rc = RC_OK, size_read, size_buf = WRITEBUFFERSIZE; |
56 | FILE *fin; |
57 | |
58 | if (zutp->addEntry(g, entry)) |
59 | return true; |
60 | else if (!(fin = fopen(fn, "rb" ))) { |
61 | sprintf(g->Message, "error in opening %s for reading" , fn); |
62 | return true; |
63 | } // endif fin |
64 | |
65 | do { |
66 | size_read = (int)fread(buf, 1, size_buf, fin); |
67 | |
68 | if (size_read < size_buf && feof(fin) == 0) { |
69 | sprintf(g->Message, "error in reading %s" , fn); |
70 | rc = RC_FX; |
71 | } // endif size_read |
72 | |
73 | if (size_read > 0) { |
74 | rc = zutp->writeEntry(g, buf, size_read); |
75 | |
76 | if (rc == RC_FX) |
77 | sprintf(g->Message, "error in writing %s in the zipfile" , fn); |
78 | |
79 | } // endif size_read |
80 | |
81 | } while (rc == RC_OK && size_read > 0); |
82 | |
83 | fclose(fin); |
84 | zutp->closeEntry(); |
85 | return rc != RC_OK; |
86 | } // end of ZipFile |
87 | |
88 | /***********************************************************************/ |
89 | /* Find and Compress several files in zip when creating a table. */ |
90 | /***********************************************************************/ |
91 | static bool ZipFiles(PGLOBAL g, ZIPUTIL *zutp, PCSZ pat, char *buf) |
92 | { |
93 | char filename[_MAX_PATH]; |
94 | int rc; |
95 | |
96 | /*********************************************************************/ |
97 | /* pat is a multiple file name with wildcard characters */ |
98 | /*********************************************************************/ |
99 | strcpy(filename, pat); |
100 | |
101 | #if defined(__WIN__) |
102 | char drive[_MAX_DRIVE], direc[_MAX_DIR]; |
103 | WIN32_FIND_DATA FileData; |
104 | HANDLE hSearch; |
105 | |
106 | _splitpath(filename, drive, direc, NULL, NULL); |
107 | |
108 | // Start searching files in the target directory. |
109 | hSearch = FindFirstFile(filename, &FileData); |
110 | |
111 | if (hSearch == INVALID_HANDLE_VALUE) { |
112 | rc = GetLastError(); |
113 | |
114 | if (rc != ERROR_FILE_NOT_FOUND) { |
115 | FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, |
116 | NULL, GetLastError(), 0, (LPTSTR)&filename, sizeof(filename), NULL); |
117 | sprintf(g->Message, MSG(BAD_FILE_HANDLE), filename); |
118 | return true; |
119 | } else { |
120 | strcpy(g->Message, "Cannot find any file to load" ); |
121 | return true; |
122 | } // endif rc |
123 | |
124 | } // endif hSearch |
125 | |
126 | while (true) { |
127 | if (!(FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { |
128 | strcat(strcat(strcpy(filename, drive), direc), FileData.cFileName); |
129 | |
130 | if (ZipFile(g, zutp, filename, FileData.cFileName, buf)) { |
131 | FindClose(hSearch); |
132 | return true; |
133 | } // endif ZipFile |
134 | |
135 | } // endif dwFileAttributes |
136 | |
137 | if (!FindNextFile(hSearch, &FileData)) { |
138 | rc = GetLastError(); |
139 | |
140 | if (rc != ERROR_NO_MORE_FILES) { |
141 | sprintf(g->Message, MSG(NEXT_FILE_ERROR), rc); |
142 | FindClose(hSearch); |
143 | return true; |
144 | } // endif rc |
145 | |
146 | break; |
147 | } // endif FindNextFile |
148 | |
149 | } // endwhile n |
150 | |
151 | // Close the search handle. |
152 | if (!FindClose(hSearch)) { |
153 | strcpy(g->Message, MSG(SRCH_CLOSE_ERR)); |
154 | return true; |
155 | } // endif FindClose |
156 | |
157 | #else // !__WIN__ |
158 | struct stat fileinfo; |
159 | char fn[FN_REFLEN], direc[FN_REFLEN], pattern[FN_HEADLEN], ftype[FN_EXTLEN]; |
160 | DIR *dir; |
161 | struct dirent *entry; |
162 | |
163 | _splitpath(filename, NULL, direc, pattern, ftype); |
164 | strcat(pattern, ftype); |
165 | |
166 | // Start searching files in the target directory. |
167 | if (!(dir = opendir(direc))) { |
168 | sprintf(g->Message, MSG(BAD_DIRECTORY), direc, strerror(errno)); |
169 | return true; |
170 | } // endif dir |
171 | |
172 | while ((entry = readdir(dir))) { |
173 | strcat(strcpy(fn, direc), entry->d_name); |
174 | |
175 | if (lstat(fn, &fileinfo) < 0) { |
176 | sprintf(g->Message, "%s: %s" , fn, strerror(errno)); |
177 | return true; |
178 | } else if (!S_ISREG(fileinfo.st_mode)) |
179 | continue; // Not a regular file (should test for links) |
180 | |
181 | /*******************************************************************/ |
182 | /* Test whether the file name matches the table name filter. */ |
183 | /*******************************************************************/ |
184 | if (fnmatch(pattern, entry->d_name, 0)) |
185 | continue; // Not a match |
186 | |
187 | strcat(strcpy(filename, direc), entry->d_name); |
188 | |
189 | if (ZipFile(g, zutp, filename, entry->d_name, buf)) { |
190 | closedir(dir); |
191 | return true; |
192 | } // endif ZipFile |
193 | |
194 | } // endwhile readdir |
195 | |
196 | // Close the dir handle. |
197 | closedir(dir); |
198 | #endif // !__WIN__ |
199 | |
200 | return false; |
201 | } // end of ZipFiles |
202 | |
203 | /***********************************************************************/ |
204 | /* Load and Compress a file in zip when creating a table. */ |
205 | /***********************************************************************/ |
206 | bool ZipLoadFile(PGLOBAL g, PCSZ zfn, PCSZ fn, PCSZ entry, bool append, bool mul) |
207 | { |
208 | char *buf; |
209 | bool err; |
210 | ZIPUTIL *zutp = new(g) ZIPUTIL(NULL); |
211 | |
212 | if (zutp->open(g, zfn, append)) |
213 | return true; |
214 | |
215 | buf = (char*)PlugSubAlloc(g, NULL, WRITEBUFFERSIZE); |
216 | |
217 | if (mul) |
218 | err = ZipFiles(g, zutp, fn, buf); |
219 | else |
220 | err = ZipFile(g, zutp, fn, entry, buf); |
221 | |
222 | zutp->close(); |
223 | return err; |
224 | } // end of ZipLoadFile |
225 | |
226 | /* -------------------------- class ZIPUTIL -------------------------- */ |
227 | |
228 | /***********************************************************************/ |
229 | /* Constructors. */ |
230 | /***********************************************************************/ |
231 | ZIPUTIL::ZIPUTIL(PCSZ tgt) |
232 | { |
233 | zipfile = NULL; |
234 | target = tgt; |
235 | fp = NULL; |
236 | entryopen = false; |
237 | } // end of ZIPUTIL standard constructor |
238 | |
239 | #if 0 |
240 | ZIPUTIL::ZIPUTIL(ZIPUTIL *zutp) |
241 | { |
242 | zipfile = zutp->zipfile; |
243 | target = zutp->target; |
244 | fp = zutp->fp; |
245 | entryopen = zutp->entryopen; |
246 | } // end of UNZIPUTL copy constructor |
247 | #endif // 0 |
248 | |
249 | /***********************************************************************/ |
250 | /* Fill the zip time structure */ |
251 | /* param: tmZip time structure to be filled */ |
252 | /***********************************************************************/ |
253 | void ZIPUTIL::getTime(tm_zip& tmZip) |
254 | { |
255 | time_t rawtime; |
256 | time(&rawtime); |
257 | struct tm *timeinfo = localtime(&rawtime); |
258 | tmZip.tm_sec = timeinfo->tm_sec; |
259 | tmZip.tm_min = timeinfo->tm_min; |
260 | tmZip.tm_hour = timeinfo->tm_hour; |
261 | tmZip.tm_mday = timeinfo->tm_mday; |
262 | tmZip.tm_mon = timeinfo->tm_mon; |
263 | tmZip.tm_year = timeinfo->tm_year; |
264 | } // end of getTime |
265 | |
266 | /***********************************************************************/ |
267 | /* open a zip file for deflate. */ |
268 | /* param: filename path and the filename of the zip file to open. */ |
269 | /* append: set true to append the zip file */ |
270 | /* return: true if open, false otherwise. */ |
271 | /***********************************************************************/ |
272 | bool ZIPUTIL::open(PGLOBAL g, PCSZ filename, bool append) |
273 | { |
274 | if (!zipfile && !(zipfile = zipOpen64(filename, |
275 | append ? APPEND_STATUS_ADDINZIP |
276 | : APPEND_STATUS_CREATE))) |
277 | sprintf(g->Message, "Zipfile open error on %s" , filename); |
278 | |
279 | return (zipfile == NULL); |
280 | } // end of open |
281 | |
282 | /***********************************************************************/ |
283 | /* Close the zip file. */ |
284 | /***********************************************************************/ |
285 | void ZIPUTIL::close() |
286 | { |
287 | if (zipfile) { |
288 | closeEntry(); |
289 | zipClose(zipfile, 0); |
290 | zipfile = NULL; |
291 | } // endif zipfile |
292 | |
293 | if (fp) |
294 | fp->Count = 0; |
295 | |
296 | } // end of close |
297 | |
298 | /***********************************************************************/ |
299 | /* OpenTableFile: Open a DOS/UNIX table file from a ZIP file. */ |
300 | /***********************************************************************/ |
301 | bool ZIPUTIL::OpenTable(PGLOBAL g, MODE mode, PCSZ fn, bool append) |
302 | { |
303 | /*********************************************************************/ |
304 | /* The file will be compressed. */ |
305 | /*********************************************************************/ |
306 | if (mode == MODE_INSERT) { |
307 | bool b = open(g, fn, append); |
308 | |
309 | if (!b) { |
310 | if (addEntry(g, target)) |
311 | return true; |
312 | |
313 | /*****************************************************************/ |
314 | /* Link a Fblock. This make possible to automatically close it */ |
315 | /* in case of error g->jump. */ |
316 | /*****************************************************************/ |
317 | PDBUSER dbuserp = (PDBUSER)g->Activityp->Aptr; |
318 | |
319 | fp = (PFBLOCK)PlugSubAlloc(g, NULL, sizeof(FBLOCK)); |
320 | fp->Type = TYPE_FB_ZIP; |
321 | fp->Fname = PlugDup(g, fn); |
322 | fp->Next = dbuserp->Openlist; |
323 | dbuserp->Openlist = fp; |
324 | fp->Count = 1; |
325 | fp->Length = 0; |
326 | fp->Memory = NULL; |
327 | fp->Mode = mode; |
328 | fp->File = this; |
329 | fp->Handle = 0; |
330 | } else |
331 | return true; |
332 | |
333 | } else { |
334 | strcpy(g->Message, "Only INSERT mode supported for ZIPPING files" ); |
335 | return true; |
336 | } // endif mode |
337 | |
338 | return false; |
339 | } // end of OpenTableFile |
340 | |
341 | /***********************************************************************/ |
342 | /* Add target in zip file. */ |
343 | /***********************************************************************/ |
344 | bool ZIPUTIL::addEntry(PGLOBAL g, PCSZ entry) |
345 | { |
346 | //?? we dont need the stinking time |
347 | zip_fileinfo zi = { {0, 0, 0, 0, 0, 0}, 0, 0, 0 }; |
348 | |
349 | getTime(zi.tmz_date); |
350 | target = entry; |
351 | |
352 | int err = zipOpenNewFileInZip(zipfile, target, &zi, |
353 | NULL, 0, NULL, 0, NULL, Z_DEFLATED, Z_DEFAULT_COMPRESSION); |
354 | |
355 | return !(entryopen = (err == ZIP_OK)); |
356 | } // end of addEntry |
357 | |
358 | /***********************************************************************/ |
359 | /* writeEntry: Deflate the buffer to the zip file. */ |
360 | /***********************************************************************/ |
361 | int ZIPUTIL::writeEntry(PGLOBAL g, char *buf, int len) |
362 | { |
363 | if (zipWriteInFileInZip(zipfile, buf, len) < 0) { |
364 | sprintf(g->Message, "Error writing %s in the zipfile" , target); |
365 | return RC_FX; |
366 | } // endif zipWriteInFileInZip |
367 | |
368 | return RC_OK; |
369 | } // end of writeEntry |
370 | |
371 | /***********************************************************************/ |
372 | /* Close the zip file. */ |
373 | /***********************************************************************/ |
374 | void ZIPUTIL::closeEntry() |
375 | { |
376 | if (entryopen) { |
377 | zipCloseFileInZip(zipfile); |
378 | entryopen = false; |
379 | } // endif entryopen |
380 | |
381 | } // end of closeEntry |
382 | |
383 | /* ------------------------- class UNZIPUTL -------------------------- */ |
384 | |
385 | /***********************************************************************/ |
386 | /* Constructors. */ |
387 | /***********************************************************************/ |
388 | UNZIPUTL::UNZIPUTL(PCSZ tgt, bool mul) |
389 | { |
390 | zipfile = NULL; |
391 | target = tgt; |
392 | pwd = NULL; |
393 | fp = NULL; |
394 | memory = NULL; |
395 | size = 0; |
396 | entryopen = false; |
397 | multiple = mul; |
398 | memset(fn, 0, sizeof(fn)); |
399 | |
400 | // Init the case mapping table. |
401 | #if defined(__WIN__) |
402 | for (int i = 0; i < 256; ++i) mapCaseTable[i] = toupper(i); |
403 | #else |
404 | for (int i = 0; i < 256; ++i) mapCaseTable[i] = i; |
405 | #endif |
406 | } // end of UNZIPUTL standard constructor |
407 | |
408 | UNZIPUTL::UNZIPUTL(PDOSDEF tdp) |
409 | { |
410 | zipfile = NULL; |
411 | target = tdp->GetEntry(); |
412 | pwd = tdp->Pwd; |
413 | fp = NULL; |
414 | memory = NULL; |
415 | size = 0; |
416 | entryopen = false; |
417 | multiple = tdp->GetMul(); |
418 | memset(fn, 0, sizeof(fn)); |
419 | |
420 | // Init the case mapping table. |
421 | #if defined(__WIN__) |
422 | for (int i = 0; i < 256; ++i) mapCaseTable[i] = toupper(i); |
423 | #else |
424 | for (int i = 0; i < 256; ++i) mapCaseTable[i] = i; |
425 | #endif |
426 | } // end of UNZIPUTL standard constructor |
427 | |
428 | #if 0 |
429 | UNZIPUTL::UNZIPUTL(PZIPUTIL zutp) |
430 | { |
431 | zipfile = zutp->zipfile; |
432 | target = zutp->target; |
433 | fp = zutp->fp; |
434 | finfo = zutp->finfo; |
435 | entryopen = zutp->entryopen; |
436 | multiple = zutp->multiple; |
437 | for (int i = 0; i < 256; ++i) mapCaseTable[i] = zutp->mapCaseTable[i]; |
438 | } // end of UNZIPUTL copy constructor |
439 | #endif // 0 |
440 | |
441 | /***********************************************************************/ |
442 | /* This code is the copyright property of Alessandro Felice Cantatore. */ |
443 | /* http://xoomer.virgilio.it/acantato/dev/wildcard/wildmatch.html */ |
444 | /***********************************************************************/ |
445 | bool UNZIPUTL::WildMatch(PCSZ pat, PCSZ str) { |
446 | PCSZ s, p; |
447 | bool star = FALSE; |
448 | |
449 | loopStart: |
450 | for (s = str, p = pat; *s; ++s, ++p) { |
451 | switch (*p) { |
452 | case '?': |
453 | if (*s == '.') goto starCheck; |
454 | break; |
455 | case '*': |
456 | star = TRUE; |
457 | str = s, pat = p; |
458 | if (!*++pat) return TRUE; |
459 | goto loopStart; |
460 | default: |
461 | if (mapCaseTable[(uint)*s] != mapCaseTable[(uint)*p]) |
462 | goto starCheck; |
463 | break; |
464 | } /* endswitch */ |
465 | } /* endfor */ |
466 | if (*p == '*') ++p; |
467 | return (!*p); |
468 | |
469 | starCheck: |
470 | if (!star) return FALSE; |
471 | str++; |
472 | goto loopStart; |
473 | } // end of WildMatch |
474 | |
475 | /***********************************************************************/ |
476 | /* open a zip file. */ |
477 | /* param: filename path and the filename of the zip file to open. */ |
478 | /* return: true if open, false otherwise. */ |
479 | /***********************************************************************/ |
480 | bool UNZIPUTL::open(PGLOBAL g, PCSZ filename) |
481 | { |
482 | if (!zipfile && !(zipfile = unzOpen64(filename))) |
483 | sprintf(g->Message, "Zipfile open error on %s" , filename); |
484 | |
485 | return (zipfile == NULL); |
486 | } // end of open |
487 | |
488 | /***********************************************************************/ |
489 | /* Close the zip file. */ |
490 | /***********************************************************************/ |
491 | void UNZIPUTL::close() |
492 | { |
493 | if (zipfile) { |
494 | closeEntry(); |
495 | unzClose(zipfile); |
496 | zipfile = NULL; |
497 | } // endif zipfile |
498 | |
499 | if (fp) |
500 | fp->Count = 0; |
501 | |
502 | } // end of close |
503 | |
504 | /***********************************************************************/ |
505 | /* Find next entry matching target pattern. */ |
506 | /***********************************************************************/ |
507 | int UNZIPUTL::findEntry(PGLOBAL g, bool next) |
508 | { |
509 | int rc; |
510 | |
511 | do { |
512 | if (next) { |
513 | rc = unzGoToNextFile(zipfile); |
514 | |
515 | if (rc == UNZ_END_OF_LIST_OF_FILE) |
516 | return RC_EF; |
517 | else if (rc != UNZ_OK) { |
518 | sprintf(g->Message, "unzGoToNextFile rc = %d" , rc); |
519 | return RC_FX; |
520 | } // endif rc |
521 | |
522 | } // endif next |
523 | |
524 | if (target && *target) { |
525 | rc = unzGetCurrentFileInfo(zipfile, NULL, fn, sizeof(fn), |
526 | NULL, 0, NULL, 0); |
527 | if (rc == UNZ_OK) { |
528 | if (WildMatch(target, fn)) |
529 | return RC_OK; |
530 | |
531 | } else { |
532 | sprintf(g->Message, "GetCurrentFileInfo rc = %d" , rc); |
533 | return RC_FX; |
534 | } // endif rc |
535 | |
536 | } else |
537 | return RC_OK; |
538 | |
539 | next = true; |
540 | } while (true); |
541 | |
542 | strcpy(g->Message, "FindNext logical error" ); |
543 | return RC_FX; |
544 | } // end of FindEntry |
545 | |
546 | |
547 | /***********************************************************************/ |
548 | /* Get the next used entry. */ |
549 | /***********************************************************************/ |
550 | int UNZIPUTL::nextEntry(PGLOBAL g) |
551 | { |
552 | if (multiple) { |
553 | int rc; |
554 | |
555 | closeEntry(); |
556 | |
557 | if ((rc = findEntry(g, true)) != RC_OK) |
558 | return rc; |
559 | |
560 | if (openEntry(g)) |
561 | return RC_FX; |
562 | |
563 | return RC_OK; |
564 | } else |
565 | return RC_EF; |
566 | |
567 | } // end of nextEntry |
568 | |
569 | |
570 | /***********************************************************************/ |
571 | /* OpenTableFile: Open a DOS/UNIX table file from a ZIP file. */ |
572 | /***********************************************************************/ |
573 | bool UNZIPUTL::OpenTable(PGLOBAL g, MODE mode, PCSZ fn) |
574 | { |
575 | /*********************************************************************/ |
576 | /* The file will be decompressed into virtual memory. */ |
577 | /*********************************************************************/ |
578 | if (mode == MODE_READ || mode == MODE_ANY) { |
579 | bool b = open(g, fn); |
580 | |
581 | if (!b) { |
582 | int rc; |
583 | |
584 | if (target && *target) { |
585 | if (!multiple) { |
586 | rc = unzLocateFile(zipfile, target, 0); |
587 | |
588 | if (rc == UNZ_END_OF_LIST_OF_FILE) { |
589 | sprintf(g->Message, "Target file %s not in %s" , target, fn); |
590 | return true; |
591 | } else if (rc != UNZ_OK) { |
592 | sprintf(g->Message, "unzLocateFile rc=%d" , rc); |
593 | return true; |
594 | } // endif's rc |
595 | |
596 | } else { |
597 | if ((rc = findEntry(g, false)) == RC_FX) |
598 | return true; |
599 | else if (rc == RC_EF) { |
600 | sprintf(g->Message, "No match of %s in %s" , target, fn); |
601 | return true; |
602 | } // endif rc |
603 | |
604 | } // endif multiple |
605 | |
606 | } // endif target |
607 | |
608 | if (openEntry(g)) |
609 | return true; |
610 | |
611 | if (size > 0) { |
612 | /*******************************************************************/ |
613 | /* Link a Fblock. This make possible to automatically close it */ |
614 | /* in case of error g->jump. */ |
615 | /*******************************************************************/ |
616 | PDBUSER dbuserp = (PDBUSER)g->Activityp->Aptr; |
617 | |
618 | fp = (PFBLOCK)PlugSubAlloc(g, NULL, sizeof(FBLOCK)); |
619 | fp->Type = TYPE_FB_ZIP; |
620 | fp->Fname = PlugDup(g, fn); |
621 | fp->Next = dbuserp->Openlist; |
622 | dbuserp->Openlist = fp; |
623 | fp->Count = 1; |
624 | fp->Length = size; |
625 | fp->Memory = memory; |
626 | fp->Mode = mode; |
627 | fp->File = this; |
628 | fp->Handle = 0; |
629 | } // endif fp |
630 | |
631 | } else |
632 | return true; |
633 | |
634 | } else { |
635 | strcpy(g->Message, "Only READ mode supported for ZIPPED tables" ); |
636 | return true; |
637 | } // endif mode |
638 | |
639 | return false; |
640 | } // end of OpenTableFile |
641 | |
642 | /***********************************************************************/ |
643 | /* Insert only if the entry does not exist. */ |
644 | /***********************************************************************/ |
645 | bool UNZIPUTL::IsInsertOk(PGLOBAL g, PCSZ fn) |
646 | { |
647 | bool ok = true, b = open(g, fn); |
648 | |
649 | if (!b) { |
650 | if (!target || *target == 0) { |
651 | unz_global_info64 ginfo; |
652 | int err = unzGetGlobalInfo64(zipfile, &ginfo); |
653 | |
654 | ok = !(err == UNZ_OK && ginfo.number_entry > 0); |
655 | } else // Check if the target exist |
656 | ok = (unzLocateFile(zipfile, target, 0) != UNZ_OK); |
657 | |
658 | unzClose(zipfile); |
659 | } // endif b |
660 | |
661 | return ok; |
662 | } // end of IsInsertOk |
663 | |
664 | /***********************************************************************/ |
665 | /* Open target in zip file. */ |
666 | /***********************************************************************/ |
667 | bool UNZIPUTL::openEntry(PGLOBAL g) |
668 | { |
669 | int rc; |
670 | |
671 | rc = unzGetCurrentFileInfo(zipfile, &finfo, fn, sizeof(fn), |
672 | NULL, 0, NULL, 0); |
673 | |
674 | if (rc != UNZ_OK) { |
675 | sprintf(g->Message, "unzGetCurrentFileInfo64 rc=%d" , rc); |
676 | return true; |
677 | } else if ((rc = unzOpenCurrentFilePassword(zipfile, pwd)) != UNZ_OK) { |
678 | sprintf(g->Message, "unzOpen fn=%s rc=%d" , fn, rc); |
679 | return true; |
680 | } // endif rc |
681 | |
682 | size = finfo.uncompressed_size; |
683 | |
684 | try { |
685 | memory = new char[size + 1]; |
686 | } catch (...) { |
687 | strcpy(g->Message, "Out of memory" ); |
688 | return true; |
689 | } // end try/catch |
690 | |
691 | if ((rc = unzReadCurrentFile(zipfile, memory, size)) < 0) { |
692 | sprintf(g->Message, "unzReadCurrentFile rc = %d" , rc); |
693 | unzCloseCurrentFile(zipfile); |
694 | delete[] memory; |
695 | memory = NULL; |
696 | entryopen = false; |
697 | } else { |
698 | memory[size] = 0; // Required by some table types (XML) |
699 | entryopen = true; |
700 | } // endif rc |
701 | |
702 | if (trace(1)) |
703 | htrc("Openning entry%s %s\n" , fn, (entryopen) ? "oked" : "failed" ); |
704 | |
705 | return !entryopen; |
706 | } // end of openEntry |
707 | |
708 | /***********************************************************************/ |
709 | /* Close the zip file. */ |
710 | /***********************************************************************/ |
711 | void UNZIPUTL::closeEntry() |
712 | { |
713 | if (entryopen) { |
714 | unzCloseCurrentFile(zipfile); |
715 | entryopen = false; |
716 | } // endif entryopen |
717 | |
718 | if (memory) { |
719 | delete[] memory; |
720 | memory = NULL; |
721 | } // endif memory |
722 | |
723 | } // end of closeEntry |
724 | |
725 | /* -------------------------- class UNZFAM --------------------------- */ |
726 | |
727 | /***********************************************************************/ |
728 | /* Constructors. */ |
729 | /***********************************************************************/ |
730 | UNZFAM::UNZFAM(PDOSDEF tdp) : MAPFAM(tdp) |
731 | { |
732 | zutp = NULL; |
733 | tdfp = tdp; |
734 | //target = tdp->GetEntry(); |
735 | //mul = tdp->GetMul(); |
736 | } // end of UNZFAM standard constructor |
737 | |
738 | UNZFAM::UNZFAM(PUNZFAM txfp) : MAPFAM(txfp) |
739 | { |
740 | zutp = txfp->zutp; |
741 | tdfp = txfp->tdfp; |
742 | //target = txfp->target; |
743 | //mul = txfp->mul; |
744 | } // end of UNZFAM copy constructor |
745 | |
746 | /***********************************************************************/ |
747 | /* ZIP GetFileLength: returns file size in number of bytes. */ |
748 | /***********************************************************************/ |
749 | int UNZFAM::GetFileLength(PGLOBAL g) |
750 | { |
751 | int len = (zutp && zutp->entryopen) ? (int)(Top - Memory) |
752 | : TXTFAM::GetFileLength(g) * 3; |
753 | |
754 | if (trace(1)) |
755 | htrc("Zipped file length=%d\n" , len); |
756 | |
757 | return len; |
758 | } // end of GetFileLength |
759 | |
760 | /***********************************************************************/ |
761 | /* ZIP Cardinality: return the number of rows if possible. */ |
762 | /***********************************************************************/ |
763 | int UNZFAM::Cardinality(PGLOBAL g) |
764 | { |
765 | if (!g) |
766 | return 1; |
767 | |
768 | int card = -1; |
769 | int len = GetFileLength(g); |
770 | |
771 | if (len) { |
772 | // Estimated ??? |
773 | card = (len / (int)Lrecl) * 2; |
774 | card = card ? card : 10; // Lrecl can be too big |
775 | } else |
776 | card = 0; |
777 | |
778 | return card; |
779 | } // end of Cardinality |
780 | |
781 | /***********************************************************************/ |
782 | /* OpenTableFile: Open a DOS/UNIX table file from a ZIP file. */ |
783 | /***********************************************************************/ |
784 | bool UNZFAM::OpenTableFile(PGLOBAL g) |
785 | { |
786 | char filename[_MAX_PATH]; |
787 | MODE mode = Tdbp->GetMode(); |
788 | |
789 | /*********************************************************************/ |
790 | /* Allocate the ZIP utility class. */ |
791 | /*********************************************************************/ |
792 | zutp = new(g) UNZIPUTL(tdfp); |
793 | |
794 | // We used the file name relative to recorded datapath |
795 | PlugSetPath(filename, To_File, Tdbp->GetPath()); |
796 | |
797 | if (!zutp->OpenTable(g, mode, filename)) { |
798 | // The pseudo "buffer" is here the entire real buffer |
799 | Fpos = Mempos = Memory = zutp->memory; |
800 | Top = Memory + zutp->size; |
801 | To_Fb = zutp->fp; // Useful when closing |
802 | } else |
803 | return true; |
804 | |
805 | return false; |
806 | } // end of OpenTableFile |
807 | |
808 | /***********************************************************************/ |
809 | /* GetNext: go to next entry. */ |
810 | /***********************************************************************/ |
811 | int UNZFAM::GetNext(PGLOBAL g) |
812 | { |
813 | int rc = zutp->nextEntry(g); |
814 | |
815 | if (rc != RC_OK) |
816 | return rc; |
817 | |
818 | Mempos = Memory = zutp->memory; |
819 | Top = Memory + zutp->size; |
820 | return RC_OK; |
821 | } // end of GetNext |
822 | |
823 | #if 0 |
824 | /***********************************************************************/ |
825 | /* ReadBuffer: Read one line for a ZIP file. */ |
826 | /***********************************************************************/ |
827 | int UNZFAM::ReadBuffer(PGLOBAL g) |
828 | { |
829 | int rc, len; |
830 | |
831 | // Are we at the end of the memory |
832 | if (Mempos >= Top) { |
833 | if ((rc = zutp->nextEntry(g)) != RC_OK) |
834 | return rc; |
835 | |
836 | Mempos = Memory = zutp->memory; |
837 | Top = Memory + zutp->size; |
838 | } // endif Mempos |
839 | |
840 | #if 0 |
841 | if (!Placed) { |
842 | /*******************************************************************/ |
843 | /* Record file position in case of UPDATE or DELETE. */ |
844 | /*******************************************************************/ |
845 | int rc; |
846 | |
847 | next: |
848 | Fpos = Mempos; |
849 | CurBlk = (int)Rows++; |
850 | |
851 | /*******************************************************************/ |
852 | /* Check whether optimization on ROWID */ |
853 | /* can be done, as well as for join as for local filtering. */ |
854 | /*******************************************************************/ |
855 | switch (Tdbp->TestBlock(g)) { |
856 | case RC_EF: |
857 | return RC_EF; |
858 | case RC_NF: |
859 | // Skip this record |
860 | if ((rc = SkipRecord(g, false)) != RC_OK) |
861 | return rc; |
862 | |
863 | goto next; |
864 | } // endswitch rc |
865 | |
866 | } else |
867 | Placed = false; |
868 | #else |
869 | // Perhaps unuseful |
870 | Fpos = Mempos; |
871 | CurBlk = (int)Rows++; |
872 | Placed = false; |
873 | #endif |
874 | |
875 | // Immediately calculate next position (Used by DeleteDB) |
876 | while (*Mempos++ != '\n'); // What about Unix ??? |
877 | |
878 | // Set caller line buffer |
879 | len = (Mempos - Fpos) - 1; |
880 | |
881 | // Don't rely on ENDING setting |
882 | if (len > 0 && *(Mempos - 2) == '\r') |
883 | len--; // Line ends by CRLF |
884 | |
885 | memcpy(Tdbp->GetLine(), Fpos, len); |
886 | Tdbp->GetLine()[len] = '\0'; |
887 | return RC_OK; |
888 | } // end of ReadBuffer |
889 | |
890 | /***********************************************************************/ |
891 | /* Table file close routine for MAP access method. */ |
892 | /***********************************************************************/ |
893 | void UNZFAM::CloseTableFile(PGLOBAL g, bool) |
894 | { |
895 | close(); |
896 | } // end of CloseTableFile |
897 | #endif // 0 |
898 | |
899 | /* -------------------------- class UZXFAM --------------------------- */ |
900 | |
901 | /***********************************************************************/ |
902 | /* Constructors. */ |
903 | /***********************************************************************/ |
904 | UZXFAM::UZXFAM(PDOSDEF tdp) : MPXFAM(tdp) |
905 | { |
906 | zutp = NULL; |
907 | tdfp = tdp; |
908 | //target = tdp->GetEntry(); |
909 | //mul = tdp->GetMul(); |
910 | //Lrecl = tdp->GetLrecl(); |
911 | } // end of UZXFAM standard constructor |
912 | |
913 | UZXFAM::UZXFAM(PUZXFAM txfp) : MPXFAM(txfp) |
914 | { |
915 | zutp = txfp->zutp; |
916 | tdfp = txfp->tdfp; |
917 | //target = txfp->target; |
918 | //mul = txfp->mul; |
919 | //Lrecl = txfp->Lrecl; |
920 | } // end of UZXFAM copy constructor |
921 | |
922 | /***********************************************************************/ |
923 | /* ZIP GetFileLength: returns file size in number of bytes. */ |
924 | /***********************************************************************/ |
925 | int UZXFAM::GetFileLength(PGLOBAL g) |
926 | { |
927 | int len; |
928 | |
929 | if (!zutp && OpenTableFile(g)) |
930 | return 0; |
931 | |
932 | if (zutp->entryopen) |
933 | len = zutp->size; |
934 | else |
935 | len = 0; |
936 | |
937 | return len; |
938 | } // end of GetFileLength |
939 | |
940 | /***********************************************************************/ |
941 | /* ZIP Cardinality: return the number of rows if possible. */ |
942 | /***********************************************************************/ |
943 | int UZXFAM::Cardinality(PGLOBAL g) |
944 | { |
945 | if (!g) |
946 | return 1; |
947 | |
948 | int card = -1; |
949 | int len = GetFileLength(g); |
950 | |
951 | if (!(len % Lrecl)) |
952 | card = len / (int)Lrecl; // Fixed length file |
953 | else |
954 | sprintf(g->Message, MSG(NOT_FIXED_LEN), zutp->fn, len, Lrecl); |
955 | |
956 | // Set number of blocks for later use |
957 | Block = (card > 0) ? (card + Nrec - 1) / Nrec : 0; |
958 | return card; |
959 | } // end of Cardinality |
960 | |
961 | /***********************************************************************/ |
962 | /* OpenTableFile: Open a DOS/UNIX table file from a ZIP file. */ |
963 | /***********************************************************************/ |
964 | bool UZXFAM::OpenTableFile(PGLOBAL g) |
965 | { |
966 | // May have been already opened in GetFileLength |
967 | if (!zutp || !zutp->zipfile) { |
968 | char filename[_MAX_PATH]; |
969 | MODE mode = Tdbp->GetMode(); |
970 | |
971 | /*********************************************************************/ |
972 | /* Allocate the ZIP utility class. */ |
973 | /*********************************************************************/ |
974 | if (!zutp) |
975 | zutp = new(g)UNZIPUTL(tdfp); |
976 | |
977 | // We used the file name relative to recorded datapath |
978 | PlugSetPath(filename, To_File, Tdbp->GetPath()); |
979 | |
980 | if (!zutp->OpenTable(g, mode, filename)) { |
981 | // The pseudo "buffer" is here the entire real buffer |
982 | Memory = zutp->memory; |
983 | Fpos = Mempos = Memory + Headlen; |
984 | Top = Memory + zutp->size; |
985 | To_Fb = zutp->fp; // Useful when closing |
986 | } else |
987 | return true; |
988 | |
989 | } else |
990 | Reset(); |
991 | |
992 | return false; |
993 | } // end of OpenTableFile |
994 | |
995 | /***********************************************************************/ |
996 | /* GetNext: go to next entry. */ |
997 | /***********************************************************************/ |
998 | int UZXFAM::GetNext(PGLOBAL g) |
999 | { |
1000 | int rc = zutp->nextEntry(g); |
1001 | |
1002 | if (rc != RC_OK) |
1003 | return rc; |
1004 | |
1005 | int len = zutp->size; |
1006 | |
1007 | if (len % Lrecl) { |
1008 | sprintf(g->Message, MSG(NOT_FIXED_LEN), zutp->fn, len, Lrecl); |
1009 | return RC_FX; |
1010 | } // endif size |
1011 | |
1012 | Memory = zutp->memory; |
1013 | Top = Memory + len; |
1014 | Rewind(); |
1015 | return RC_OK; |
1016 | } // end of GetNext |
1017 | |
1018 | /* -------------------------- class ZIPFAM --------------------------- */ |
1019 | |
1020 | /***********************************************************************/ |
1021 | /* Constructor. */ |
1022 | /***********************************************************************/ |
1023 | ZIPFAM::ZIPFAM(PDOSDEF tdp) : DOSFAM(tdp) |
1024 | { |
1025 | zutp = NULL; |
1026 | target = tdp->GetEntry(); |
1027 | append = tdp->GetAppend(); |
1028 | } // end of ZIPFAM standard constructor |
1029 | |
1030 | /***********************************************************************/ |
1031 | /* OpenTableFile: Open a DOS/UNIX table file from a ZIP file. */ |
1032 | /***********************************************************************/ |
1033 | bool ZIPFAM::OpenTableFile(PGLOBAL g) |
1034 | { |
1035 | char filename[_MAX_PATH]; |
1036 | MODE mode = Tdbp->GetMode(); |
1037 | int len = TXTFAM::GetFileLength(g); |
1038 | |
1039 | // We used the file name relative to recorded datapath |
1040 | PlugSetPath(filename, To_File, Tdbp->GetPath()); |
1041 | |
1042 | if (len < 0) |
1043 | return true; |
1044 | else if (!append && len > 0) { |
1045 | strcpy(g->Message, "No insert into existing zip file" ); |
1046 | return true; |
1047 | } else if (append && len > 0) { |
1048 | UNZIPUTL *zutp = new(g) UNZIPUTL(target, false); |
1049 | |
1050 | if (!zutp->IsInsertOk(g, filename)) { |
1051 | strcpy(g->Message, "No insert into existing entry" ); |
1052 | return true; |
1053 | } // endif Ok |
1054 | |
1055 | } // endif's |
1056 | |
1057 | /*********************************************************************/ |
1058 | /* Allocate the ZIP utility class. */ |
1059 | /*********************************************************************/ |
1060 | zutp = new(g) ZIPUTIL(target); |
1061 | |
1062 | // We used the file name relative to recorded datapath |
1063 | PlugSetPath(filename, To_File, Tdbp->GetPath()); |
1064 | |
1065 | if (!zutp->OpenTable(g, mode, filename, append)) { |
1066 | To_Fb = zutp->fp; // Useful when closing |
1067 | } else |
1068 | return true; |
1069 | |
1070 | return AllocateBuffer(g); |
1071 | } // end of OpenTableFile |
1072 | |
1073 | /***********************************************************************/ |
1074 | /* ReadBuffer: Read one line for a ZIP file. */ |
1075 | /***********************************************************************/ |
1076 | int ZIPFAM::ReadBuffer(PGLOBAL g) |
1077 | { |
1078 | strcpy(g->Message, "ReadBuffer should not been called when zipping" ); |
1079 | return RC_FX; |
1080 | } // end of ReadBuffer |
1081 | |
1082 | /***********************************************************************/ |
1083 | /* WriteBuffer: Deflate the buffer to the zip file. */ |
1084 | /***********************************************************************/ |
1085 | int ZIPFAM::WriteBuffer(PGLOBAL g) |
1086 | { |
1087 | int len; |
1088 | |
1089 | // Prepare to write the new line |
1090 | strcat(strcpy(To_Buf, Tdbp->GetLine()), (Bin) ? CrLf : "\n" ); |
1091 | len = (int)(strchr(To_Buf, '\n') - To_Buf + 1); |
1092 | return zutp->writeEntry(g, To_Buf, len); |
1093 | } // end of WriteBuffer |
1094 | |
1095 | /***********************************************************************/ |
1096 | /* Table file close routine for ZIP access method. */ |
1097 | /***********************************************************************/ |
1098 | void ZIPFAM::CloseTableFile(PGLOBAL g, bool) |
1099 | { |
1100 | To_Fb->Count = 0; |
1101 | zutp->close(); |
1102 | } // end of CloseTableFile |
1103 | |
1104 | /* -------------------------- class ZPXFAM --------------------------- */ |
1105 | |
1106 | /***********************************************************************/ |
1107 | /* Constructor. */ |
1108 | /***********************************************************************/ |
1109 | ZPXFAM::ZPXFAM(PDOSDEF tdp) : FIXFAM(tdp) |
1110 | { |
1111 | zutp = NULL; |
1112 | target = tdp->GetEntry(); |
1113 | append = tdp->GetAppend(); |
1114 | //Lrecl = tdp->GetLrecl(); |
1115 | } // end of ZPXFAM standard constructor |
1116 | |
1117 | /***********************************************************************/ |
1118 | /* OpenTableFile: Open a DOS/UNIX table file from a ZIP file. */ |
1119 | /***********************************************************************/ |
1120 | bool ZPXFAM::OpenTableFile(PGLOBAL g) |
1121 | { |
1122 | char filename[_MAX_PATH]; |
1123 | MODE mode = Tdbp->GetMode(); |
1124 | int len = TXTFAM::GetFileLength(g); |
1125 | |
1126 | if (len < 0) |
1127 | return true; |
1128 | else if (!append && len > 0) { |
1129 | strcpy(g->Message, "No insert into existing zip file" ); |
1130 | return true; |
1131 | } else if (append && len > 0) { |
1132 | UNZIPUTL *zutp = new(g) UNZIPUTL(target, false); |
1133 | |
1134 | if (!zutp->IsInsertOk(g, filename)) { |
1135 | strcpy(g->Message, "No insert into existing entry" ); |
1136 | return true; |
1137 | } // endif Ok |
1138 | |
1139 | } // endif's |
1140 | |
1141 | /*********************************************************************/ |
1142 | /* Allocate the ZIP utility class. */ |
1143 | /*********************************************************************/ |
1144 | zutp = new(g) ZIPUTIL(target); |
1145 | |
1146 | // We used the file name relative to recorded datapath |
1147 | PlugSetPath(filename, To_File, Tdbp->GetPath()); |
1148 | |
1149 | if (!zutp->OpenTable(g, mode, filename, append)) { |
1150 | To_Fb = zutp->fp; // Useful when closing |
1151 | } else |
1152 | return true; |
1153 | |
1154 | return AllocateBuffer(g); |
1155 | } // end of OpenTableFile |
1156 | |
1157 | /***********************************************************************/ |
1158 | /* WriteBuffer: Deflate the buffer to the zip file. */ |
1159 | /***********************************************************************/ |
1160 | int ZPXFAM::WriteBuffer(PGLOBAL g) |
1161 | { |
1162 | /*********************************************************************/ |
1163 | /* In Insert mode, we write only full blocks. */ |
1164 | /*********************************************************************/ |
1165 | if (++CurNum != Rbuf) { |
1166 | Tdbp->IncLine(Lrecl); // Used by DOSCOL functions |
1167 | return RC_OK; |
1168 | } // endif CurNum |
1169 | |
1170 | // Now start the compress process. |
1171 | if (zutp->writeEntry(g, To_Buf, Lrecl * Rbuf) != RC_OK) { |
1172 | Closing = true; |
1173 | return RC_FX; |
1174 | } // endif writeEntry |
1175 | |
1176 | CurBlk++; |
1177 | CurNum = 0; |
1178 | Tdbp->SetLine(To_Buf); |
1179 | return RC_OK; |
1180 | } // end of WriteBuffer |
1181 | |
1182 | /***********************************************************************/ |
1183 | /* Table file close routine for ZIP access method. */ |
1184 | /***********************************************************************/ |
1185 | void ZPXFAM::CloseTableFile(PGLOBAL g, bool) |
1186 | { |
1187 | if (CurNum && !Closing) { |
1188 | // Some more inserted lines remain to be written |
1189 | Rbuf = CurNum--; |
1190 | WriteBuffer(g); |
1191 | } // endif Curnum |
1192 | |
1193 | To_Fb->Count = 0; |
1194 | zutp->close(); |
1195 | } // end of CloseTableFile |
1196 | |