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