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
48bool 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/***********************************************************************/
53static 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/***********************************************************************/
91static 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/***********************************************************************/
206bool 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/***********************************************************************/
231ZIPUTIL::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
240ZIPUTIL::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/***********************************************************************/
253void 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/***********************************************************************/
272bool 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/***********************************************************************/
285void 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/***********************************************************************/
301bool 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/***********************************************************************/
344bool 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/***********************************************************************/
361int 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/***********************************************************************/
374void 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/***********************************************************************/
388UNZIPUTL::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
408UNZIPUTL::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
429UNZIPUTL::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/***********************************************************************/
445bool UNZIPUTL::WildMatch(PCSZ pat, PCSZ str) {
446 PCSZ s, p;
447 bool star = FALSE;
448
449loopStart:
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
469starCheck:
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/***********************************************************************/
480bool 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/***********************************************************************/
491void 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/***********************************************************************/
507int 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/***********************************************************************/
550int 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/***********************************************************************/
573bool 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/***********************************************************************/
645bool 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/***********************************************************************/
667bool 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/***********************************************************************/
711void 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/***********************************************************************/
730UNZFAM::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
738UNZFAM::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/***********************************************************************/
749int 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/***********************************************************************/
763int 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/***********************************************************************/
784bool 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/***********************************************************************/
811int 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/***********************************************************************/
827int 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/***********************************************************************/
893void UNZFAM::CloseTableFile(PGLOBAL g, bool)
894{
895 close();
896} // end of CloseTableFile
897#endif // 0
898
899/* -------------------------- class UZXFAM --------------------------- */
900
901/***********************************************************************/
902/* Constructors. */
903/***********************************************************************/
904UZXFAM::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
913UZXFAM::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/***********************************************************************/
925int 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/***********************************************************************/
943int 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/***********************************************************************/
964bool 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/***********************************************************************/
998int 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/***********************************************************************/
1023ZIPFAM::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/***********************************************************************/
1033bool 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/***********************************************************************/
1076int 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/***********************************************************************/
1085int 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/***********************************************************************/
1098void 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/***********************************************************************/
1109ZPXFAM::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/***********************************************************************/
1120bool 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/***********************************************************************/
1160int 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/***********************************************************************/
1185void 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