1 /*****************************************************************************/
2 /*                                                                           */
3 /*                 (C) Copyright 1992-1996  Alberto Pasquale                 */
4 /*                 Portions (C) Copyright 1999 Per Lundberg                  */
5 /*                                                                           */
6 /*                   A L L   R I G H T S   R E S E R V E D                   */
7 /*                                                                           */
8 /*****************************************************************************/
9 /*                                                                           */
10 /* This source code is NOT in the public domain and it CANNOT be used or     */
11 /* distributed without written permission from the author.                   */
12 /*                                                                           */
13 /*****************************************************************************/
14 /*                                                                           */
15 /* How to contact the author:  Alberto Pasquale of 2:332/504@fidonet         */
16 /*                             Viale Verdi 106                               */
17 /*                             41100 Modena                                  */
18 /*                             Italy                                         */
19 /*                                                                           */
20 /*****************************************************************************/
21 
22 // ComprCfg.Cpp
23 
24 #ifdef __OS2__
25   #define INCL_DOS
26   #include <os2.h>
27 #endif
28 #include "bbsgenlb.hpp"
29 #include "apgenlib.hpp"
30 #include <string.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <stdarg.h>
34 
35 
36 
37 #define IDENTBUFSIZE   64
38 #define CFGLINESIZE    256
39 
40 
41 #define InString    1   // for CleanLine status
42 #define OutString   2
43 #define LineEnd     3
44 
45 
46 AH_VShow AH_ComprCfg::outf;
47 
48 
CleanLine(char * line)49 static void CleanLine (char *line)    // Get rid of tabs, comments, newline.
50 {                              // Preserve ';' if enclosed in string.
51     int status = OutString;    // Remove trailing space.
52     char *c = line;
53 
54     while (status != LineEnd) {
55         switch (*c) {
56             case '\t':      // convert tab to blank
57                 *c = ' ';
58                 break;
59 
60             case '\n':
61             case '\0':
62                 status = LineEnd;
63                 continue;
64 
65             case '\"':
66                 if (status == InString) {
67                     if (*(c+1) == '\"')
68                         c++;
69                     else
70                         status = OutString;
71                 } else
72                     status = InString;
73                 break;
74 
75             case ';' :
76                 if (status == OutString) {
77                     status = LineEnd;
78                     continue;
79                 }
80         }
81         c++;
82     }
83 
84     while (c > line)            // remove trailing space
85         if (*(c-1) == ' ')
86             c--;
87         else
88             break;
89 
90     *c = '\0';
91 }
92 
93 
fgetln(FILE * f,char * lbuff,const char * & tkp)94 static char *fgetln (FILE *f, char *lbuff, const char *&tkp)
95 {
96     char *tok = NULL;
97 
98     while ((_fgets (lbuff, CFGLINESIZE, f)) != NULL) {
99         CleanLine (lbuff);  /* get rid of tabs, comments and newline */
100         tkp = lbuff;
101         tok = GetStatName (tkp);
102         if (tok != NULL) /* if keyword ok, return */
103             break;
104     }
105     return tok;
106 }
107 
108 
RcShow(int code,...)109 void AH_ComprCfg::RcShow (int code, ...)
110 {
111     if (!outf)
112         return;
113     va_list args;
114     va_start (args, code);
115     switch (code) {
116         case RC_DOING:
117             outf (AH_MT_Action, "Executing \"%s\"\n", va_arg (args, char *));
118             break;
119         case RC_EXIT:
120             outf (AH_MT_Info, "Exit code: %d\n", va_arg (args, int));
121             break;
122         case RC_EMPTY:
123             outf (AH_MT_Error, "Error: Empty external command !\n");
124             break;
125     }
126     va_end (args);
127 }
128 
129 
AH_Archiver(const AH_Archiver * aptr)130 AH_Archiver::AH_Archiver (const AH_Archiver *aptr)   // constructor
131 {
132     memset (this, 0, sizeof (*this));   // clear all fields
133     prev = aptr;
134 }
135 
136 
AH_ComprCfg(const char * cfgfile,AH_VShow outf)137 AH_ComprCfg::AH_ComprCfg (const char *cfgfile, AH_VShow outf)      // constructor
138 {
139     FILE *f;
140     const char *tok, *tkp;
141 
142     AH_ComprCfg::outf = outf;
143 
144     lastarc = NULL;
145 
146     f = fopen (cfgfile, "rt");
147     if (!f) {
148         if (outf)
149             outf (AH_MT_Error, "Error: cannot open \"%s\"\n", cfgfile);
150         return;
151     }
152 
153     if (outf)
154         outf (AH_MT_Info, "Including Compress Definition \"%s\"\n", cfgfile);
155 
156     BOOL InArchive = FALSE;
157 
158     char lbuff[CFGLINESIZE];
159 
160     while ((tok = fgetln (f, lbuff, tkp)) != NULL) {
161 
162       #ifdef __OS2__
163         if (stricmp (tok, "DOS") == 0)  // ignore DOS lines
164             continue;
165 
166         if (stricmp (tok, "OS2") == 0) {  // skip OS2 prefix
167             if ((tok = GetStatName (tkp)) == NULL)
168                 continue;
169         }
170       #else // DOS
171         if (stricmp (tok, "OS2") == 0)  // ignore OS2 lines
172             continue;
173 
174         if (stricmp (tok, "DOS") == 0) {  // skip DOS prefix
175             if ((tok = GetStatName (tkp)) == NULL)
176                 continue;
177         }
178       #endif
179 
180         if (!InArchive) {
181             if (stricmp (tok, "Archiver") == 0) {
182                 if ((tok = GetStatName (tkp)) == NULL)
183                     continue;
184                 InArchive = TRUE;
185                 lastarc = new AH_Archiver (lastarc);
186                 lastarc->name = newcpy (tok);
187                 continue;
188             }
189         } else {        // Inside Archiver definition
190             if (stricmp (tok, "End") == 0) {
191                 InArchive = FALSE;
192                 continue;
193             }
194 
195             if (stricmp (tok, "View") == 0) // ignore View command
196                 continue;
197 
198             if (stricmp (tok, "Extension") == 0) {
199                 if ((tok = GetStatName (tkp)) == NULL)
200                     continue;
201                 lastarc->ext = newcpy (tok);
202                 continue;
203             }
204 
205             if (stricmp (tok, "Ident") == 0) {
206                 if ((tok = GetStatName (tkp)) == NULL)
207                     continue;
208                 ScanIdent (tok);
209                 continue;
210             }
211 
212             if (stricmp (tok, "Add") == 0) {
213                 if (*tkp == '\0')
214                     continue;
215                 lastarc->addcmd = GetAllocLn (tkp, GL_Empty);
216                 continue;
217             }
218 
219             if (stricmp (tok, "Extract") == 0) {
220                 if (*tkp == '\0')
221                     continue;
222                 lastarc->extcmd = GetAllocLn (tkp, GL_Empty);
223                 continue;
224             }
225         }
226 
227         if (outf)
228             outf (AH_MT_Error, "\nUnknown or out of sequence ComprCfg line:\n%s\n\n", lbuff);
229     }
230 
231     fclose (f);
232 
233     if (outf)
234         outf (AH_MT_Info, "Finished Compress Definition \"%s\"\n", cfgfile);
235 }
236 
237 
ScanIdent(const char * tok)238 void AH_ComprCfg::ScanIdent (const char *tok)
239 {
240     char hexfig[3] = "00";  // initialized to set hexfig[2] = '\0';
241     byte identbuf[IDENTBUFSIZE];
242     int identlen = 0;
243 
244     #ifndef __QNX__
245        char *p = strchr (tok, ',');
246     #else
247        char *p = strchr ((char *)tok, ',');
248     #endif // __QNX__
249 
250     if (!p)
251         return;
252 
253     p++;    // points to first hex figure
254 
255     while (*p) {
256         *hexfig = *(p++);
257         if (*p == '\0')
258             return;
259         *(hexfig+1) = *(p++);
260         identbuf[identlen++] = (byte) strtol (hexfig, NULL, 16);
261     }
262 
263     lastarc->identofs = atoi (tok);
264 
265     lastarc->identlen = identlen;
266 
267     lastarc->identstr = new byte[identlen];
268     memcpy (lastarc->identstr, identbuf, identlen);
269 }
270 
271 
272 typedef enum { St_Start,        // Look for 1st byte of ID
273                St_StrChk        // Looking for next byte
274              } State;
275 
276 struct _Status {
277     State state;
278     const AH_Archiver *CurArc;    // current arc type in evaluation
279     ulong idofs;            // current ofs in ID
280 };
281 
282 
ArcGood(const AH_Archiver * a)283 BOOL AH_ComprCfg::ArcGood (const AH_Archiver *a)
284 {
285     return ((a->identlen > 1) && (a->extcmd != NULL));
286 }
287 
288 
SfxNext(const AH_Archiver * a)289 const AH_Archiver *AH_ComprCfg::SfxNext (const AH_Archiver *a)
290 {
291     if (!a) {
292         a = lastarc;
293         if (!a)
294             return NULL;
295         if (ArcGood (a))
296             return a;
297     }
298 
299     do {
300         a = a->prev;
301         if (!a)
302             return NULL;
303     } while (!ArcGood (a));
304 
305     return a;
306 }
307 
308 
ChkSfx(const char * filename)309 const AH_Archiver *AH_ComprCfg::ChkSfx (const char *filename)
310 {
311     int namelen = strlen (filename);
312     if (namelen < 5)
313         return NULL;
314     if (stricmp (filename + namelen - 4, ".exe") != 0)
315         return NULL;
316 
317 
318     FILE *f = fopen (filename, "rb");
319     if (!f)
320         return NULL;
321     setvbuf (f, NULL, _IOFBF, 8192);
322 
323     int ch;
324     _Status Status = { St_Start, SfxNext (NULL), 0 };
325     if (!Status.CurArc)
326         return NULL;
327     BOOL afound = FALSE;
328 
329     while ((ch = fgetc (f)) != EOF) {
330         switch (Status.state) {
331 
332             case St_Start:      // looking for 1st byte of ID
333                 if (!Status.CurArc)
334                     Status.CurArc = SfxNext (NULL);
335                 while (Status.CurArc) {
336                     if (ch == Status.CurArc->identstr[0]) {
337                         Status.state = St_StrChk;
338                         Status.idofs = 1;
339                         break;
340                     }
341                     Status.CurArc = SfxNext (Status.CurArc);
342                 }
343                 break;
344 
345             case St_StrChk:
346                 if (ch == Status.CurArc->identstr[Status.idofs++]) {
347                     if (Status.CurArc->identlen == (long)Status.idofs)
348                         afound = TRUE;
349                 } else {
350                     long nback = Status.idofs;
351                     Status.state = St_Start;
352                     Status.CurArc = SfxNext (Status.CurArc);
353                     if (!Status.CurArc)
354                         nback --;
355                     fseek (f, -nback, SEEK_CUR);
356                 }
357                 break;
358         }
359 
360         if (afound)
361             break;
362     }
363 
364     fclose (f);
365 
366     if (!afound)
367         return NULL;
368 
369     return Status.CurArc;
370 }
371 
372 
UnArc(const char * filename,const char * extract)373 int AH_ComprCfg::UnArc (const char *filename, const char *extract)
374 {                                      // Unarcs extract from filename
375     FILE *f;                           // returns errorlevel
376     const AH_Archiver *a;              // returns -1 if cannot execute
377     int res;                           // returns -2 on unknown type
378     BOOL afound; // Archive type found // returns -3 on file not found
379     char buf[PATH_MAX], buf2[PATH_MAX];
380 
381 
382     f = fopen (filename, "rb");
383     if (!f) {
384         if (outf)
385             outf (AH_MT_Error, "Error: cannot open \"%s\"\n", filename);
386         return -3;      // cannot open
387     }
388 
389     afound = FALSE;
390     a = lastarc;
391     while (a) {
392         if ((a->identlen > 0) && (a->extcmd != NULL)) {
393             if (a->identofs >= 0)
394                 res = fseek (f, a->identofs, SEEK_SET);
395             else
396                 res = fseek (f, a->identofs, SEEK_END);
397             if (res == 0) {     // seek successful
398                 afound = TRUE;
399                 for (int i = 0; i < a->identlen; i ++) {
400                     res = fgetc (f);
401                     if (res != a->identstr[i]) { // incl. EOF
402                         afound = FALSE;
403                         break;
404                     }
405                 }
406                 if (afound)
407                     break;
408             }
409         }
410         a = a->prev;
411     }
412 
413     fclose (f);
414 
415     if (!afound) {
416         a = ChkSfx (filename);
417         afound = (a != NULL);
418     }
419 
420     if (!afound) {
421         if (outf)
422             outf (AH_MT_Error, "Error: unknown archive for \"%s\"\n", filename);
423         return -2;      // Archive type not identified
424     }
425 
426 /*  Note from Gerrit (2:2411/12):
427     The following code tries two types to unarc commands:
428 	1. extcmd filename "extract"
429 	2. (if 1. has failed)
430 	   extcmd "filename extract"
431     The whole thing is about jokers (???) being present in extract. A shell
432     (e.g. under *ix) must be prevented to expand them - extract has to be given
433     to extcmd as is. However, sometimes (namely with arc under *ix) this seems
434     to fail and the 2nd form of command is tried (my arc sometimes works with
435     the first version, sometimes with the second - I really don't know why!).*/
436 
437     sprintf(buf2,"%s",filename);
438     sprintf(buf,"\"%s\"",extract);
439     res = RunCmd (a->extcmd, RcShow, "af", buf2, buf);
440     if (res) {
441       outf (AH_MT_Error, "Warning: unable to extract from \"%s\"\n", filename);
442       outf (AH_MT_Error, "Warning: trying alternate extract command composition\n");
443       sprintf(buf2,"\"%s",filename);
444       sprintf(buf,"%s\"",extract);
445       res = RunCmd (a->extcmd, RcShow, "af", buf2, buf);
446     }
447     if (res) {
448       outf (AH_MT_Error, "Error: unable to extract from \"%s\"\n", filename);
449       outf (AH_MT_Error, "Error: giving up\n");
450     }
451     return res;
452 }
453 
454 
Arc(const AH_Archiver * a,const char * filename,const char * add)455 int AH_ComprCfg::Arc (const AH_Archiver *a, const char *filename, const char *add)
456 {                                       // Adds add to filename using archiver
457     return RunCmd (a->addcmd, RcShow, "af", filename, add);
458 }
459 
460 
AddDefined(const char * method)461 const AH_Archiver *AH_ComprCfg::AddDefined (const char *method) // is method defined in cfg ?
462 {                                             // return pointer
463     const AH_Archiver *a = lastarc;
464     while (a) {
465         if (stricmp (a->name, method) == 0) {
466             if ((a->addcmd != NULL) && (a->ext != NULL))
467                 return a;
468             else
469                 return NULL;
470         }
471         a = a->prev;
472     }
473     return NULL;
474 }
475 
476 
ExtDefined(const char * ext)477 const AH_Archiver *AH_ComprCfg::ExtDefined (const char *ext)  // is extension defined in compress.cfg ?
478 {
479     const AH_Archiver *a = lastarc;
480     while (a) {
481         if (stricmp (a->ext, ext) == 0)
482             return a;
483         a = a->prev;
484     }
485     return NULL;
486 }
487