Mercurial > hg > sidinfo
comparison sidlib.c @ 163:179ffe97599c
Implement support for the "new" MD5 format of SLDB.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Fri, 16 Feb 2018 22:07:19 +0200 |
parents | 7359170fbb7f |
children | e6c8a235ce2f |
comparison
equal
deleted
inserted
replaced
162:7359170fbb7f | 163:179ffe97599c |
---|---|
45 th_free(tmp); | 45 th_free(tmp); |
46 return FALSE; | 46 return FALSE; |
47 } | 47 } |
48 | 48 |
49 | 49 |
50 int si_read_sid_file(th_ioctx *ctx, PSIDHeader **ppsid) | 50 static BOOL si_read_hash_data(th_ioctx *ctx, PSIDHeader *psid, |
51 { | 51 th_md5state_t *state, BOOL first) |
52 PSIDHeader *psid = NULL; | 52 { |
53 th_md5state_t state; | 53 uint8_t *data = NULL; |
54 uint8_t tmp8, *data = NULL; | 54 BOOL ret = FALSE; |
55 int index, ret = -1; | |
56 size_t read; | 55 size_t read; |
57 BOOL first; | |
58 | 56 |
59 if ((data = (uint8_t *) th_malloc(PSID_BUFFER_SIZE)) == NULL) | 57 if ((data = (uint8_t *) th_malloc(PSID_BUFFER_SIZE)) == NULL) |
60 { | 58 { |
61 th_io_error(ctx, THERR_MALLOC, | 59 th_io_error(ctx, THERR_MALLOC, |
62 "Error allocating temporary data buffer of %d bytes.\n", | 60 "Error allocating temporary data buffer of %d bytes.\n", |
63 PSID_BUFFER_SIZE); | 61 PSID_BUFFER_SIZE); |
64 goto error; | 62 goto error; |
65 } | 63 } |
66 | 64 |
65 psid->dataSize = 0; | |
66 do | |
67 { | |
68 read = thfread(data, sizeof(uint8_t), PSID_BUFFER_SIZE, ctx); | |
69 psid->dataSize += read; | |
70 | |
71 // If load address is 0 in header and we have the first block, grab it | |
72 if (first && psid->loadAddress == 0) | |
73 { | |
74 if (read < 4) | |
75 { | |
76 th_io_error(ctx, THERR_FREAD, | |
77 "Error reading song data, unexpectedly small file.\n"); | |
78 goto error; | |
79 } | |
80 | |
81 // Grab the load address | |
82 psid->loadAddress = TH_LE16_TO_NATIVE(*(uint16_t *) data); | |
83 | |
84 // .. do not include the load address to the hash | |
85 th_md5_append(state, &data[2], read - 2); | |
86 first = FALSE; | |
87 } | |
88 else | |
89 if (read > 0) | |
90 { | |
91 // Append data "as is" | |
92 th_md5_append(state, data, read); | |
93 } | |
94 } while (read > 0 && !thfeof(ctx)); | |
95 | |
96 ret = TRUE; | |
97 | |
98 error: | |
99 th_free(data); | |
100 return ret; | |
101 } | |
102 | |
103 | |
104 BOOL si_read_sid_file(th_ioctx *ctx, PSIDHeader **ppsid, const BOOL newSLDB) | |
105 { | |
106 PSIDHeader *psid = NULL; | |
107 th_md5state_t state; | |
108 BOOL ret = FALSE; | |
109 off_t hdrStart, hdrEnd; | |
110 | |
67 if ((psid = *ppsid = th_malloc0(sizeof(PSIDHeader))) == NULL) | 111 if ((psid = *ppsid = th_malloc0(sizeof(PSIDHeader))) == NULL) |
68 { | 112 { |
69 th_io_error(ctx, THERR_MALLOC, | 113 th_io_error(ctx, THERR_MALLOC, |
70 "Error PSID context struct.\n"); | 114 "Error PSID context struct.\n"); |
71 goto error; | 115 goto error; |
72 } | 116 } |
117 | |
118 hdrStart = thftell(ctx); | |
73 | 119 |
74 // Read PSID header in | 120 // Read PSID header in |
75 if (!thfread_str(ctx, (uint8_t *) psid->magic, PSID_MAGIC_LEN) || | 121 if (!thfread_str(ctx, (uint8_t *) psid->magic, PSID_MAGIC_LEN) || |
76 !thfread_be16(ctx, &psid->version) || | 122 !thfread_be16(ctx, &psid->version) || |
77 !thfread_be16(ctx, &psid->dataOffset) || | 123 !thfread_be16(ctx, &psid->dataOffset) || |
126 th_error_str(ctx->status)); | 172 th_error_str(ctx->status)); |
127 goto error; | 173 goto error; |
128 } | 174 } |
129 } | 175 } |
130 | 176 |
177 hdrEnd = thftell(ctx); | |
178 | |
131 // Initialize MD5-hash calculation | 179 // Initialize MD5-hash calculation |
132 th_md5_init(&state); | 180 th_md5_init(&state); |
133 | 181 |
134 // Process actual data | 182 if (newSLDB) |
135 psid->dataSize = 0; | 183 { |
136 first = TRUE; | 184 // New Songlengths.md5 style hash calculation: |
137 do | 185 // We just hash the whole file, so seek back to beginning .. |
138 { | 186 thfseek(ctx, hdrStart, SEEK_SET); |
139 read = thfread(data, sizeof(uint8_t), PSID_BUFFER_SIZE, ctx); | 187 |
140 psid->dataSize += read; | 188 if (!si_read_hash_data(ctx, psid, &state, FALSE)) |
141 | 189 goto error; |
142 // If load address is 0 in header and we have the first block, grab it | 190 |
143 if (first && psid->loadAddress == 0) | 191 psid->dataSize -= hdrEnd - hdrStart; |
144 { | 192 } |
145 if (read < 4) | 193 else |
146 { | 194 { |
147 th_io_error(ctx, THERR_FREAD, | 195 // "Old" Songlengths.txt style MD5 hash calculation |
148 "Error reading song data, unexpectedly small file.\n"); | 196 // We need to separately hash data etc. |
149 goto error; | 197 if (!si_read_hash_data(ctx, psid, &state, TRUE)) |
150 } | 198 goto error; |
151 | 199 |
152 // Grab the load address | 200 // Append header data to hash |
153 psid->loadAddress = TH_LE16_TO_NATIVE(*(uint16_t *) data); | 201 th_md5_append_le16(&state, psid->initAddress); |
154 | 202 th_md5_append_le16(&state, psid->playAddress); |
155 // .. do not include the load address to the hash | 203 th_md5_append_le16(&state, psid->nSongs); |
156 th_md5_append(&state, &data[2], read - 2); | 204 |
157 first = FALSE; | 205 // Append song speed data to hash |
158 } | 206 uint8_t tmp8 = psid->isRSID ? 60 : 0; |
159 else | 207 for (int index = 0; index < psid->nSongs && index < 32; index++) |
160 if (read > 0) | 208 { |
161 { | 209 if (psid->isRSID) |
162 // Append data "as is" | 210 tmp8 = 60; |
163 th_md5_append(&state, data, read); | 211 else |
164 } | 212 tmp8 = (psid->speed & (1 << index)) ? 60 : 0; |
165 } while (read > 0 && !thfeof(ctx)); | 213 |
166 | |
167 // Append header data to hash | |
168 th_md5_append_le16(&state, psid->initAddress); | |
169 th_md5_append_le16(&state, psid->playAddress); | |
170 th_md5_append_le16(&state, psid->nSongs); | |
171 | |
172 // Append song speed data to hash | |
173 tmp8 = psid->isRSID ? 60 : 0; | |
174 for (index = 0; index < psid->nSongs && index < 32; index++) | |
175 { | |
176 if (psid->isRSID) | |
177 tmp8 = 60; | |
178 else | |
179 tmp8 = (psid->speed & (1 << index)) ? 60 : 0; | |
180 | |
181 th_md5_append(&state, &tmp8, sizeof(tmp8)); | |
182 } | |
183 | |
184 // Rest of songs (more than 32) | |
185 for (index = 32; index < psid->nSongs; index++) | |
186 th_md5_append(&state, &tmp8, sizeof(tmp8)); | |
187 | |
188 // PSIDv2NG specific | |
189 if (psid->version >= 2) | |
190 { | |
191 // REFER TO SIDPLAY HEADERS FOR MORE INFORMATION | |
192 tmp8 = (psid->flags >> 2) & 3; | |
193 if (tmp8 == 2) | |
194 th_md5_append(&state, &tmp8, sizeof(tmp8)); | 214 th_md5_append(&state, &tmp8, sizeof(tmp8)); |
215 } | |
216 | |
217 // Rest of songs (more than 32) | |
218 for (int index = 32; index < psid->nSongs; index++) | |
219 th_md5_append(&state, &tmp8, sizeof(tmp8)); | |
220 | |
221 // PSIDv2NG specific | |
222 if (psid->version >= 2) | |
223 { | |
224 // REFER TO SIDPLAY HEADERS FOR MORE INFORMATION | |
225 tmp8 = (psid->flags >> 2) & 3; | |
226 if (tmp8 == 2) | |
227 th_md5_append(&state, &tmp8, sizeof(tmp8)); | |
228 } | |
195 } | 229 } |
196 | 230 |
197 // Calculate the hash | 231 // Calculate the hash |
198 th_md5_finish(&state, psid->hash); | 232 th_md5_finish(&state, psid->hash); |
199 ret = 0; | 233 ret = TRUE; |
200 | 234 |
201 error: | 235 error: |
202 // Free buffer | 236 // Free buffer |
203 th_free(data); | |
204 return ret; | 237 return ret; |
205 } | 238 } |
206 | 239 |
207 | 240 |
208 void si_free_sid_file(PSIDHeader *psid) | 241 void si_free_sid_file(PSIDHeader *psid) |