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