Mercurial > hg > sidinfo
comparison sidlib.c @ 239:82540f819194
Clean up error handling.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Sat, 04 Jan 2020 17:27:29 +0200 |
parents | d28f3d537284 |
children | c9b57c8fd058 |
comparison
equal
deleted
inserted
replaced
238:2ed665b74043 | 239:82540f819194 |
---|---|
12 { | 12 { |
13 char *tmp = th_malloc(len + 1); | 13 char *tmp = th_malloc(len + 1); |
14 if (tmp == NULL) | 14 if (tmp == NULL) |
15 { | 15 { |
16 th_io_error(ctx, THERR_MALLOC, | 16 th_io_error(ctx, THERR_MALLOC, |
17 "Could not allocate %" PRIu_SIZE_T " bytes for a string.\n", | 17 "Could not allocate %" PRIu_SIZE_T " bytes for a string.", |
18 len); | 18 len); |
19 goto err; | 19 goto err; |
20 } | 20 } |
21 | 21 |
22 if (!thfread_str(ctx, tmp, len)) | 22 if (!thfread_str(ctx, tmp, len)) |
23 { | 23 { |
24 th_io_error(ctx, THERR_FREAD, | 24 th_io_error(ctx, THERR_FREAD, |
25 "Could not read %" PRIu_SIZE_T " bytes from file.\n", | 25 "Could not read %" PRIu_SIZE_T " bytes from file.", |
26 len); | 26 len); |
27 goto err; | 27 goto err; |
28 } | 28 } |
29 | 29 |
30 tmp[len] = 0; | 30 tmp[len] = 0; |
35 th_free(tmp); | 35 th_free(tmp); |
36 return FALSE; | 36 return FALSE; |
37 } | 37 } |
38 | 38 |
39 | 39 |
40 static BOOL sidlib_read_hash_data(th_ioctx *ctx, SIDLibPSIDHeader *psid, | 40 static int sidlib_read_hash_data(th_ioctx *ctx, SIDLibPSIDHeader *psid, |
41 th_md5state_t *state, const BOOL newSLDB) | 41 th_md5state_t *state, const BOOL newSLDB) |
42 { | 42 { |
43 int ret = THERR_OK; | |
43 uint8_t *data = NULL; | 44 uint8_t *data = NULL; |
44 BOOL ret = FALSE, first = TRUE; | 45 BOOL first = TRUE; |
45 size_t read; | 46 size_t read; |
46 | 47 |
47 if ((data = (uint8_t *) th_malloc(SIDLIB_BUFFER_SIZE)) == NULL) | 48 if ((data = (uint8_t *) th_malloc(SIDLIB_BUFFER_SIZE)) == NULL) |
48 { | 49 { |
49 th_io_error(ctx, THERR_MALLOC, | 50 ret = th_io_error(ctx, THERR_MALLOC, |
50 "Error allocating temporary data buffer of %d bytes.\n", | 51 "Error allocating temporary data buffer of %d bytes.", |
51 SIDLIB_BUFFER_SIZE); | 52 SIDLIB_BUFFER_SIZE); |
52 goto error; | 53 goto exit; |
53 } | 54 } |
54 | 55 |
55 psid->dataSize = 0; | 56 psid->dataSize = 0; |
56 do | 57 do |
57 { | 58 { |
61 // If load address is 0 in header and we have the first block, grab it | 62 // If load address is 0 in header and we have the first block, grab it |
62 if (first && psid->loadAddress == 0) | 63 if (first && psid->loadAddress == 0) |
63 { | 64 { |
64 if (read < 4) | 65 if (read < 4) |
65 { | 66 { |
66 th_io_error(ctx, THERR_FREAD, | 67 ret = th_io_error(ctx, THERR_FREAD, |
67 "Error reading song data, unexpectedly small file.\n"); | 68 "Error reading song data, unexpectedly small file."); |
68 goto error; | 69 goto exit; |
69 } | 70 } |
70 | 71 |
71 // Grab the load address | 72 // Grab the load address |
72 psid->loadAddress = TH_LE16_TO_NATIVE(*(uint16_t *) data); | 73 psid->loadAddress = TH_LE16_TO_NATIVE(*(uint16_t *) data); |
73 | 74 |
85 // Append data "as is" | 86 // Append data "as is" |
86 th_md5_append(state, data, read); | 87 th_md5_append(state, data, read); |
87 } | 88 } |
88 } while (read > 0 && !thfeof(ctx)); | 89 } while (read > 0 && !thfeof(ctx)); |
89 | 90 |
90 ret = TRUE; | 91 exit: |
91 | |
92 error: | |
93 th_free(data); | 92 th_free(data); |
94 return ret; | 93 return ret; |
95 } | 94 } |
96 | 95 |
97 | 96 |
98 BOOL sidlib_read_sid_file(th_ioctx *ctx, SIDLibPSIDHeader *psid, const BOOL newSLDB) | 97 int sidlib_read_sid_file(th_ioctx *ctx, SIDLibPSIDHeader *psid, const BOOL newSLDB) |
99 { | 98 { |
99 int ret = THERR_OK; | |
100 th_md5state_t state; | 100 th_md5state_t state; |
101 BOOL ret = FALSE; | |
102 off_t hdrStart, hdrEnd; | 101 off_t hdrStart, hdrEnd; |
103 | 102 |
104 hdrStart = thftell(ctx); | 103 hdrStart = thftell(ctx); |
105 | 104 |
106 // Read PSID header in | 105 // Read PSID header in |
112 !thfread_be16(ctx, &psid->playAddress) || | 111 !thfread_be16(ctx, &psid->playAddress) || |
113 !thfread_be16(ctx, &psid->nSongs) || | 112 !thfread_be16(ctx, &psid->nSongs) || |
114 !thfread_be16(ctx, &psid->startSong) || | 113 !thfread_be16(ctx, &psid->startSong) || |
115 !thfread_be32(ctx, &psid->speed)) | 114 !thfread_be32(ctx, &psid->speed)) |
116 { | 115 { |
117 th_io_error(ctx, ctx->status, | 116 ret = th_io_error(ctx, ctx->status, |
118 "Could not read PSID/RSID header from '%s': %s.\n", | 117 "Could not read PSID/RSID header from '%s': %s.", |
119 ctx->filename, th_error_str(ctx->status)); | 118 ctx->filename, th_error_str(ctx->status)); |
120 goto error; | 119 goto exit; |
121 } | 120 } |
122 | 121 |
123 psid->magic[SIDLIB_PSID_MAGIC_LEN] = 0; | 122 psid->magic[SIDLIB_PSID_MAGIC_LEN] = 0; |
124 | 123 |
125 if ((psid->magic[0] != 'R' && psid->magic[0] != 'P') || | 124 if ((psid->magic[0] != 'R' && psid->magic[0] != 'P') || |
126 psid->magic[1] != 'S' || psid->magic[2] != 'I' || psid->magic[3] != 'D' || | 125 psid->magic[1] != 'S' || psid->magic[2] != 'I' || psid->magic[3] != 'D' || |
127 psid->version < 1 || psid->version > 4) | 126 psid->version < 1 || psid->version > 4) |
128 { | 127 { |
129 th_io_error(ctx, THERR_NOT_SUPPORTED, | 128 ret = th_io_error(ctx, THERR_NOT_SUPPORTED, |
130 "Not a supported PSID or RSID file: %s\n", | 129 "Not a supported PSID or RSID file: '%s'", |
131 ctx->filename); | 130 ctx->filename); |
132 goto error; | 131 goto exit; |
133 } | 132 } |
134 | 133 |
135 psid->isRSID = psid->magic[0] == 'R'; | 134 psid->isRSID = psid->magic[0] == 'R'; |
136 | 135 |
137 if (!sidlib_fread_str(ctx, &psid->sidName, SIDLIB_PSID_STR_LEN) || | 136 if (!sidlib_fread_str(ctx, &psid->sidName, SIDLIB_PSID_STR_LEN) || |
138 !sidlib_fread_str(ctx, &psid->sidAuthor, SIDLIB_PSID_STR_LEN) || | 137 !sidlib_fread_str(ctx, &psid->sidAuthor, SIDLIB_PSID_STR_LEN) || |
139 !sidlib_fread_str(ctx, &psid->sidCopyright, SIDLIB_PSID_STR_LEN)) | 138 !sidlib_fread_str(ctx, &psid->sidCopyright, SIDLIB_PSID_STR_LEN)) |
140 { | 139 { |
141 th_io_error(ctx, ctx->status, | 140 ret = th_io_error(ctx, ctx->status, |
142 "Error reading SID file header from '%s': %s.\n", | 141 "Error reading SID file header from '%s': %s.", |
143 ctx->filename, th_error_str(ctx->status)); | 142 ctx->filename, th_error_str(ctx->status)); |
144 goto error; | 143 goto exit; |
145 } | 144 } |
146 | 145 |
147 // Check if we need to load PSIDv2NG header ... | 146 // Check if we need to load PSIDv2NG header ... |
148 if (psid->version >= 2) | 147 if (psid->version >= 2) |
149 { | 148 { |
152 !thfread_u8(ctx, &psid->startPage) || | 151 !thfread_u8(ctx, &psid->startPage) || |
153 !thfread_u8(ctx, &psid->pageLength) || | 152 !thfread_u8(ctx, &psid->pageLength) || |
154 !thfread_u8(ctx, &psid->sid2Addr) || | 153 !thfread_u8(ctx, &psid->sid2Addr) || |
155 !thfread_u8(ctx, &psid->sid3Addr)) | 154 !thfread_u8(ctx, &psid->sid3Addr)) |
156 { | 155 { |
157 th_io_error(ctx, ctx->status, | 156 ret = th_io_error(ctx, ctx->status, |
158 "Error reading PSID/RSID v2+ extra header data from '%s': %s.\n", | 157 "Error reading PSID/RSID v2+ extra header data from '%s': %s.", |
159 ctx->filename, th_error_str(ctx->status)); | 158 ctx->filename, th_error_str(ctx->status)); |
160 goto error; | 159 goto exit; |
161 } | 160 } |
162 } | 161 } |
163 | 162 |
164 hdrEnd = thftell(ctx); | 163 hdrEnd = thftell(ctx); |
165 | 164 |
170 { | 169 { |
171 // New Songlengths.md5 style hash calculation: | 170 // New Songlengths.md5 style hash calculation: |
172 // We just hash the whole file, so seek back to beginning .. | 171 // We just hash the whole file, so seek back to beginning .. |
173 thfseek(ctx, hdrStart, SEEK_SET); | 172 thfseek(ctx, hdrStart, SEEK_SET); |
174 | 173 |
175 if (!sidlib_read_hash_data(ctx, psid, &state, FALSE)) | 174 if ((ret = sidlib_read_hash_data(ctx, psid, &state, FALSE)) != THERR_OK) |
176 goto error; | 175 goto exit; |
177 | 176 |
178 psid->dataSize -= hdrEnd - hdrStart; | 177 psid->dataSize -= hdrEnd - hdrStart; |
179 } | 178 } |
180 else | 179 else |
181 { | 180 { |
182 // "Old" Songlengths.txt style MD5 hash calculation | 181 // "Old" Songlengths.txt style MD5 hash calculation |
183 // We need to separately hash data etc. | 182 // We need to separately hash data etc. |
184 if (!sidlib_read_hash_data(ctx, psid, &state, TRUE)) | 183 if ((ret = sidlib_read_hash_data(ctx, psid, &state, TRUE)) != THERR_OK) |
185 goto error; | 184 goto exit; |
186 | 185 |
187 // Append header data to hash | 186 // Append header data to hash |
188 th_md5_append_le16(&state, psid->initAddress); | 187 th_md5_append_le16(&state, psid->initAddress); |
189 th_md5_append_le16(&state, psid->playAddress); | 188 th_md5_append_le16(&state, psid->playAddress); |
190 th_md5_append_le16(&state, psid->nSongs); | 189 th_md5_append_le16(&state, psid->nSongs); |
215 } | 214 } |
216 } | 215 } |
217 | 216 |
218 // Calculate the hash | 217 // Calculate the hash |
219 th_md5_finish(&state, psid->hash); | 218 th_md5_finish(&state, psid->hash); |
220 ret = TRUE; | 219 |
221 | 220 exit: |
222 error: | |
223 // Free buffer | |
224 return ret; | 221 return ret; |
225 } | 222 } |
226 | 223 |
227 | 224 |
228 BOOL sidlib_read_sid_file_alloc(th_ioctx *ctx, SIDLibPSIDHeader **ppsid, const BOOL newSLDB) | 225 int sidlib_read_sid_file_alloc(th_ioctx *ctx, SIDLibPSIDHeader **ppsid, const BOOL newSLDB) |
229 { | 226 { |
230 if ((*ppsid = th_malloc0(sizeof(SIDLibPSIDHeader))) == NULL) | 227 if ((*ppsid = th_malloc0(sizeof(SIDLibPSIDHeader))) == NULL) |
231 { | 228 return THERR_MALLOC; |
232 th_io_error(ctx, THERR_MALLOC, | |
233 "Error allocating PSID context struct.\n"); | |
234 return FALSE; | |
235 } | |
236 | 229 |
237 (*ppsid)->allocated = TRUE; | 230 (*ppsid)->allocated = TRUE; |
238 | 231 |
239 return sidlib_read_sid_file(ctx, *ppsid, newSLDB); | 232 return sidlib_read_sid_file(ctx, *ppsid, newSLDB); |
240 } | 233 } |
336 } | 329 } |
337 | 330 |
338 | 331 |
339 // Parse one SLDB definition line, return SLDB node | 332 // Parse one SLDB definition line, return SLDB node |
340 // | 333 // |
341 SIDLibSLDBNode *sidlib_sldb_parse_entry(th_ioctx *ctx, const char *line) | 334 static int sidlib_sldb_parse_entry(th_ioctx *ctx, SIDLibSLDBNode **pnode, const char *line) |
342 { | 335 { |
343 SIDLibSLDBNode *node = NULL; | 336 int ret = THERR_OK; |
337 SIDLibSLDBNode *node; | |
344 size_t pos, tmpLen, savePos; | 338 size_t pos, tmpLen, savePos; |
345 BOOL isOK; | 339 BOOL isOK; |
346 int i; | 340 int i; |
347 | 341 |
348 // Allocate new node | 342 // Allocate new node |
349 node = (SIDLibSLDBNode *) th_malloc0(sizeof(SIDLibSLDBNode)); | 343 if ((*pnode = node = (SIDLibSLDBNode *) th_malloc0(sizeof(SIDLibSLDBNode))) == NULL) |
350 if (node == NULL) | 344 { |
351 { | 345 ret = th_io_error(ctx, THERR_MALLOC, |
352 th_io_error(ctx, THERR_MALLOC, | 346 "Error allocating new SLDB node for SongLengthDB file '%s' line #%d:\n%s", |
353 "Error allocating new node.\n"); | 347 ctx->filename, ctx->line, line); |
354 return NULL; | 348 goto exit; |
355 } | 349 } |
356 | 350 |
357 // Get hash value | 351 // Get hash value |
358 for (pos = 0, i = 0; i < TH_MD5HASH_LENGTH; i++, pos += 2) | 352 for (pos = 0, i = 0; i < TH_MD5HASH_LENGTH; i++, pos += 2) |
359 { | 353 { |
364 | 358 |
365 // Get playtimes | 359 // Get playtimes |
366 th_findnext(line, &pos); | 360 th_findnext(line, &pos); |
367 if (line[pos] != '=') | 361 if (line[pos] != '=') |
368 { | 362 { |
369 th_io_error(ctx, THERR_INVALID_DATA, | 363 ret = th_io_error(ctx, THERR_INVALID_DATA, |
370 "'=' expected on column #%d.\n", pos); | 364 "'=' expected on column %d of SongLengthDB file '%s' line #%d:\n%s", |
371 goto error; | 365 pos, ctx->filename, ctx->line, line); |
366 goto exit; | |
372 } | 367 } |
373 | 368 |
374 // First playtime is after '=' | 369 // First playtime is after '=' |
375 savePos = ++pos; | 370 savePos = ++pos; |
376 tmpLen = strlen(line); | 371 tmpLen = strlen(line); |
387 isOK = FALSE; | 382 isOK = FALSE; |
388 } | 383 } |
389 | 384 |
390 // Allocate memory for lengths | 385 // Allocate memory for lengths |
391 if (node->nlengths == 0) | 386 if (node->nlengths == 0) |
392 goto error; | 387 { |
393 | 388 ret = THERR_OK; |
394 node->lengths = (int *) th_calloc(node->nlengths, sizeof(int)); | 389 goto exit; |
395 if (node->lengths == NULL) | 390 } |
396 { | 391 |
397 th_io_error(ctx, THERR_MALLOC, | 392 if ((node->lengths = (int *) th_calloc(node->nlengths, sizeof(int))) == NULL) |
398 "Could not allocate memory for node.\n"); | 393 { |
399 goto error; | 394 ret = th_io_error(ctx, THERR_MALLOC, |
395 "Error allocating SLDB length data for SongLengthDB file '%s' line #%d:\n%s", | |
396 ctx->filename, ctx->line, line); | |
397 goto exit; | |
400 } | 398 } |
401 | 399 |
402 // Read lengths in | 400 // Read lengths in |
403 for (i = 0, pos = savePos, isOK = TRUE; | 401 for (i = 0, pos = savePos, isOK = TRUE; |
404 pos < tmpLen && i < node->nlengths && isOK; i++) | 402 pos < tmpLen && i < node->nlengths && isOK; i++) |
405 { | 403 { |
406 int l; | 404 int l; |
407 th_findnext(line, &pos); | 405 th_findnext(line, &pos); |
408 | 406 |
409 l = sidlib_sldb_gettime(line, &pos); | 407 l = sidlib_sldb_gettime(line, &pos); |
408 | |
410 if (l >= 0) | 409 if (l >= 0) |
411 node->lengths[i] = l; | 410 node->lengths[i] = l; |
412 else | 411 else |
413 isOK = FALSE; | 412 isOK = FALSE; |
414 } | 413 } |
415 | 414 |
416 return node; | 415 return ret; |
417 | 416 |
418 error: | 417 exit: |
419 sidlib_sldb_node_free(node); | 418 sidlib_sldb_node_free(node); |
420 return NULL; | 419 return ret; |
421 } | 420 } |
422 | 421 |
423 | 422 |
424 int sidlib_sldb_new(SIDLibSLDB **pdbh) | 423 int sidlib_sldb_new(SIDLibSLDB **pdbh) |
425 { | 424 { |
433 | 432 |
434 // Read SLDB database to memory | 433 // Read SLDB database to memory |
435 // | 434 // |
436 int sidlib_sldb_read(th_ioctx *ctx, SIDLibSLDB *dbh) | 435 int sidlib_sldb_read(th_ioctx *ctx, SIDLibSLDB *dbh) |
437 { | 436 { |
437 int ret = THERR_OK; | |
438 char *line = NULL; | 438 char *line = NULL; |
439 | 439 |
440 if ((line = th_malloc(SIDLIB_BUFFER_SIZE)) == NULL) | 440 if ((line = th_malloc(SIDLIB_BUFFER_SIZE)) == NULL) |
441 { | 441 { |
442 return th_io_error(ctx, THERR_MALLOC, | 442 ret = th_io_error(ctx, THERR_MALLOC, |
443 "Error allocating temporary data buffer of %d bytes.\n", | 443 "Error allocating temporary data buffer of %d bytes.", |
444 SIDLIB_BUFFER_SIZE); | 444 SIDLIB_BUFFER_SIZE); |
445 goto exit; | |
445 } | 446 } |
446 | 447 |
447 while (thfgets(line, SIDLIB_BUFFER_SIZE, ctx) != NULL) | 448 while (thfgets(line, SIDLIB_BUFFER_SIZE, ctx) != NULL) |
448 { | 449 { |
449 SIDLibSLDBNode *tmnode; | 450 SIDLibSLDBNode *tmnode; |
459 int hashLen; | 460 int hashLen; |
460 for (hashLen = 0; line[pos] && th_isxdigit(line[pos]); hashLen++, pos++); | 461 for (hashLen = 0; line[pos] && th_isxdigit(line[pos]); hashLen++, pos++); |
461 | 462 |
462 if (hashLen != TH_MD5HASH_LENGTH_CH) | 463 if (hashLen != TH_MD5HASH_LENGTH_CH) |
463 { | 464 { |
464 th_io_error(ctx, THERR_INVALID_DATA, | 465 ret = th_io_error(ctx, THERR_INVALID_DATA, |
465 "Invalid MD5-hash in SongLengthDB file '%s' line #%d:\n%s\n", | 466 "Invalid MD5-hash in SongLengthDB file '%s' line #%d:\n%s", |
466 ctx->filename, ctx->line, line); | 467 ctx->filename, ctx->line, line); |
468 goto exit; | |
467 } | 469 } |
468 else | 470 else |
469 { | 471 { |
470 // Parse and add node to db | 472 // Parse and add node to db |
471 if ((tmnode = sidlib_sldb_parse_entry(ctx, line)) != NULL) | 473 if ((ret = sidlib_sldb_parse_entry(ctx, &tmnode, line)) != THERR_OK) |
472 { | 474 goto exit; |
473 th_llist_append_node((th_llist_t **) &dbh->nodes, (th_llist_t *) tmnode); | 475 |
474 } | 476 th_llist_append_node((th_llist_t **) &dbh->nodes, (th_llist_t *) tmnode); |
475 else | |
476 { | |
477 th_io_error(ctx, THERR_INVALID_DATA, | |
478 "Invalid entry in SongLengthDB file '%s' line #%d:\n%s\n", | |
479 ctx->filename, ctx->line, line); | |
480 } | |
481 } | 477 } |
482 } | 478 } |
483 else | 479 else |
484 if (line[pos] != ';' && line[pos] != '[' && line[pos] != 0) | 480 if (line[pos] != ';' && line[pos] != '[' && line[pos] != 0) |
485 { | 481 { |
486 th_io_error(ctx, THERR_INVALID_DATA, | 482 ret = th_io_error(ctx, THERR_INVALID_DATA, |
487 "Invalid line in SongLengthDB file '%s' line #%d:\n%s\n", | 483 "Invalid line in SongLengthDB file '%s' line #%d:\n%s", |
488 ctx->filename, ctx->line, line); | 484 ctx->filename, ctx->line, line); |
489 } | 485 goto exit; |
490 } | 486 } |
491 | 487 } |
488 | |
489 exit: | |
492 th_free(line); | 490 th_free(line); |
493 return THERR_OK; | 491 return ret; |
494 } | 492 } |
495 | 493 |
496 | 494 |
497 // Compare two given MD5-hashes. | 495 // Compare two given MD5-hashes. |
498 // Return: 0 if equal | 496 // Return: 0 if equal |