Mercurial > hg > sidinfo
annotate sidinfo.c @ 44:7b137e4e817c
Fix to match the changes in th_args API.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Sat, 22 Nov 2014 23:46:56 +0200 |
parents | 3414fc882229 |
children | ed8c803a948c |
rev | line source |
---|---|
2 | 1 /* |
2 * SIDInfo - PSID/RSID information displayer | |
3 * Written by Matti 'ccr' Hämäläinen | |
4 * (C) Copyright 2014 Tecnic Software productions (TNSP) | |
5 */ | |
0 | 6 #include "th_args.h" |
7 #include "th_endian.h" | |
2 | 8 #include "th_string.h" |
0 | 9 #include "th_crypto.h" |
10 | |
28 | 11 // Some constants |
2 | 12 #define PSID_MAGIC_LEN 4 |
13 #define PSID_STR_LEN 32 | |
1 | 14 #define PSID_BUFFER_SIZE (1024 * 16) |
15 | |
0 | 16 |
28 | 17 // Flags for various information fields |
2 | 18 enum |
19 { | |
35
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
20 SIF_NONE = 0, |
2 | 21 |
35
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
22 SIF_TYPE = 0x00000001, |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
23 SIF_VERSION = 0x00000002, |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
24 SIF_DATA_OFFS = 0x00000004, |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
25 SIF_LOAD_ADDR = 0x00000008, |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
26 SIF_INIT_ADDR = 0x00000010, |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
27 SIF_PLAY_ADDR = 0x00000020, |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
28 SIF_SONGS = 0x00000040, |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
29 SIF_START_SONG = 0x00000080, |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
30 SIF_SPEEDS = 0x00000100, |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
31 SIF_SID_NAME = 0x00000200, |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
32 SIF_SID_AUTHOR = 0x00000400, |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
33 SIF_SID_COPYRIGHT = 0x00000800, |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
34 SIF_PLAYER_TYPE = 0x00001000, |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
35 SIF_PLAYSID_TUNE = 0x00002000, |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
36 SIF_VIDEO_CLOCK = 0x00004000, |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
37 SIF_SID_MODEL = 0x00008000, |
2 | 38 |
35
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
39 SIF_DATA_SIZE = 0x00100000, |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
40 SIF_HASH = 0x00200000, |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
41 SIF_FILENAME = 0x10000000, |
2 | 42 |
35
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
43 SIF_ALL = 0xffffffff, |
2 | 44 }; |
45 | |
46 | |
0 | 47 typedef struct |
48 { | |
2 | 49 uint32_t flag; |
50 char *name; | |
51 char *lname; | |
52 } PSFOption; | |
53 | |
54 | |
55 const PSFOption optPSFlags[] = | |
56 { | |
35
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
57 { SIF_TYPE , "Type" , NULL }, |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
58 { SIF_VERSION , "Version" , NULL }, |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
59 { SIF_DATA_OFFS , "DataOffs" , "Data offset" }, |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
60 { SIF_DATA_SIZE , "DataSize" , "Data size" }, |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
61 { SIF_LOAD_ADDR , "LoadAddr" , "Load address" }, |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
62 { SIF_INIT_ADDR , "InitAddr" , "Init address" }, |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
63 { SIF_PLAY_ADDR , "PlayAddr" , "Play address" }, |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
64 { SIF_SONGS , "Songs" , "Songs" }, |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
65 { SIF_START_SONG , "StartSong" , "Start song" }, |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
66 { SIF_SID_NAME , "Name" , NULL }, |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
67 { SIF_SID_AUTHOR , "Author" , NULL }, |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
68 { SIF_SID_COPYRIGHT , "Copyright" , NULL }, |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
69 { SIF_HASH , "Hash" , NULL }, |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
70 { SIF_FILENAME , "Filename" , NULL }, |
28 | 71 |
35
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
72 { SIF_PLAYER_TYPE , "PlayerType" , "Player type" }, |
36 | 73 { SIF_PLAYSID_TUNE , "PlayerCompat", "Player compatibility" }, |
35
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
74 { SIF_VIDEO_CLOCK , "VideoClock" , "Video clock speed" }, |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
75 { SIF_SID_MODEL , "SIDModel" , "SID model" }, |
28 | 76 |
35
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
77 { SIF_ALL , "All" , NULL }, |
2 | 78 }; |
79 | |
80 const int noptPSFlags = sizeof(optPSFlags) / sizeof(optPSFlags[0]); | |
81 | |
82 | |
28 | 83 // Option variables |
2 | 84 BOOL optParsable = FALSE, |
7 | 85 optNoNamePrefix = FALSE, |
29 | 86 optHexadecimal = FALSE, |
87 optOneLine = FALSE; | |
33
39d9df17c8b1
Add field separator argument to -l option.
Matti Hamalainen <ccr@tnsp.org>
parents:
32
diff
changeset
|
88 char * optFieldSep = NULL; |
35
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
89 uint32_t optFields = SIF_ALL; |
19 | 90 int optNFiles = 0; |
2 | 91 |
92 | |
28 | 93 // Define option arguments |
44
7b137e4e817c
Fix to match the changes in th_args API.
Matti Hamalainen <ccr@tnsp.org>
parents:
41
diff
changeset
|
94 static const th_optarg_t optList[] = |
2 | 95 { |
96 { 0, '?', "help", "Show this help", OPT_NONE }, | |
24
16d6b5029543
Disable verbose option for now, it does not do anything at the moment.
Matti Hamalainen <ccr@tnsp.org>
parents:
23
diff
changeset
|
97 // { 1, 'v', "verbose", "Be more verbose", OPT_NONE }, |
2 | 98 { 2, 'p', "parsable", "Output in script-parsable format", OPT_NONE }, |
7 | 99 { 5, 'n', "noprefix", "Output without field name prefix", OPT_NONE }, |
33
39d9df17c8b1
Add field separator argument to -l option.
Matti Hamalainen <ccr@tnsp.org>
parents:
32
diff
changeset
|
100 { 6, 'l', "line", "Output in one line format, -l <field separator>", OPT_ARGREQ }, |
2 | 101 { 3, 'f', "fields", "Show only specified field(s)", OPT_ARGREQ }, |
102 { 4, 'x', "hex", "Use hexadecimal values", OPT_NONE }, | |
103 }; | |
104 | |
44
7b137e4e817c
Fix to match the changes in th_args API.
Matti Hamalainen <ccr@tnsp.org>
parents:
41
diff
changeset
|
105 static const int optListN = sizeof(optList) / sizeof(optList[0]); |
2 | 106 |
107 | |
108 void argShowHelp(void) | |
109 { | |
110 int index, n; | |
111 | |
20 | 112 th_print_banner(stdout, th_prog_name, "[options] <sid filename> [sid filename #2 ..]"); |
44
7b137e4e817c
Fix to match the changes in th_args API.
Matti Hamalainen <ccr@tnsp.org>
parents:
41
diff
changeset
|
113 th_args_help(stdout, optList, optListN, 0); |
2 | 114 printf( |
115 "\n" | |
116 "Available fields:\n"); | |
3 | 117 |
2 | 118 for (index = n = 0; index < noptPSFlags; index++) |
119 { | |
120 const PSFOption *opt = &optPSFlags[index]; | |
121 printf("%s%s", opt->name, (index < noptPSFlags - 1) ? ", " : "\n\n"); | |
122 if (++n > 5) | |
123 { | |
124 printf("\n"); | |
125 n = 0; | |
126 } | |
127 } | |
5 | 128 |
129 printf("Example: %s -x -p -f hash,copyright somesidfile.sid\n", th_prog_name); | |
2 | 130 } |
131 | |
132 | |
133 int argMatchPSField(const char *field) | |
134 { | |
135 int index, found = -1; | |
136 size_t len = strlen(field); | |
137 for (index = 0; index < noptPSFlags; index++) | |
138 { | |
139 const PSFOption *opt = &optPSFlags[index]; | |
140 if (strncasecmp(opt->name, field, len) == 0) | |
141 { | |
142 if (found >= 0) | |
143 return -2; | |
144 found = index; | |
145 } | |
146 } | |
147 | |
148 return found; | |
149 } | |
150 | |
151 | |
152 BOOL argParsePSField(char *opt, char *end, uint32_t *fields) | |
153 { | |
154 // Trim whitespace | |
155 if (end != NULL) | |
156 { | |
157 *end = 0; | |
158 for (end--; end > opt && *end && th_isspace(*end); end--) | |
159 *end = 0; | |
160 } | |
161 while (*opt && th_isspace(*opt)) opt++; | |
162 | |
163 // Match field name | |
164 int found = argMatchPSField(opt); | |
165 switch (found) | |
166 { | |
167 case -1: | |
168 THERR("No such flag '%s'.\n", opt); | |
169 return FALSE; | |
170 | |
171 case -2: | |
172 THERR("Flag '%s' is ambiguous.\n", opt); | |
173 return FALSE; | |
3 | 174 |
2 | 175 default: |
176 *fields |= optPSFlags[found].flag; | |
177 return TRUE; | |
178 } | |
179 } | |
180 | |
181 | |
182 BOOL argHandleOpt(const int optN, char *optArg, char *currArg) | |
183 { | |
184 switch (optN) | |
185 { | |
186 case 0: | |
187 argShowHelp(); | |
188 exit(0); | |
189 break; | |
190 | |
191 case 1: | |
192 th_verbosityLevel++; | |
193 break; | |
194 | |
195 case 2: | |
196 optParsable = TRUE; | |
197 break; | |
198 | |
199 case 3: | |
200 { | |
201 char *start = optArg; | |
35
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
202 optFields = SIF_NONE; |
2 | 203 |
204 while (*start) | |
205 { | |
206 char *end = strchr(start, ','); | |
207 | |
208 if (!argParsePSField(start, end, &optFields)) | |
209 return FALSE; | |
210 | |
211 if (!end) | |
212 break; | |
213 | |
214 start = end + 1; | |
215 } | |
3 | 216 |
2 | 217 //fprintf(stderr, "%08x\n", optFields); |
218 } | |
219 break; | |
220 | |
221 case 4: | |
222 optHexadecimal = TRUE; | |
223 break; | |
224 | |
7 | 225 case 5: |
226 optNoNamePrefix = TRUE; | |
227 break; | |
228 | |
29 | 229 case 6: |
230 optOneLine = TRUE; | |
33
39d9df17c8b1
Add field separator argument to -l option.
Matti Hamalainen <ccr@tnsp.org>
parents:
32
diff
changeset
|
231 optFieldSep = optArg; |
29 | 232 break; |
233 | |
2 | 234 default: |
235 THERR("Unknown option '%s'.\n", currArg); | |
236 return FALSE; | |
237 } | |
238 | |
239 return TRUE; | |
240 } | |
241 | |
242 | |
243 typedef struct | |
244 { | |
245 char magic[PSID_MAGIC_LEN + 1]; // "PSID" / "RSID" magic identifier | |
246 uint16_t | |
247 version, // Version number | |
0 | 248 dataOffset, // Start of actual c64 data in file |
249 loadAddress, // Loading address | |
250 initAddress, // Initialization address | |
251 playAddress, // Play one frame | |
252 nSongs, // Number of subsongs | |
253 startSong; // Default starting song | |
254 uint32_t speed; // Speed | |
2 | 255 char sidName[PSID_STR_LEN + 1]; // Descriptive text-fields, ASCIIZ |
256 char sidAuthor[PSID_STR_LEN + 1]; | |
257 char sidCopyright[PSID_STR_LEN + 1]; | |
0 | 258 |
259 // PSIDv2 data | |
260 uint16_t flags; // Flags | |
261 uint8_t startPage, pageLength; | |
262 uint16_t reserved; | |
263 | |
1 | 264 // Extra data |
0 | 265 BOOL isRSID; |
1 | 266 size_t dataSize; // Total size of data - header |
267 th_md5hash_t hash; // Songlength database hash | |
0 | 268 |
269 } PSIDHeader; | |
270 | |
271 | |
35
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
272 enum |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
273 { |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
274 PSF_PLAYER_TYPE = 0x0001, // 0 = built-in, 1 = Compute! SIDPlayer MUS |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
275 PSF_PLAYSID_TUNE = 0x0002, // 0 = Real C64-compatible, 1 = PlaySID specific (v2NG) |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
276 |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
277 PSF_CLOCK_UNKNOWN = 0x0000, // Video standard used (v2NG) |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
278 PSF_CLOCK_PAL = 0x0004, |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
279 PSF_CLOCK_NTSC = 0x0008, |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
280 PSF_CLOCK_ANY = 0x000c, |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
281 PSF_CLOCK_MASK = 0x000c, |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
282 |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
283 PSF_MODEL_UNKNOWN = 0x0000, // SID model (v2NG) |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
284 PSF_MODEL_MOS6581 = 0x0010, |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
285 PSF_MODEL_MOS8580 = 0x0020, |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
286 PSF_MODEL_ANY = 0x0030, |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
287 PSF_MODEL_MASK = 0x0030, |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
288 }; |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
289 |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
290 |
2 | 291 static void siAppendHash16(th_md5state_t *state, uint16_t data) |
292 { | |
293 uint8_t ib8[2]; | |
294 ib8[0] = data & 0xff; | |
295 ib8[1] = data >> 8; | |
296 th_md5_append(state, (uint8_t *) &ib8, sizeof(ib8)); | |
297 } | |
298 | |
299 | |
300 int siReadPSIDFile(FILE *inFile, PSIDHeader *psid) | |
0 | 301 { |
1 | 302 th_md5state_t state; |
303 uint8_t tmp8, *fileData = NULL; | |
304 int index, ret = -1; | |
305 size_t read; | |
306 BOOL first; | |
307 | |
308 memset(psid, 0, sizeof(*psid)); | |
309 | |
310 if ((fileData = (uint8_t *) th_malloc(PSID_BUFFER_SIZE)) == NULL) | |
311 { | |
312 THERR("Error allocating temporary data buffer of %d bytes.\n", PSID_BUFFER_SIZE); | |
313 goto error; | |
314 } | |
3 | 315 |
0 | 316 // Read PSID header in |
2 | 317 if (!th_fread_str(inFile, (uint8_t *) psid->magic, PSID_MAGIC_LEN) || |
1 | 318 !th_fread_be16(inFile, &psid->version) || |
319 !th_fread_be16(inFile, &psid->dataOffset) || | |
320 !th_fread_be16(inFile, &psid->loadAddress) || | |
321 !th_fread_be16(inFile, &psid->initAddress) || | |
322 !th_fread_be16(inFile, &psid->playAddress) || | |
323 !th_fread_be16(inFile, &psid->nSongs) || | |
324 !th_fread_be16(inFile, &psid->startSong) || | |
325 !th_fread_be32(inFile, &psid->speed)) | |
0 | 326 { |
1 | 327 THERR("Could not read PSID/RSID header.\n"); |
0 | 328 goto error; |
329 } | |
330 | |
2 | 331 psid->magic[PSID_MAGIC_LEN] = 0; |
332 | |
0 | 333 if ((psid->magic[0] != 'R' && psid->magic[0] != 'P') || |
334 psid->magic[1] != 'S' || psid->magic[2] != 'I' || psid->magic[3] != 'D' || | |
335 psid->version < 1 || psid->version > 3) | |
336 { | |
1 | 337 THERR("Not a supported PSID or RSID file.\n"); |
0 | 338 goto error; |
339 } | |
340 | |
1 | 341 psid->isRSID = psid->magic[0] == 'R'; |
0 | 342 |
2 | 343 if (!th_fread_str(inFile, (uint8_t *)psid->sidName, PSID_STR_LEN) || |
344 !th_fread_str(inFile, (uint8_t *)psid->sidAuthor, PSID_STR_LEN) || | |
345 !th_fread_str(inFile, (uint8_t *)psid->sidCopyright, PSID_STR_LEN)) | |
0 | 346 { |
1 | 347 THERR("Error reading SID file header.\n"); |
0 | 348 goto error; |
349 } | |
350 | |
2 | 351 psid->sidName[PSID_STR_LEN] = 0; |
352 psid->sidAuthor[PSID_STR_LEN] = 0; | |
353 psid->sidCopyright[PSID_STR_LEN] = 0; | |
354 | |
0 | 355 // Check if we need to load PSIDv2NG header ... |
356 if (psid->version >= 2) | |
357 { | |
358 // Yes, we need to | |
1 | 359 if (!th_fread_be16(inFile, &psid->flags) || |
360 !th_fread_byte(inFile, &psid->startPage) || | |
361 !th_fread_byte(inFile, &psid->pageLength) || | |
362 !th_fread_be16(inFile, &psid->reserved)) | |
0 | 363 { |
1 | 364 THERR("Error reading PSID/RSID v2+ extra header data.\n"); |
0 | 365 goto error; |
366 } | |
367 } | |
368 | |
1 | 369 // Initialize MD5-hash calculation |
370 th_md5_init(&state); | |
0 | 371 |
1 | 372 // Process actual data |
373 psid->dataSize = 0; | |
374 first = TRUE; | |
2 | 375 do |
376 { | |
1 | 377 read = fread(fileData, sizeof(uint8_t), PSID_BUFFER_SIZE, inFile); |
378 psid->dataSize += read; | |
0 | 379 |
1 | 380 if (first && psid->loadAddress == 0) |
381 { | |
8
cfc74ec918dc
Fix handling of "large" SID files.
Matti Hamalainen <ccr@tnsp.org>
parents:
7
diff
changeset
|
382 if (read < 4) |
cfc74ec918dc
Fix handling of "large" SID files.
Matti Hamalainen <ccr@tnsp.org>
parents:
7
diff
changeset
|
383 { |
cfc74ec918dc
Fix handling of "large" SID files.
Matti Hamalainen <ccr@tnsp.org>
parents:
7
diff
changeset
|
384 THERR("Error reading song data, unexpectedly small file.\n"); |
cfc74ec918dc
Fix handling of "large" SID files.
Matti Hamalainen <ccr@tnsp.org>
parents:
7
diff
changeset
|
385 goto error; |
cfc74ec918dc
Fix handling of "large" SID files.
Matti Hamalainen <ccr@tnsp.org>
parents:
7
diff
changeset
|
386 } |
39
3ce9d2198193
Grab the actual loading address from data block if PSID header loadAddr value is 0.
Matti Hamalainen <ccr@tnsp.org>
parents:
37
diff
changeset
|
387 |
3ce9d2198193
Grab the actual loading address from data block if PSID header loadAddr value is 0.
Matti Hamalainen <ccr@tnsp.org>
parents:
37
diff
changeset
|
388 // Grab the actual load address |
3ce9d2198193
Grab the actual loading address from data block if PSID header loadAddr value is 0.
Matti Hamalainen <ccr@tnsp.org>
parents:
37
diff
changeset
|
389 psid->loadAddress = TH_LE16_TO_NATIVE(*(uint16_t *) fileData); |
8
cfc74ec918dc
Fix handling of "large" SID files.
Matti Hamalainen <ccr@tnsp.org>
parents:
7
diff
changeset
|
390 |
1 | 391 // Strip load address (2 first bytes) |
392 th_md5_append(&state, &fileData[2], read - 2); | |
393 first = FALSE; | |
394 } | |
395 else | |
8
cfc74ec918dc
Fix handling of "large" SID files.
Matti Hamalainen <ccr@tnsp.org>
parents:
7
diff
changeset
|
396 if (read > 0) |
1 | 397 { |
398 // Append "as is" | |
399 th_md5_append(&state, fileData, read); | |
400 } | |
401 } while (read > 0 && !feof(inFile)); | |
0 | 402 |
1 | 403 // Append header data to hash |
2 | 404 siAppendHash16(&state, psid->initAddress); |
405 siAppendHash16(&state, psid->playAddress); | |
406 siAppendHash16(&state, psid->nSongs); | |
0 | 407 |
408 // Append song speed data to hash | |
1 | 409 tmp8 = psid->isRSID ? 60 : 0; |
0 | 410 for (index = 0; index < psid->nSongs && index < 32; index++) |
411 { | |
1 | 412 if (psid->isRSID) |
413 tmp8 = 60; | |
0 | 414 else |
1 | 415 tmp8 = (psid->speed & (1 << index)) ? 60 : 0; |
0 | 416 |
1 | 417 th_md5_append(&state, &tmp8, sizeof(tmp8)); |
0 | 418 } |
419 | |
420 // Rest of songs (more than 32) | |
421 for (index = 32; index < psid->nSongs; index++) | |
1 | 422 th_md5_append(&state, &tmp8, sizeof(tmp8)); |
0 | 423 |
424 // PSIDv2NG specific | |
425 if (psid->version >= 2) | |
426 { | |
427 // REFER TO SIDPLAY HEADERS FOR MORE INFORMATION | |
1 | 428 tmp8 = (psid->flags >> 2) & 3; |
429 if (tmp8 == 2) | |
430 th_md5_append(&state, &tmp8, sizeof(tmp8)); | |
0 | 431 } |
432 | |
433 // Calculate the hash | |
1 | 434 th_md5_finish(&state, psid->hash); |
435 ret = 0; | |
0 | 436 |
1 | 437 error: |
0 | 438 // Free buffer |
1 | 439 th_free(fileData); |
440 return ret; | |
0 | 441 } |
442 | |
443 | |
31 | 444 static void siPrintFieldPrefix(FILE *outFile, const char *name) |
2 | 445 { |
7 | 446 if (!optNoNamePrefix) |
29 | 447 fprintf(outFile, optParsable ? "%s=" : "%-20s : ", name); |
2 | 448 } |
449 | |
450 | |
33
39d9df17c8b1
Add field separator argument to -l option.
Matti Hamalainen <ccr@tnsp.org>
parents:
32
diff
changeset
|
451 static void siPrintFieldSeparator(FILE *outFile) |
39d9df17c8b1
Add field separator argument to -l option.
Matti Hamalainen <ccr@tnsp.org>
parents:
32
diff
changeset
|
452 { |
39d9df17c8b1
Add field separator argument to -l option.
Matti Hamalainen <ccr@tnsp.org>
parents:
32
diff
changeset
|
453 fprintf(outFile, optOneLine ? optFieldSep : "\n"); |
39d9df17c8b1
Add field separator argument to -l option.
Matti Hamalainen <ccr@tnsp.org>
parents:
32
diff
changeset
|
454 } |
39d9df17c8b1
Add field separator argument to -l option.
Matti Hamalainen <ccr@tnsp.org>
parents:
32
diff
changeset
|
455 |
39d9df17c8b1
Add field separator argument to -l option.
Matti Hamalainen <ccr@tnsp.org>
parents:
32
diff
changeset
|
456 |
29 | 457 static void siPrintPSIDInfoLine(FILE *outFile, BOOL *shown, const int xindex, const char *xfmt, const char *xaltfmt, ...) |
2 | 458 { |
459 const PSFOption *opt = &optPSFlags[xindex]; | |
29 | 460 if (optFields & opt->flag) |
2 | 461 { |
462 va_list ap; | |
29 | 463 const char *fmt = optHexadecimal ? (xaltfmt != NULL ? xaltfmt : xfmt) : xfmt; |
2 | 464 |
31 | 465 siPrintFieldPrefix(outFile, (optParsable || opt->lname == NULL) ? opt->name : opt->lname); |
2 | 466 |
467 va_start(ap, xaltfmt); | |
468 | |
29 | 469 if (optParsable) |
2 | 470 vfprintf(outFile, fmt, ap); |
471 else | |
472 vfprintf(outFile, fmt, ap); | |
473 | |
474 va_end(ap); | |
3 | 475 |
33
39d9df17c8b1
Add field separator argument to -l option.
Matti Hamalainen <ccr@tnsp.org>
parents:
32
diff
changeset
|
476 siPrintFieldSeparator(outFile); |
29 | 477 *shown = TRUE; |
2 | 478 } |
479 } | |
480 | |
29 | 481 #define PR(xindex, xfmt, xaltfmt, ...) siPrintPSIDInfoLine(outFile, &shown, xindex, xfmt, xaltfmt, __VA_ARGS__ ) |
2 | 482 |
483 | |
29 | 484 void siPrintPSIDInformation(FILE *outFile, const char *filename, const PSIDHeader *psid) |
2 | 485 { |
29 | 486 BOOL shown = FALSE; |
487 | |
16 | 488 PR(13, "%s", NULL, filename); |
9
c1fba4abf56f
Make filename printing optional.
Matti Hamalainen <ccr@tnsp.org>
parents:
8
diff
changeset
|
489 |
2 | 490 PR( 0, "%s", NULL, psid->magic); |
491 PR( 1, "%d.%d", NULL, (psid->version & 0xff), (psid->version >> 8)); | |
35
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
492 PR(14, "%s", NULL, (psid->flags & PSF_PLAYER_TYPE) ? "Compute! SIDPlayer MUS" : "Normal built-in"); |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
493 if (psid->version >= 2) |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
494 { |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
495 char *str; |
36 | 496 PR(15, "%s", NULL, (psid->flags & PSF_PLAYSID_TUNE) ? "PlaySID" : "C64 compatible"); |
35
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
497 |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
498 switch (psid->flags & PSF_CLOCK_MASK) |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
499 { |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
500 case PSF_CLOCK_UNKNOWN : str = "Unknown"; break; |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
501 case PSF_CLOCK_PAL : str = "PAL 50Hz"; break; |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
502 case PSF_CLOCK_NTSC : str = "NTSC 60Hz"; break; |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
503 case PSF_CLOCK_ANY : str = "PAL / NTSC"; break; |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
504 default : str = "?"; break; |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
505 } |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
506 PR(16, "%s", NULL, str); |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
507 |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
508 switch (psid->flags & PSF_MODEL_MASK) |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
509 { |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
510 case PSF_MODEL_UNKNOWN : str = "Unknown"; break; |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
511 case PSF_MODEL_MOS6581 : str = "MOS6581"; break; |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
512 case PSF_MODEL_MOS8580 : str = "MOS8580"; break; |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
513 case PSF_MODEL_ANY : str = "MOS6581 / MOS8580"; break; |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
514 default : str = "?"; break; |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
515 } |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
516 PR(17, "%s", NULL, str); |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
517 } |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
518 |
2 | 519 PR( 2, "%d", "$%08x", psid->dataOffset); |
520 PR( 3, "%d", "$%08x", psid->dataSize); | |
521 PR( 4, "%d", "$%04x", psid->loadAddress); | |
522 PR( 5, "%d", "$%04x", psid->initAddress); | |
523 PR( 6, "%d", "$%04x", psid->playAddress); | |
524 PR( 7, "%d", "$%04x", psid->nSongs); | |
525 PR( 8, "%d", "$%04x", psid->startSong); | |
526 | |
527 PR( 9, "%s", NULL, psid->sidName); | |
528 PR(10, "%s", NULL, psid->sidAuthor); | |
3 | 529 PR(11, "%s", NULL, psid->sidCopyright); |
2 | 530 |
35
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
531 if (optFields & SIF_HASH) |
2 | 532 { |
31 | 533 siPrintFieldPrefix(outFile, "Hash"); |
2 | 534 th_md5_print(outFile, psid->hash); |
33
39d9df17c8b1
Add field separator argument to -l option.
Matti Hamalainen <ccr@tnsp.org>
parents:
32
diff
changeset
|
535 siPrintFieldSeparator(outFile); |
29 | 536 } |
537 | |
34
50fe65830c03
Fix non-one-line entry output.
Matti Hamalainen <ccr@tnsp.org>
parents:
33
diff
changeset
|
538 if (shown && optOneLine) |
2 | 539 fprintf(outFile, "\n"); |
540 } | |
541 | |
0 | 542 |
19 | 543 BOOL argHandleFile(char *filename) |
544 { | |
545 static PSIDHeader psid; | |
546 static FILE *inFile = NULL; | |
547 optNFiles++; | |
548 | |
549 if ((inFile = fopen(filename, "rb")) == NULL) | |
550 { | |
551 THERR("Could not open file '%s'.\n", filename); | |
27
4dd463eebb74
Fix argument handling when file does not exist.
Matti Hamalainen <ccr@tnsp.org>
parents:
25
diff
changeset
|
552 return TRUE; |
19 | 553 } |
554 | |
555 // Read PSID data | |
556 if (siReadPSIDFile(inFile, &psid) != 0) | |
23 | 557 { |
558 THERR("Error reading %s\n", filename); | |
19 | 559 goto error; |
23 | 560 } |
19 | 561 |
562 // Output | |
29 | 563 siPrintPSIDInformation(stdout, filename, &psid); |
19 | 564 |
565 // Shutdown | |
566 error: | |
567 if (inFile != NULL) | |
568 fclose(inFile); | |
569 | |
570 return TRUE; | |
571 } | |
572 | |
573 | |
0 | 574 int main(int argc, char *argv[]) |
575 { | |
576 // Initialize | |
41 | 577 th_init("SIDInfo", "PSID/RSID information displayer", "0.5.1", NULL, NULL); |
0 | 578 th_verbosityLevel = 0; |
579 | |
2 | 580 // Parse command line arguments |
581 if (!th_args_process(argc, argv, optList, optListN, | |
23 | 582 argHandleOpt, argHandleFile, OPTH_ONLY_OPTS)) |
2 | 583 return -1; |
584 | |
29 | 585 if (optOneLine) |
586 { | |
587 optParsable = FALSE; | |
588 optNoNamePrefix = TRUE; | |
589 } | |
590 | |
23 | 591 // Process files |
592 if (!th_args_process(argc, argv, optList, optListN, | |
593 argHandleOpt, argHandleFile, OPTH_ONLY_OTHER)) | |
594 return -2; | |
595 | |
19 | 596 if (optNFiles == 0) |
2 | 597 { |
598 argShowHelp(); | |
19 | 599 THERR("No filename(s) specified.\n"); |
2 | 600 } |
1 | 601 |
19 | 602 return 0; |
0 | 603 } |