0
|
1 #include "th_args.h"
|
|
2 #include "th_endian.h"
|
|
3 #include "th_crypto.h"
|
|
4
|
|
5
|
|
6 typedef struct
|
|
7 {
|
|
8 char magic[4]; // "PSID" / "RSID" magic identifier
|
|
9 uint16_t version, // Version number
|
|
10 dataOffset, // Start of actual c64 data in file
|
|
11 loadAddress, // Loading address
|
|
12 initAddress, // Initialization address
|
|
13 playAddress, // Play one frame
|
|
14 nSongs, // Number of subsongs
|
|
15 startSong; // Default starting song
|
|
16 uint32_t speed; // Speed
|
|
17 char sidName[32]; // Descriptive text-fields, ASCIIZ
|
|
18 char sidAuthor[32];
|
|
19 char sidCopyright[32];
|
|
20
|
|
21 // PSIDv2 data
|
|
22 uint16_t flags; // Flags
|
|
23 uint8_t startPage, pageLength;
|
|
24 uint16_t reserved;
|
|
25
|
|
26 // RSID data
|
|
27 BOOL isRSID;
|
|
28
|
|
29 // Songlength database hash
|
|
30 th_md5hash_t hash;
|
|
31 } PSIDHeader;
|
|
32
|
|
33
|
|
34 int si_read_sid_file(FILE *srcFile, PSIDHeader *psid)
|
|
35 {
|
|
36 th_md5
|
|
37
|
|
38 // Read PSID header in
|
|
39 if (!th_fread_str(srcFile, (uint8_t *) psid->magic, sizeof(psid->magic)) ||
|
|
40 !th_fread_be16(srcFile, &psid->version) ||
|
|
41 !th_fread_be16(srcFile, &psid->dataOffset) ||
|
|
42 !th_fread_be16(srcFile, &psid->loadAddress) ||
|
|
43 !th_fread_be16(srcFile, &psid->initAddress) ||
|
|
44 !th_fread_be16(srcFile, &psid->playAddress) ||
|
|
45 !th_fread_be16(srcFile, &psid->nSongs) ||
|
|
46 !th_fread_be16(srcFile, &psid->startSong) ||
|
|
47 !th_fread_be32(srcFile, &psid->speed))
|
|
48 {
|
|
49 THERR("Could not read PSID/RSID header from '%s'\n", filename);
|
|
50 goto error;
|
|
51 }
|
|
52
|
|
53 if ((psid->magic[0] != 'R' && psid->magic[0] != 'P') ||
|
|
54 psid->magic[1] != 'S' || psid->magic[2] != 'I' || psid->magic[3] != 'D' ||
|
|
55 psid->version < 1 || psid->version > 3)
|
|
56 {
|
|
57 THERR("Not a supported PSID or RSID file '%s'\n", filename);
|
|
58 goto error;
|
|
59 }
|
|
60
|
|
61 isRSID = psid->magic[0] == 'R';
|
|
62
|
|
63 if (!th_fread_str(srcFile, (uint8_t *)psid->sidName, sizeof(psid->sidName)) ||
|
|
64 !th_fread_str(srcFile, (uint8_t *)psid->sidAuthor, sizeof(psid->sidAuthor)) ||
|
|
65 !th_fread_str(srcFile, (uint8_t *)psid->sidCopyright, sizeof(psid->sidCopyright)))
|
|
66 {
|
|
67 THERR("Error reading SID file header from '%s'\n", filename);
|
|
68 goto error;
|
|
69 }
|
|
70
|
|
71 // Check if we need to load PSIDv2NG header ...
|
|
72 psidH2.flags = 0; // Just silence a stupid gcc warning
|
|
73
|
|
74 if (psid->version >= 2)
|
|
75 {
|
|
76 // Yes, we need to
|
|
77 if (!th_fread_be16(srcFile, &psidH2.flags) ||
|
|
78 !th_fread_byte(srcFile, &psidH2.startPage) ||
|
|
79 !th_fread_byte(srcFile, &psidH2.pageLength) ||
|
|
80 !th_fread_be16(srcFile, &psidH2.reserved))
|
|
81 {
|
|
82 THERR("Error reading PSID/RSID v2+ extra header data from '%s'\n",
|
|
83 filename);
|
|
84 goto error;
|
|
85 }
|
|
86 }
|
|
87
|
|
88 /* Allocate buffer */
|
|
89 tuneSize = 0;
|
|
90 if ((songData = (uint8_t *) th_malloc(SI_SIDBUF_SIZE)) == NULL)
|
|
91 {
|
|
92 xs_error("Error allocating temp data buffer for file '%s'\n", filename);
|
|
93 goto error;
|
|
94 }
|
|
95
|
|
96 /* Read data to buffer */
|
|
97 result = fread(songData, sizeof(uint8_t), TH_SIDBUF_SIZE, inFile);
|
|
98 xs_fclose(inFile);
|
|
99
|
|
100 /* Initialize and start MD5-hash calculation */
|
|
101 th_md5_init(&inState);
|
|
102
|
|
103 if (psid->loadAddress == 0)
|
|
104 {
|
|
105 /* Strip load address (2 first bytes) */
|
|
106 th_md5_append(&inState, &songData[2], result - 2);
|
|
107 }
|
|
108 else
|
|
109 {
|
|
110 /* Append "as is" */
|
|
111 th_md5_append(&inState, songData, result);
|
|
112 }
|
|
113
|
|
114
|
|
115 /* Append header data to hash */
|
|
116 #define THADDHASH(QDATAB) do { \
|
|
117 uint8_t ib8[2]; \
|
|
118 ib8[0] = (QDATAB & 0xff); \
|
|
119 ib8[1] = (QDATAB >> 8); \
|
|
120 th_md5_append(&inState, (uint8_t *) &ib8, sizeof(ib8)); \
|
|
121 } while (0)
|
|
122
|
|
123 THADDHASH(psid->initAddress);
|
|
124 THADDHASH(psid->playAddress);
|
|
125 THADDHASH(psid->nSongs);
|
|
126 #undef THADDHASH
|
|
127
|
|
128 // Append song speed data to hash
|
|
129 i8 = isRSID ? 60 : 0;
|
|
130 for (index = 0; index < psid->nSongs && index < 32; index++)
|
|
131 {
|
|
132 if (isRSID)
|
|
133 i8 = 60;
|
|
134 else
|
|
135 i8 = (psid->speed & (1 << index)) ? 60 : 0;
|
|
136
|
|
137 th_md5_append(&inState, &i8, sizeof(i8));
|
|
138 }
|
|
139
|
|
140 // Rest of songs (more than 32)
|
|
141 for (index = 32; index < psid->nSongs; index++)
|
|
142 th_md5_append(&inState, &i8, sizeof(i8));
|
|
143
|
|
144 // PSIDv2NG specific
|
|
145 if (psid->version >= 2)
|
|
146 {
|
|
147 // REFER TO SIDPLAY HEADERS FOR MORE INFORMATION
|
|
148 i8 = (psid->flags >> 2) & 3;
|
|
149 if (i8 == 2)
|
|
150 th_md5_append(&inState, &i8, sizeof(i8));
|
|
151 }
|
|
152
|
|
153 // Calculate the hash
|
|
154 th_md5_finish(&inState, psid->hash);
|
|
155
|
|
156
|
|
157 // Free buffer
|
|
158 th_free(songData);
|
|
159 }
|
|
160
|
|
161
|
|
162
|
|
163 int main(int argc, char *argv[])
|
|
164 {
|
|
165 FILE *srcFile = NULL;
|
|
166 uint8_t i8;
|
|
167 int index;
|
|
168
|
|
169 // Initialize
|
|
170 th_init("SIDInfo", "PSID/RSID information displayer", "0.1", NULL, NULL);
|
|
171 th_verbosityLevel = 0;
|
|
172
|
|
173 // Try to open the file
|
|
174 if ((srcFile = fopen(srcFilename, "rb")) == NULL)
|
|
175 goto error;
|
|
176
|
|
177 }
|