1
2 /*
3 * xDMS - Portable DMS archive unpacker - Public Domain
4 * Written by Andre Rodrigues de la Rocha <adlroc@usa.net>
5 *
6 *
7 */
8
9
10
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <ctype.h>
15
16 #include <unistd.h>
17
18 #include "cdata.h"
19 #include "pfile.h"
20 #include "crc_csum.h"
21
22 #ifdef UNDER_DOS
23 #include <io.h>
24 #include <fcntl.h>
25 #endif
26
27
28 #define FNAME_MAXC 512
29
30
31 static void Usage(void);
32 static int strcmpnc(char *, char *);
33 static void strcpymax(char *, char *, int);
34 static void strcatmax(char *, char *, int);
35 static void ErrMsg(USHORT, char *, char *);
36
37
main(int argc,char ** argv)38 int main(int argc, char **argv){
39 USHORT i, cmd=0, opt=0, ret, PCRC=0, pwd=0;
40 int ext;
41 char iname[FNAME_MAXC+1], oname[FNAME_MAXC+1], cmdstr[FNAME_MAXC+20], *inm, *onm, *p, *q, *destdir=NULL;
42 char tname[FNAME_MAXC];
43
44
45 if (argc < 3) {
46 Usage();
47 exit(EXIT_FAILURE);
48 }
49
50 /* proccess options in the command line */
51 for (i=1; (i<argc) && (argv[i][0] == '-'); i++){
52 if (strlen(argv[i])>2) {
53 fprintf(stderr,"Unknown option !\n");
54 Usage();
55 exit(EXIT_FAILURE);
56 }
57 switch (tolower(argv[i][1])) {
58 case 'f':
59 OverrideErrors = 1;
60 break;
61 case 'q' :
62 opt = OPT_QUIET;
63 break;
64 case 'v' :
65 opt = OPT_VERBOSE;
66 break;
67 case 'd' :
68 if (++i == argc) {
69 Usage();
70 exit(EXIT_FAILURE);
71 }
72 destdir = argv[i];
73 break;
74 case 'p' :
75 if (++i == argc) {
76 Usage();
77 exit(EXIT_FAILURE);
78 }
79 PCRC = CreateCRC((UCHAR*)argv[i],(ULONG)strlen(argv[i]));
80 pwd = 1;
81 break;
82 default:
83 fprintf(stderr,"Unknown option !\n");
84 Usage();
85 exit(EXIT_FAILURE);
86 }
87 }
88
89 if ((i == argc) || (strlen(argv[i])>1)) {
90 Usage();
91 exit(EXIT_FAILURE);
92 }
93
94
95 switch (tolower(argv[i][0])) {
96 case 'u':
97 cmd = CMD_UNPACK;
98 break;
99 case 'z':
100 cmd = CMD_UNPKGZ;
101 break;
102 case 'x':
103 cmd = CMD_EXTRACT;
104 break;
105 case 't':
106 cmd = CMD_TEST;
107 break;
108 case 'v':
109 cmd = CMD_VIEW;
110 break;
111 case 'f':
112 cmd = CMD_VIEWFULL;
113 break;
114 case 'd':
115 cmd = CMD_SHOWDIZ;
116 break;
117 case 'b':
118 cmd = CMD_SHOWBANNER;
119 break;
120 default:
121 fprintf(stderr,"Unknown command !\n");
122 Usage();
123 exit(EXIT_FAILURE);
124 }
125
126 if (++i == argc) {
127 Usage();
128 exit(EXIT_FAILURE);
129 }
130
131 ext = EXIT_SUCCESS;
132
133 while (i < argc) {
134
135 if (!strcmpnc("stdin",argv[i])) {
136 inm = NULL;
137 } else {
138 strcpymax(iname,argv[i],FNAME_MAXC);
139 if ((strlen(iname)<4) || (strcmpnc(".dms",iname+strlen(iname)-4))) strcatmax(iname,".dms",FNAME_MAXC);
140 inm = iname;
141 }
142 i++;
143
144
145 /* generate the output filename */
146 if ((i < argc) && (argv[i][0]=='+')) {
147 if ((!strcmpnc("stdout",argv[i]+1)) || (destdir && (!strcmpnc("stdout",destdir)))) {
148 strcpy(oname,"");
149 onm = NULL;
150 } else {
151 if (destdir) {
152 strcpymax(oname,destdir,FNAME_MAXC-1);
153 p = oname + strlen(oname) - 1;
154 if (!strchr(DIR_SEPARATORS,*p)) {
155 *(p+1) = DIR_CHAR;
156 *(p+2) = '\0';
157 }
158 } else strcpy(oname,"");
159 strcatmax(oname,argv[i]+1,FNAME_MAXC);
160 if (((cmd == CMD_UNPACK) || (cmd == CMD_UNPKGZ)) && (strlen(oname)>0)) {
161 p = oname + strlen(oname) - 1;
162 if (strchr(DIR_SEPARATORS,*p)) {
163 if (inm) {
164 p = q = iname;
165 while(*p) {
166 if (strchr(DIR_SEPARATORS,*p)) q = p+1;
167 p++;
168 }
169 strcatmax(oname,q,FNAME_MAXC);
170 if ((strlen(oname)>4) && (!strcmpnc(oname+strlen(oname)-4,".dms"))) {
171 if (cmd == CMD_UNPKGZ)
172 strcpy(oname+strlen(oname)-4,".adz");
173 else
174 strcpy(oname+strlen(oname)-4,".adf");
175 } else {
176 if (cmd == CMD_UNPKGZ)
177 strcatmax(oname,".adz",FNAME_MAXC);
178 else
179 strcatmax(oname,".adf",FNAME_MAXC);
180 }
181 } else {
182 if (cmd == CMD_UNPKGZ)
183 strcatmax(oname,"stdin.adz",FNAME_MAXC);
184 else
185 strcatmax(oname,"stdin.adf",FNAME_MAXC);
186 }
187
188 }
189 }
190
191 onm = oname;
192 }
193 i++;
194 } else if (destdir && (!strcmpnc("stdout",destdir))) {
195 strcpy(oname,"");
196 onm = NULL;
197 } else {
198
199 if (destdir)
200 strcpymax(oname,destdir,FNAME_MAXC-1);
201 else
202 strcpy(oname,"");
203
204 if ((cmd == CMD_UNPACK) || (cmd == CMD_UNPKGZ)) {
205
206 if (strlen(oname)>0) {
207 p = oname + strlen(oname) - 1;
208 if (!strchr(DIR_SEPARATORS,*p)) {
209 *(p+1) = DIR_CHAR;
210 *(p+2) = '\0';
211 }
212 }
213
214 if (inm) {
215 p = q = iname;
216 while(*p) {
217 if (strchr(DIR_SEPARATORS,*p)) q = p+1;
218 p++;
219 }
220 strcatmax(oname,q,FNAME_MAXC);
221 if ((strlen(oname)>4) && (!strcmpnc(oname+strlen(oname)-4,".dms"))) {
222 if (cmd == CMD_UNPKGZ)
223 strcpy(oname+strlen(oname)-4,".adz");
224 else
225 strcpy(oname+strlen(oname)-4,".adf");
226 } else {
227 if (cmd == CMD_UNPKGZ)
228 strcatmax(oname,".adz",FNAME_MAXC);
229 else
230 strcatmax(oname,".adf",FNAME_MAXC);
231 }
232 } else {
233 if (cmd == CMD_UNPKGZ)
234 strcatmax(oname,"stdin.adz",FNAME_MAXC);
235 else
236 strcatmax(oname,"stdin.adf",FNAME_MAXC);
237 }
238
239 }
240
241 onm = oname;
242
243 }
244
245
246
247 if (opt == OPT_VERBOSE) {
248 if ((cmd == CMD_UNPACK)) {
249 if (inm)
250 fprintf(stderr,"Unpacking file %s to ",inm);
251 else
252 fprintf(stderr,"Unpacking data from stdin to ");
253 if (onm)
254 fprintf(stderr,"%s\n",onm);
255 else
256 fprintf(stderr,"stdout\n");
257 } else if ((cmd == CMD_EXTRACT) || (cmd == CMD_UNPKGZ)) {
258 if (inm)
259 fprintf(stderr,"Unpacking file %s\n",inm);
260 else
261 fprintf(stderr,"Unpacking data from stdin\n");
262 } else if (cmd == CMD_TEST) {
263 if (inm)
264 fprintf(stderr,"Testing file %s\n",inm);
265 else
266 fprintf(stderr,"Testing data from stdin\n");
267 } else if (cmd == CMD_SHOWDIZ) {
268 if (inm)
269 printf("Showing FILEID.DIZ in %s :\n",inm);
270 else
271 printf("Showing FILEID.DIZ in stdin :\n");
272 } else if (cmd == CMD_SHOWBANNER) {
273 if (inm)
274 printf("Showing Banner in %s :\n",inm);
275 else
276 printf("Showing Banner in stdin :\n");
277 }
278
279 }
280
281 #ifdef UNDER_DOS
282 if (!inm) setmode(fileno(stdin),O_BINARY);
283 if ((cmd == CMD_UNPACK) && (!onm)) setmode(fileno(stdout),O_BINARY);
284 #endif
285
286 if ((cmd == CMD_UNPKGZ) || (cmd == CMD_EXTRACT)) {
287 int fd;
288 strcpy(tname, "/tmp/xdmsXXXXXX");
289 fd = mkstemp(tname);
290 if (fd < 0) {
291 fprintf(stderr, "couldn't create a temp file\n");
292 exit(-1);
293 }
294 close(fd);
295 #ifdef UNDER_DOS
296 p = tname;
297 if (p) {
298 while (*p) {
299 if (*p == '/') *p = '\\';
300 p++;
301 }
302 }
303 #endif
304 ret = Process_File(inm, tname, CMD_UNPACK, opt, PCRC, pwd);
305 if (opt != OPT_QUIET) ErrMsg(ret, inm, "Temporary file");
306 if (ret == NO_PROBLEM) {
307 if (cmd == CMD_UNPKGZ) {
308 if (opt == OPT_VERBOSE) {
309 fprintf(stderr,"Repacking unpacked data with gzip\n");
310 }
311 if (onm)
312 #ifdef UNDER_DOS
313 /* DOS sucks */
314 sprintf(cmdstr,"gzip -cfqn %s >%s",tname,onm);
315 #else
316 sprintf(cmdstr,"gzip -cfqn \"%s\" >\"%s\"",tname,onm);
317 #endif
318 else
319 #ifdef UNDER_DOS
320 sprintf(cmdstr,"gzip -cfqn %s",tname);
321 #else
322 sprintf(cmdstr,"gzip -cfqn \"%s\"",tname);
323 #endif
324 if (system(cmdstr)) ret = ERR_GZIP;
325 if (opt != OPT_QUIET) ErrMsg(ret, inm, onm);
326 } else {
327 if (opt == OPT_VERBOSE) {
328 fprintf(stderr,"Extracting files from unpacked data with readdisk\n");
329 }
330 if ((onm) && (strlen(onm)>0))
331 #ifdef UNDER_DOS
332 sprintf(cmdstr,"readdisk %s %s",tname,onm);
333 #else
334 sprintf(cmdstr,"readdisk \"%s\" \"%s\"",tname,onm);
335 #endif
336 else
337 #ifdef UNDER_DOS
338 sprintf(cmdstr,"readdisk %s",tname);
339 #else
340 sprintf(cmdstr,"readdisk \"%s\"",tname);
341 #endif
342 if (system(cmdstr)) ret = ERR_READDISK;
343 if (opt != OPT_QUIET) ErrMsg(ret, inm, onm);
344 }
345 }
346 remove(tname);
347 } else {
348 ret = Process_File(inm, onm, cmd, opt, PCRC, pwd);
349 if (opt != OPT_QUIET) ErrMsg(ret, inm, onm);
350 }
351
352 if (ret != NO_PROBLEM) ext = EXIT_FAILURE;
353
354 if ((ret == NO_PROBLEM) && (opt != OPT_QUIET)) {
355 switch (cmd) {
356 case CMD_UNPACK:
357 if (inm)
358 fprintf(stderr,"File %s was correctly unpacked to ",inm);
359 else
360 fprintf(stderr,"Data from stdin was correctly unpacked to ");
361 if (onm)
362 fprintf(stderr,"%s\n",onm);
363 else
364 fprintf(stderr,"stdout\n");
365 break;
366 case CMD_UNPKGZ:
367 if (inm)
368 fprintf(stderr,"File %s was correctly converted to ",inm);
369 else
370 fprintf(stderr,"Data from stdin was correctly converted to ");
371 if (onm)
372 fprintf(stderr,"%s\n",onm);
373 else
374 fprintf(stderr,"stdout\n");
375 break;
376 case CMD_EXTRACT:
377 if (inm)
378 fprintf(stderr,"The files were correctly extracted from %s\n",inm);
379 else
380 fprintf(stderr,"The files were correctly extracted from stdin\n");
381 break;
382 case CMD_TEST:
383 if (inm)
384 fprintf(stderr,"File %s is ok\n",inm);
385 else
386 fprintf(stderr,"Data from stdin is ok\n");
387 break;
388 default:
389 break;
390 }
391 }
392
393 if (opt != OPT_QUIET) fprintf(stderr,"\n");
394
395 }
396
397 return (int) ext;
398 }
399
400
401
strcmpnc(char * s1,char * s2)402 static int strcmpnc(char *s1, char *s2){
403 while (*s1 && (tolower(*s1)==tolower(*s2))) {s1++; s2++;}
404 return tolower(*s1)-tolower(*s2);
405 }
406
407
408
strcpymax(char * s1,char * s2,int max)409 static void strcpymax(char *s1, char *s2, int max){
410 if (strlen(s2)>max){
411 memcpy(s1,s2,max);
412 *(s1+max) = 0;
413 } else
414 strcpy(s1,s2);
415 }
416
417
418
strcatmax(char * s1,char * s2,int max)419 static void strcatmax(char *s1, char *s2, int max){
420 if (strlen(s1)+strlen(s2)>max){
421 memcpy(s1+strlen(s1),s2,max-strlen(s1));
422 *(s1+max) = 0;
423 } else
424 strcat(s1,s2);
425 }
426
427
428
Usage(void)429 static void Usage(void)
430 {
431 printf("\n");
432 printf(" xDMS v%s - Portable DMS archive unpacker - Public Domain\n", VERSION);
433 printf(" Written by Andre Rodrigues de la Rocha <adlroc@usa.net>\n");
434 printf(" Maintained by Heikki Orsila <heikki.orsila@iki.fi>\n\n");
435 printf(" Usage: xdms [options] <command> {<dms_file[.dms]> [+output]} \n\n");
436 printf(" Commands :\n");
437 printf(" t : Test DMS archives\n");
438 printf(" u : Unpack DMS archives to disk images\n");
439 printf(" z : Unpack to disk images and compress it with gzip\n");
440 printf(" x : Extract files inside DMS archives using readdisk\n");
441 printf(" v : View DMS archives information\n");
442 printf(" f : View full information\n");
443 printf(" d : Show attached FILEID.DIZ\n");
444 printf(" b : Show attached Banner\n\n");
445 printf(" Options :\n");
446 printf(" -f : Override errors (for desperate data salvaging)\n");
447 printf(" -q : Quiet\n");
448 printf(" -v : Verbose\n");
449 printf(" -d <destdir> : Set destination directory\n");
450 printf(" -p <password> : Decrypt encrypted archives using password\n");
451 printf("\n");
452 }
453
454
455
ErrMsg(USHORT err,char * i,char * o)456 static void ErrMsg(USHORT err, char *i, char *o){
457
458 if (!i) i = "stdin";
459 if (!o) o = "stdout";
460
461 switch (err) {
462 case NO_PROBLEM:
463 case FILE_END:
464 return;
465 case ERR_NOMEMORY:
466 fprintf(stderr,"Not enough memory for buffers !\n");
467 break;
468 case ERR_CANTOPENIN:
469 fprintf(stderr,"Can't open %s for reading !\n",i);
470 break;
471 case ERR_CANTOPENOUT:
472 fprintf(stderr,"Can't open %s for writing !\n",o);
473 break;
474 case ERR_NOTDMS:
475 fprintf(stderr,"File %s is not a DMS archive !\n",i);
476 break;
477 case ERR_SREAD:
478 fprintf(stderr,"Error reading file %s : unexpected end of file !\n",i);
479 break;
480 case ERR_HCRC:
481 fprintf(stderr,"Error in file %s : header CRC error !\n",i);
482 break;
483 case ERR_NOTTRACK:
484 fprintf(stderr,"Error in file %s : track header not found !\n",i);
485 break;
486 case ERR_BIGTRACK:
487 fprintf(stderr,"Error in file %s : track too big !\n",i);
488 break;
489 case ERR_THCRC:
490 fprintf(stderr,"Error in file %s : track header CRC error !\n",i);
491 break;
492 case ERR_TDCRC:
493 fprintf(stderr,"Error in file %s : track data CRC error !\n",i);
494 break;
495 case ERR_CSUM:
496 fprintf(stderr,"Error in file %s : checksum error after unpacking !\n",i);
497 fprintf(stderr,"This file seems ok, but the unpacking failed.\n");
498 fprintf(stderr,"This can be caused by a bug in xDMS. Please contact the author\n");
499 break;
500 case ERR_CANTWRITE:
501 fprintf(stderr,"Error : can't write to file %s !\n",o);
502 break;
503 case ERR_BADDECR:
504 fprintf(stderr,"Error in file %s : error unpacking !\n",i);
505 fprintf(stderr,"This file seems ok, but the unpacking failed.\n");
506 fprintf(stderr,"This can be caused by a bug in xDMS. Please contact the author\n");
507 break;
508 case ERR_UNKNMODE:
509 fprintf(stderr,"Error in file %s : unknown compression mode used !\n",i);
510 break;
511 case ERR_NOPASSWD:
512 fprintf(stderr,"Can't process file %s : file is encrypted !\n",i);
513 break;
514 case ERR_BADPASSWD:
515 fprintf(stderr,"Error unpacking file %s . The password is probably wrong.\n",i);
516 break;
517 case ERR_FMS:
518 fprintf(stderr,"Error in file %s : this file is not really a compressed disk image, but an FMS archive !\n",i);
519 break;
520 case ERR_GZIP:
521 fprintf(stderr,"Can't convert file %s : gzip failed !\n",i);
522 break;
523 case ERR_READDISK:
524 fprintf(stderr,"Can't extract files from %s : readdisk failed !\n",i);
525 break;
526 default:
527 fprintf(stderr,"Error while processing file %s : internal error !\n",i);
528 fprintf(stderr,"This is a bug in xDMS\n");
529 fprintf(stderr,"Please contact the author\n");
530 break;
531 }
532 }
533
534
535