1 /*
2   Hatari tool: MSA and ST disk image creator and converter - hmsa.c
3 
4   This file is distributed under the GNU General Public License, version 2
5   or at your option any later version. Read the file gpl.txt for details.
6 */
7 
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <stdarg.h>
11 #include <string.h>
12 
13 #include "hmsa.h"
14 #include "main.h"	/* bool etc. */
15 #include "createBlankImage.h"
16 #include "file.h"
17 #include "msa.h"
18 
19 /* prototypes for dummy log/alert functions below */
20 #include "dialog.h"
21 #include "log.h"
22 
23 /**
24  * Print suitable output prefix based on log level
25  */
print_prefix(LOGTYPE nType)26 static void print_prefix(LOGTYPE nType)
27 {
28 	const char *sType;
29 	switch (nType) {
30 	case LOG_FATAL:
31 	case LOG_ERROR:
32 		sType = "ERROR: ";
33 		break;
34 	case LOG_WARN:
35 		sType = "WARNING: ";
36 		break;
37 	default:
38 		return;
39 	}
40 	fputs(sType, stdout);
41 }
42 
43 /* output newline if it's missing from text */
do_newline(const char * text)44 static void do_newline(const char *text)
45 {
46 	if (text[strlen(text)-1] != '\n')
47 		fputs("\n", stdout);
48 }
49 
50 /**
51  * Output Hatari log string.
52  */
Log_Printf(LOGTYPE nType,const char * psFormat,...)53 extern void Log_Printf(LOGTYPE nType, const char *psFormat, ...)
54 {
55 	va_list argptr;
56 	print_prefix(nType);
57 	va_start(argptr, psFormat);
58 	vfprintf(stdout, psFormat, argptr);
59 	va_end(argptr);
60 }
61 
62 /**
63  * Output Hatari Alert dialog string.
64  */
Log_AlertDlg(LOGTYPE nType,const char * psFormat,...)65 extern void Log_AlertDlg(LOGTYPE nType, const char *psFormat, ...)
66 {
67 	va_list argptr;
68 	print_prefix(nType);
69 	va_start(argptr, psFormat);
70 	vfprintf(stdout, psFormat, argptr);
71 	va_end(argptr);
72 	do_newline(psFormat);
73 }
74 
75 /**
76  * Output Hatari Query dialog string.
77  */
DlgAlert_Query(const char * text)78 int DlgAlert_Query(const char *text)
79 {
80 	puts(text);
81 	do_newline(text);
82 	return TRUE;
83 }
84 
85 
86 /**
87  * ../src/file.c requires zip.c, which calls IPF_FileNameIsIPF
88  * We create an empty function to replace it, as we don't use IPF here
89  * and don't want to compile with all the IPF related files.
90  * We do it also for STX.
91  */
92 extern bool IPF_FileNameIsIPF(const char *pszFileName, bool bAllowGZ);		/* function prototype */
IPF_FileNameIsIPF(const char * pszFileName,bool bAllowGZ)93 extern bool IPF_FileNameIsIPF(const char *pszFileName, bool bAllowGZ)
94 {
95 	return FALSE;
96 }
97 extern bool STX_FileNameIsSTX(const char *pszFileName, bool bAllowGZ);		/* function prototype */
STX_FileNameIsSTX(const char * pszFileName,bool bAllowGZ)98 extern bool STX_FileNameIsSTX(const char *pszFileName, bool bAllowGZ)
99 {
100 	return FALSE;
101 }
102 
103 
104 /**
105  * Create MSA or ST image of requested size.
106  * return error string or NULL for success.
107  */
create_image(const char * filename,const char * sizeid)108 static const char* create_image(const char *filename, const char *sizeid)
109 {
110 	int tracks, sectors, sides;
111 	tracks = 80;
112 
113 	if (strcasecmp(sizeid, "ss") == 0) {
114 		sides = 1;
115 		sectors = 9;
116 	} else if (strcasecmp(sizeid, "ds") == 0) {
117 		sides = 2;
118 		sectors = 9;
119 	} else if (strcasecmp(sizeid, "hd") == 0) {
120 		sides = 2;
121 		sectors = 18;
122 	} else if (strcasecmp(sizeid, "ed") == 0) {
123 		sides = 2;
124 		sectors = 36;
125 	} else {
126 		return "ERROR: given disk size isn't one of supported ones!\n";
127 	}
128 	if (CreateBlankImage_CreateFile(filename, tracks, sectors, sides)) {
129 		return NULL;
130 	}
131 	return "ERROR: Disk creation failed.\n";
132 }
133 
134 /**
135  * Print program usage
136  */
usage(const char * name)137 static void usage(const char *name)
138 {
139 		printf("\n\
140 Hatari MSA (Magic Shadow Archiver) / ST disk image creator & converter v0.3.\n\
141 \n\
142 Usage:  %s FILENAME [DISK SIZE]\n\
143 \n\
144 If you give only one parameter - the file name of an existing MSA\n\
145 or ST disk image, this image will be converted to the other disk image\n\
146 format under a suitable new file name.  Disk image format is recognized\n\
147 based on the file name extension (.msa or .st).\n\
148 \n\
149 If the given file doesn't exist and you give also a disk size\n\
150 (SS, DS, HD, ED), an empty disk of the given size will be created.\n\
151 \n\
152 This software is distributed under the GNU General Public License, version 2\n\
153 or at your option any later version. Please read the file gpl.txt for details.\n\
154 \n",
155 		       name);
156 }
157 
158 /**
159  * Command line argument parsing and new disk creation
160  */
main(int argc,char * argv[])161 int main(int argc, char *argv[])
162 {
163 	bool isMsa;
164 	int retval;
165 	long disksize;
166 	unsigned char *diskbuf;
167 	const char *srcfile, *srcdot;
168 	char *dstfile, *dstdot;
169 	int ImageType;
170 	int drive;
171 
172 	if(argc < 2 || argv[1][0] == '-') {
173 		usage(argv[0]);
174 		return 0;
175 	}
176 
177 	srcfile = argv[1];
178 	srcdot = strrchr(srcfile, '.');
179 	if(srcdot == NULL) {
180 		usage(argv[0]);
181 		fprintf(stderr, "ERROR: extension missing for file name %s!\n", argv[1]);
182 		return -1;
183 	}
184 
185 	if (strcasecmp(srcdot, ".msa") == 0) {
186 		isMsa = true;
187 	} else if (strcasecmp(srcdot, ".st") == 0) {
188 		isMsa = false;
189 	} else {
190 		usage(argv[0]);
191 		fprintf(stderr, "ERROR: unrecognized file name extension %s (not .msa or .st)!\n", srcdot);
192 		return -1;
193 	}
194 
195 	if (!File_Exists(srcfile)) {
196 		const char *errstr;
197 		if (argc != 3) {
198 			usage(argv[0]);
199 			fprintf(stderr, "ERROR: disk size for the new disk image not given!\n");
200 			return -1;
201 		}
202 		errstr = create_image(srcfile, argv[2]);
203 		if (errstr) {
204 			usage(argv[0]);
205 			fputs(errstr, stderr);
206 			return -1;
207 		}
208 		return 0;
209 	}
210 
211 	dstfile = malloc(strlen(srcfile) + 6);
212 	if (dstfile == NULL) {
213 		fprintf(stderr, "ERROR: No memory for new disk name!\n");
214 		return -1;
215 	}
216 
217 	strcpy(dstfile, srcfile);
218 	dstdot = strrchr(dstfile, '.');
219 	if (isMsa) {
220 		/* Convert MSA to ST disk image */
221 		strcpy(dstdot, ".st");
222 	} else {
223 		/* Convert ST to MSA disk image */
224 		strcpy(dstdot, ".msa");
225 	}
226 
227 	if (File_Exists(dstfile)) {
228 		fprintf(stderr, "ERROR: Destination disk image %s exists already!\n", dstfile);
229 		free(dstfile);
230 		return -1;
231 	}
232 
233 	drive = 0;                              /* drive is not used for ST/MSA/DIM, set it to 0 */
234 
235 	if (isMsa) {
236 		/* Read the source disk image */
237 		diskbuf = MSA_ReadDisk(drive, srcfile, &disksize, &ImageType);
238 		if (!diskbuf || disksize < 512*8) {
239 			fprintf(stderr, "ERROR: could not read MSA disk %s!\n", srcfile);
240 			retval = -1;
241 		} else {
242 			printf("Converting %s to %s (%li Bytes).\n", srcfile, dstfile, disksize);
243 			retval = File_Save(dstfile, diskbuf, disksize, FALSE);
244 		}
245 	} else {
246 		/* Just read disk image directly into buffer */
247 		disksize = 0;
248 		diskbuf = HFile_Read(srcfile, &disksize, NULL);
249 		if (!diskbuf || disksize < 512*8) {
250 			fprintf(stderr, "ERROR: could not read ST disk %s!\n", srcfile);
251 			retval = -1;
252 		} else {
253 			printf("Converting %s to %s (%li Bytes).\n", srcfile, dstfile, disksize);
254 			retval = MSA_WriteDisk(drive, dstfile, diskbuf, disksize);
255 		}
256 	}
257 
258 	if (diskbuf) {
259 		free(diskbuf);
260 	}
261 	free(dstfile);
262 
263 	return retval;
264 }
265