Mercurial > hg > sidinfo
annotate sidinfo.c @ 35:79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Fri, 26 Sep 2014 02:26:43 +0300 |
parents | 50fe65830c03 |
children | ad6acc8144bd |
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" }, |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
73 { SIF_PLAYSID_TUNE , "PlaySIDTune", "PlaySID tune" }, |
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 |
2 | 94 static optarg_t optList[] = |
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 | |
105 static const int optListN = (sizeof(optList) / sizeof(optList[0])); | |
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 ..]"); |
2 | 113 th_args_help(stdout, optList, optListN); |
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 } |
cfc74ec918dc
Fix handling of "large" SID files.
Matti Hamalainen <ccr@tnsp.org>
parents:
7
diff
changeset
|
387 |
1 | 388 // Strip load address (2 first bytes) |
389 th_md5_append(&state, &fileData[2], read - 2); | |
390 first = FALSE; | |
391 } | |
392 else | |
8
cfc74ec918dc
Fix handling of "large" SID files.
Matti Hamalainen <ccr@tnsp.org>
parents:
7
diff
changeset
|
393 if (read > 0) |
1 | 394 { |
395 // Append "as is" | |
396 th_md5_append(&state, fileData, read); | |
397 } | |
398 } while (read > 0 && !feof(inFile)); | |
0 | 399 |
1 | 400 // Append header data to hash |
2 | 401 siAppendHash16(&state, psid->initAddress); |
402 siAppendHash16(&state, psid->playAddress); | |
403 siAppendHash16(&state, psid->nSongs); | |
0 | 404 |
405 // Append song speed data to hash | |
1 | 406 tmp8 = psid->isRSID ? 60 : 0; |
0 | 407 for (index = 0; index < psid->nSongs && index < 32; index++) |
408 { | |
1 | 409 if (psid->isRSID) |
410 tmp8 = 60; | |
0 | 411 else |
1 | 412 tmp8 = (psid->speed & (1 << index)) ? 60 : 0; |
0 | 413 |
1 | 414 th_md5_append(&state, &tmp8, sizeof(tmp8)); |
0 | 415 } |
416 | |
417 // Rest of songs (more than 32) | |
418 for (index = 32; index < psid->nSongs; index++) | |
1 | 419 th_md5_append(&state, &tmp8, sizeof(tmp8)); |
0 | 420 |
421 // PSIDv2NG specific | |
422 if (psid->version >= 2) | |
423 { | |
424 // REFER TO SIDPLAY HEADERS FOR MORE INFORMATION | |
1 | 425 tmp8 = (psid->flags >> 2) & 3; |
426 if (tmp8 == 2) | |
427 th_md5_append(&state, &tmp8, sizeof(tmp8)); | |
0 | 428 } |
429 | |
430 // Calculate the hash | |
1 | 431 th_md5_finish(&state, psid->hash); |
432 ret = 0; | |
0 | 433 |
1 | 434 error: |
0 | 435 // Free buffer |
1 | 436 th_free(fileData); |
437 return ret; | |
0 | 438 } |
439 | |
440 | |
31 | 441 static void siPrintFieldPrefix(FILE *outFile, const char *name) |
2 | 442 { |
7 | 443 if (!optNoNamePrefix) |
29 | 444 fprintf(outFile, optParsable ? "%s=" : "%-20s : ", name); |
2 | 445 } |
446 | |
447 | |
33
39d9df17c8b1
Add field separator argument to -l option.
Matti Hamalainen <ccr@tnsp.org>
parents:
32
diff
changeset
|
448 static void siPrintFieldSeparator(FILE *outFile) |
39d9df17c8b1
Add field separator argument to -l option.
Matti Hamalainen <ccr@tnsp.org>
parents:
32
diff
changeset
|
449 { |
39d9df17c8b1
Add field separator argument to -l option.
Matti Hamalainen <ccr@tnsp.org>
parents:
32
diff
changeset
|
450 fprintf(outFile, optOneLine ? optFieldSep : "\n"); |
39d9df17c8b1
Add field separator argument to -l option.
Matti Hamalainen <ccr@tnsp.org>
parents:
32
diff
changeset
|
451 } |
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 |
29 | 454 static void siPrintPSIDInfoLine(FILE *outFile, BOOL *shown, const int xindex, const char *xfmt, const char *xaltfmt, ...) |
2 | 455 { |
456 const PSFOption *opt = &optPSFlags[xindex]; | |
29 | 457 if (optFields & opt->flag) |
2 | 458 { |
459 va_list ap; | |
29 | 460 const char *fmt = optHexadecimal ? (xaltfmt != NULL ? xaltfmt : xfmt) : xfmt; |
2 | 461 |
31 | 462 siPrintFieldPrefix(outFile, (optParsable || opt->lname == NULL) ? opt->name : opt->lname); |
2 | 463 |
464 va_start(ap, xaltfmt); | |
465 | |
29 | 466 if (optParsable) |
2 | 467 vfprintf(outFile, fmt, ap); |
468 else | |
469 vfprintf(outFile, fmt, ap); | |
470 | |
471 va_end(ap); | |
3 | 472 |
33
39d9df17c8b1
Add field separator argument to -l option.
Matti Hamalainen <ccr@tnsp.org>
parents:
32
diff
changeset
|
473 siPrintFieldSeparator(outFile); |
29 | 474 *shown = TRUE; |
2 | 475 } |
476 } | |
477 | |
29 | 478 #define PR(xindex, xfmt, xaltfmt, ...) siPrintPSIDInfoLine(outFile, &shown, xindex, xfmt, xaltfmt, __VA_ARGS__ ) |
2 | 479 |
480 | |
29 | 481 void siPrintPSIDInformation(FILE *outFile, const char *filename, const PSIDHeader *psid) |
2 | 482 { |
29 | 483 BOOL shown = FALSE; |
484 | |
16 | 485 PR(13, "%s", NULL, filename); |
9
c1fba4abf56f
Make filename printing optional.
Matti Hamalainen <ccr@tnsp.org>
parents:
8
diff
changeset
|
486 |
2 | 487 PR( 0, "%s", NULL, psid->magic); |
488 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
|
489 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
|
490 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
|
491 { |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
492 char *str; |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
493 PR(15, "%s", NULL, (psid->flags & PSF_PLAYSID_TUNE) ? "C64 compatible" : "PlaySID"); |
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 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
|
496 { |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
497 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
|
498 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
|
499 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
|
500 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
|
501 default : str = "?"; break; |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
502 } |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
503 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
|
504 |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
505 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
|
506 { |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
507 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
|
508 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
|
509 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
|
510 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
|
511 default : str = "?"; break; |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
512 } |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
513 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
|
514 } |
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
515 |
2 | 516 PR( 2, "%d", "$%08x", psid->dataOffset); |
517 PR( 3, "%d", "$%08x", psid->dataSize); | |
518 PR( 4, "%d", "$%04x", psid->loadAddress); | |
519 PR( 5, "%d", "$%04x", psid->initAddress); | |
520 PR( 6, "%d", "$%04x", psid->playAddress); | |
521 PR( 7, "%d", "$%04x", psid->nSongs); | |
522 PR( 8, "%d", "$%04x", psid->startSong); | |
523 | |
524 PR( 9, "%s", NULL, psid->sidName); | |
525 PR(10, "%s", NULL, psid->sidAuthor); | |
3 | 526 PR(11, "%s", NULL, psid->sidCopyright); |
2 | 527 |
35
79e6d08b473f
Add more information fields, including SID model, video clock speed, etc.
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
528 if (optFields & SIF_HASH) |
2 | 529 { |
31 | 530 siPrintFieldPrefix(outFile, "Hash"); |
2 | 531 th_md5_print(outFile, psid->hash); |
33
39d9df17c8b1
Add field separator argument to -l option.
Matti Hamalainen <ccr@tnsp.org>
parents:
32
diff
changeset
|
532 siPrintFieldSeparator(outFile); |
29 | 533 } |
534 | |
34
50fe65830c03
Fix non-one-line entry output.
Matti Hamalainen <ccr@tnsp.org>
parents:
33
diff
changeset
|
535 if (shown && optOneLine) |
2 | 536 fprintf(outFile, "\n"); |
537 } | |
538 | |
0 | 539 |
19 | 540 BOOL argHandleFile(char *filename) |
541 { | |
542 static PSIDHeader psid; | |
543 static FILE *inFile = NULL; | |
544 optNFiles++; | |
545 | |
546 if ((inFile = fopen(filename, "rb")) == NULL) | |
547 { | |
548 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
|
549 return TRUE; |
19 | 550 } |
551 | |
552 // Read PSID data | |
553 if (siReadPSIDFile(inFile, &psid) != 0) | |
23 | 554 { |
555 THERR("Error reading %s\n", filename); | |
19 | 556 goto error; |
23 | 557 } |
19 | 558 |
559 // Output | |
29 | 560 siPrintPSIDInformation(stdout, filename, &psid); |
19 | 561 |
562 // Shutdown | |
563 error: | |
564 if (inFile != NULL) | |
565 fclose(inFile); | |
566 | |
567 return TRUE; | |
568 } | |
569 | |
570 | |
0 | 571 int main(int argc, char *argv[]) |
572 { | |
573 // Initialize | |
25 | 574 th_init("SIDInfo", "PSID/RSID information displayer", "0.4", NULL, NULL); |
0 | 575 th_verbosityLevel = 0; |
576 | |
2 | 577 // Parse command line arguments |
578 if (!th_args_process(argc, argv, optList, optListN, | |
23 | 579 argHandleOpt, argHandleFile, OPTH_ONLY_OPTS)) |
2 | 580 return -1; |
581 | |
29 | 582 if (optOneLine) |
583 { | |
584 optParsable = FALSE; | |
585 optNoNamePrefix = TRUE; | |
586 } | |
587 | |
23 | 588 // Process files |
589 if (!th_args_process(argc, argv, optList, optListN, | |
590 argHandleOpt, argHandleFile, OPTH_ONLY_OTHER)) | |
591 return -2; | |
592 | |
19 | 593 if (optNFiles == 0) |
2 | 594 { |
595 argShowHelp(); | |
19 | 596 THERR("No filename(s) specified.\n"); |
2 | 597 } |
1 | 598 |
19 | 599 return 0; |
0 | 600 } |