Mercurial > hg > dmlib
comparison tools/lib64gfx.c @ 1707:a0986cfd6f9d
More consistently use DMGrowBuf in the lib64gfx APIs, and implement
"backwards" RLE decoding and encoding (optionally regards input/output).
Not tested very much yet, there may be bugs.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Tue, 05 Jun 2018 21:58:10 +0300 |
parents | 1036b0dcccb5 |
children | 1f0fac3af8e3 |
comparison
equal
deleted
inserted
replaced
1706:311b14855a1e | 1707:a0986cfd6f9d |
---|---|
280 | 280 |
281 return DMERR_OK; | 281 return DMERR_OK; |
282 } | 282 } |
283 | 283 |
284 | 284 |
285 void dmGenericRLEAnalyze(const Uint8 *buf, const size_t len, DMCompParams *cfg) | 285 void dmGenericRLEAnalyze(const DMGrowBuf *buf, DMCompParams *cfg) |
286 { | 286 { |
287 #define DM_STAT_MAX 256 | 287 #define DM_STAT_MAX 256 |
288 size_t *stats; | 288 size_t *stats; |
289 | 289 |
290 // Allocate statistics counts buffer | 290 // Allocate statistics counts buffer |
291 if ((stats = dmMalloc0(DM_STAT_MAX * sizeof(size_t))) == NULL) | 291 if ((stats = dmMalloc0(DM_STAT_MAX * sizeof(size_t))) == NULL) |
292 return; | 292 return; |
293 | 293 |
294 // Get statistics on the data | 294 // Get statistics on the data |
295 for (size_t offs = 0; offs < len; offs++) | 295 for (size_t offs = 0; offs < buf->len; offs++) |
296 stats[buf[offs]]++; | 296 stats[buf->data[offs]]++; |
297 | 297 |
298 // According to compression type .. | 298 // According to compression type .. |
299 switch (cfg->type) | 299 switch (cfg->type) |
300 { | 300 { |
301 case DM_COMP_RLE_MARKER: | 301 case DM_COMP_RLE_MARKER: |
302 { | 302 { |
303 size_t selected = 0, | 303 size_t selected = 0, |
304 smallest = len; | 304 smallest = buf->len; |
305 | 305 |
306 // Find least used byte value | 306 // Find least used byte value |
307 for (size_t n = 0; n < DM_STAT_MAX; n++) | 307 for (size_t n = 0; n < DM_STAT_MAX; n++) |
308 { | 308 { |
309 if (stats[n] < smallest) | 309 if (stats[n] < smallest) |
325 | 325 |
326 dmFree(stats); | 326 dmFree(stats); |
327 } | 327 } |
328 | 328 |
329 | 329 |
330 int dmDecodeGenericRLE(DMGrowBuf *dst, const Uint8 *src, const Uint8 *srcEnd, const DMCompParams *cfg) | 330 static void dmSetupRLEBuffers(DMGrowBuf *dst, DMGrowBuf *src, const DMCompParams *cfg) |
331 { | |
332 if (cfg->flags & DM_RLE_BACKWARDS_INPUT) | |
333 { | |
334 src->offs = src->len - 1; | |
335 src->backwards = TRUE; | |
336 } | |
337 | |
338 if (cfg->flags & DM_RLE_BACKWARDS_OUTPUT) | |
339 { | |
340 dst->backwards = TRUE; | |
341 dst->offs = dst->size - 1; | |
342 } | |
343 } | |
344 | |
345 | |
346 int dmDecodeGenericRLE(DMGrowBuf *dst, const DMGrowBuf *psrc, const DMCompParams *cfg) | |
331 { | 347 { |
332 int res; | 348 int res; |
333 | 349 Uint8 tmp1, tmp2, tmp3, data; |
334 // Perform RLE decode | 350 DMGrowBuf src; |
335 while (src < srcEnd) | 351 |
336 { | 352 // As we need to modify the offs, etc. but not the data, |
337 Uint8 data = *src++; | 353 // we will just make a shallow copy of the DMGrowBuf struct |
338 int count = 1; | 354 dmGrowBufConstCopy(&src, psrc); |
355 dmSetupRLEBuffers(dst, &src, cfg); | |
356 | |
357 while (dmGrowBufGetU8(&src, &data)) | |
358 { | |
359 unsigned int count = 1; | |
339 | 360 |
340 if (cfg->type == DM_COMP_RLE_MARKER) | 361 if (cfg->type == DM_COMP_RLE_MARKER) |
341 { | 362 { |
342 // A simple marker byte RLE variant: [Marker] [count] [data] | 363 // A simple marker byte RLE variant: [Marker] [count] [data] |
343 if (data == cfg->rleMarkerB && (cfg->flags & DM_RLE_BYTE_RUNS)) | 364 if (data == cfg->rleMarkerB && (cfg->flags & DM_RLE_BYTE_RUNS)) |
344 { | 365 { |
345 if (srcEnd - src + 1 < 2) | 366 if (!dmGrowBufGetU8(&src, &tmp1) || |
367 !dmGrowBufGetU8(&src, &tmp2)) | |
346 { | 368 { |
347 res = DMERR_INVALID_DATA; | 369 res = DMERR_INVALID_DATA; |
348 goto err; | 370 goto out; |
349 } | 371 } |
350 | |
351 switch (cfg->flags & DM_RLE_ORDER_MASK) | 372 switch (cfg->flags & DM_RLE_ORDER_MASK) |
352 { | 373 { |
353 case DM_RLE_ORDER_1: | 374 case DM_RLE_ORDER_1: |
354 count = src[0]; | 375 count = tmp1; |
355 data = src[1]; | 376 data = tmp2; |
356 break; | 377 break; |
357 | 378 |
358 case DM_RLE_ORDER_2: | 379 case DM_RLE_ORDER_2: |
359 data = src[0]; | 380 data = tmp1; |
360 count = src[1]; | 381 count = tmp2; |
361 break; | 382 break; |
362 } | 383 } |
363 src += 2; | |
364 } | 384 } |
365 else | 385 else |
366 if (data == cfg->rleMarkerW && (cfg->flags & DM_RLE_WORD_RUNS)) | 386 if (data == cfg->rleMarkerW && (cfg->flags & DM_RLE_WORD_RUNS)) |
367 { | 387 { |
368 if (srcEnd - src + 1 < 3) | 388 if (!dmGrowBufGetU8(&src, &tmp1) || |
389 !dmGrowBufGetU8(&src, &tmp2) || | |
390 !dmGrowBufGetU8(&src, &tmp3)) | |
369 { | 391 { |
370 res = DMERR_INVALID_DATA; | 392 res = DMERR_INVALID_DATA; |
371 goto err; | 393 goto out; |
372 } | 394 } |
373 | |
374 switch (cfg->flags & DM_RLE_ORDER_MASK) | 395 switch (cfg->flags & DM_RLE_ORDER_MASK) |
375 { | 396 { |
376 case DM_RLE_ORDER_1: | 397 case DM_RLE_ORDER_1: |
377 count = (src[1] << 8) | src[0]; | 398 count = (tmp2 << 8) | tmp1; |
378 data = src[2]; | 399 data = tmp3; |
379 break; | 400 break; |
380 | 401 |
381 case DM_RLE_ORDER_2: | 402 case DM_RLE_ORDER_2: |
382 data = src[0]; | 403 data = tmp1; |
383 count = (src[2] << 8) | src[1]; | 404 count = (tmp3 << 8) | tmp2; |
384 break; | 405 break; |
385 } | 406 } |
386 src += 3; | |
387 } | 407 } |
388 } | 408 } |
389 else | 409 else |
390 if (cfg->type == DM_COMP_RLE_MASK) | 410 if (cfg->type == DM_COMP_RLE_MASK) |
391 { | 411 { |
392 // Mask marker RLE: usually high bit(s) of byte mark RLE sequence | 412 // Mask marker RLE: usually high bit(s) of byte mark RLE sequence |
393 // and the lower bits contain the count: [Mask + count] [data] | 413 // and the lower bits contain the count: [Mask + count] [data] |
394 if ((data & cfg->rleMarkerMask) == cfg->rleMarkerBits) | 414 if ((data & cfg->rleMarkerMask) == cfg->rleMarkerBits) |
395 { | 415 { |
396 if (srcEnd - src + 1 < 1) | 416 if (!dmGrowBufGetU8(&src, &tmp1)) |
397 { | 417 { |
398 res = DMERR_INVALID_DATA; | 418 res = DMERR_INVALID_DATA; |
399 goto err; | 419 goto out; |
400 } | 420 } |
401 | 421 |
402 count = data & cfg->rleCountMask; | 422 count = data & cfg->rleCountMask; |
403 data = *src++; | 423 data = tmp1; |
404 } | 424 } |
405 } | 425 } |
406 | 426 |
407 while (count--) | 427 while (count--) |
408 { | 428 { |
409 if (!dmGrowBufPutU8(dst, data)) | 429 if (!dmGrowBufPutU8(dst, data)) |
410 { | 430 { |
411 res = DMERR_MALLOC; | 431 res = DMERR_MALLOC; |
412 goto err; | 432 goto out; |
413 } | 433 } |
414 } | 434 } |
415 } | 435 } |
416 | 436 |
417 res = DMERR_OK; | 437 res = DMERR_OK; |
418 | 438 |
419 err: | 439 out: |
420 return res; | 440 return res; |
421 } | 441 } |
422 | 442 |
423 | 443 |
424 int dmDecodeGenericRLEAlloc(DMGrowBuf *dst, const Uint8 *src, const Uint8 *srcEnd, const DMCompParams *cfg) | 444 int dmDecodeGenericRLEAlloc(DMGrowBuf *dst, const DMGrowBuf *src, const DMCompParams *cfg) |
425 { | 445 { |
426 int res; | 446 int res; |
427 if ((res = dmGrowBufAlloc(dst, BUF_SIZE_INITIAL, BUF_SIZE_GROW)) != DMERR_OK) | 447 if ((res = dmGrowBufAlloc(dst, BUF_SIZE_INITIAL, BUF_SIZE_GROW)) != DMERR_OK) |
428 return res; | 448 return res; |
429 | 449 |
430 return dmDecodeGenericRLE(dst, src, srcEnd, cfg); | 450 return dmDecodeGenericRLE(dst, src, cfg); |
431 } | 451 } |
432 | 452 |
433 | 453 |
434 static BOOL dmEncodeGenericRLESequence(DMGrowBuf *dst, const Uint8 data, int count, const DMCompParams *cfg) | 454 static BOOL dmEncodeGenericRLESequence(DMGrowBuf *dst, const Uint8 data, unsigned int count, const DMCompParams *cfg) |
435 { | 455 { |
436 BOOL copyOnly = FALSE; | 456 BOOL copyOnly = FALSE; |
437 | 457 |
438 switch (cfg->type) | 458 switch (cfg->type) |
439 { | 459 { |
512 | 532 |
513 return TRUE; | 533 return TRUE; |
514 } | 534 } |
515 | 535 |
516 | 536 |
517 int dmEncodeGenericRLE(DMGrowBuf *dst, const Uint8 *src, const Uint8 *srcEnd, const DMCompParams *cfg) | 537 int dmEncodeGenericRLE(DMGrowBuf *dst, const DMGrowBuf *psrc, const DMCompParams *cfg) |
518 { | 538 { |
519 // Perform RLE encoding | 539 DMGrowBuf src; |
520 int count = 0, prev = -1; | 540 unsigned int count = 0; |
521 while (src < srcEnd) | 541 int prev = -1; |
522 { | 542 Uint8 data; |
523 Uint8 data = *src++; | 543 |
524 | 544 // As we need to modify the offs, etc. but not the data, |
545 // we will just make a shallow copy of the DMGrowBuf struct | |
546 dmGrowBufConstCopy(&src, psrc); | |
547 dmSetupRLEBuffers(dst, &src, cfg); | |
548 | |
549 while (dmGrowBufGetU8(&src, &data)) | |
550 { | |
525 // If new data byte is different, or we exceed the rleMaxCount | 551 // If new data byte is different, or we exceed the rleMaxCount |
526 // for the active runs mode(s) .. then encode the run. | 552 // for the active runs mode(s) .. then encode the run. |
527 if (data != prev || | 553 if (data != prev || |
528 ((cfg->flags & DM_RLE_WORD_RUNS) && count >= cfg->rleMaxCountW) || | 554 ((cfg->flags & DM_RLE_WORD_RUNS) && count >= cfg->rleMaxCountW) || |
529 (((cfg->flags & DM_RLE_RUNS_MASK) == DM_RLE_BYTE_RUNS) && count >= cfg->rleMaxCountB)) | 555 (((cfg->flags & DM_RLE_RUNS_MASK) == DM_RLE_BYTE_RUNS) && count >= cfg->rleMaxCountB)) |
544 | 570 |
545 return DMERR_OK; | 571 return DMERR_OK; |
546 | 572 |
547 err: | 573 err: |
548 return dmError(DMERR_MALLOC, | 574 return dmError(DMERR_MALLOC, |
549 "Could reallocate memory for RLE encoding buffer.\n"); | 575 "Could not reallocate memory for RLE encoding buffer.\n"); |
550 } | 576 } |
551 | 577 |
552 | 578 |
553 int dmEncodeGenericRLEAlloc(DMGrowBuf *dst, const Uint8 *src, const Uint8 *srcEnd, const DMCompParams *cfg) | 579 int dmEncodeGenericRLEAlloc(DMGrowBuf *dst, const DMGrowBuf *src, const DMCompParams *cfg) |
554 { | 580 { |
555 int res; | 581 int res; |
556 if ((res = dmGrowBufAlloc(dst, BUF_SIZE_INITIAL, BUF_SIZE_GROW)) != DMERR_OK) | 582 if ((res = dmGrowBufAlloc(dst, BUF_SIZE_INITIAL, BUF_SIZE_GROW)) != DMERR_OK) |
557 return res; | 583 return res; |
558 | 584 |
559 return dmEncodeGenericRLE(dst, src, srcEnd, cfg); | 585 return dmEncodeGenericRLE(dst, src, cfg); |
560 } | 586 } |
561 | 587 |
562 | 588 |
563 // Perform probing of the given data buffer, trying to determine | 589 // Perform probing of the given data buffer, trying to determine |
564 // if it contains a supported "C64" image format. Returns the | 590 // if it contains a supported "C64" image format. Returns the |
705 default: *blk = NULL; *blkname = NULL; break; | 731 default: *blk = NULL; *blkname = NULL; break; |
706 } | 732 } |
707 } | 733 } |
708 | 734 |
709 | 735 |
710 int dmC64DecodeGenericBMP(DMC64Image *img, const Uint8 *buf, | 736 int dmC64DecodeGenericBMP(DMC64Image *img, const DMGrowBuf *buf, const DMC64ImageFormat *fmt) |
711 const size_t len, const DMC64ImageFormat *fmt) | |
712 { | 737 { |
713 int res = DMERR_OK; | 738 int res = DMERR_OK; |
714 | 739 |
715 if (buf == NULL || img == NULL || fmt == NULL) | 740 if (buf == NULL || buf->data == NULL || img == NULL || fmt == NULL) |
716 return DMERR_NULLPTR; | 741 return DMERR_NULLPTR; |
717 | 742 |
718 // Clear the image structure, set basics | 743 // Clear the image structure, set basics |
719 img->type = fmt->type; | 744 img->type = fmt->type; |
720 img->width = fmt->width; | 745 img->width = fmt->width; |
749 "bank=%d, size=%d ($%04x) vs. allocated %d ($%04x)\n", | 774 "bank=%d, size=%d ($%04x) vs. allocated %d ($%04x)\n", |
750 i, op->type, op->subject, op->offs, op->offs, op->bank, size, size, op->size, op->size); | 775 i, op->type, op->subject, op->offs, op->offs, op->bank, size, size, op->size, op->size); |
751 } | 776 } |
752 | 777 |
753 // Is the operation inside the bounds? | 778 // Is the operation inside the bounds? |
754 if (op->offs + size > len + 1) | 779 if (op->offs + size > buf->len + 1) |
755 { | 780 { |
756 return dmError(DMERR_INVALID_DATA, | 781 return dmError(DMERR_INVALID_DATA, |
757 "Decode DATA out of bounds, op #%d type=%d, subj=%d, offs=%d ($%04x), " | 782 "Decode DATA out of bounds, op #%d type=%d, subj=%d, offs=%d ($%04x), " |
758 "bank=%d, size=%d ($%04x) @ %d ($%04x)\n", | 783 "bank=%d, size=%d ($%04x) @ %d ($%04x)\n", |
759 i, op->type, op->subject, op->offs, op->offs, op->bank, size, size, len, len); | 784 i, op->type, op->subject, op->offs, op->offs, op->bank, |
760 } | 785 size, size, buf->len, buf->len); |
761 | 786 } |
762 src = buf + op->offs; | 787 |
788 src = buf->data + op->offs; | |
763 | 789 |
764 // Perform operation | 790 // Perform operation |
765 switch (op->type) | 791 switch (op->type) |
766 { | 792 { |
767 case DO_COPY: | 793 case DO_COPY: |
779 if ((dmC64MemBlockAlloc(blk, size)) != DMERR_OK) | 805 if ((dmC64MemBlockAlloc(blk, size)) != DMERR_OK) |
780 { | 806 { |
781 return dmError(DMERR_MALLOC, | 807 return dmError(DMERR_MALLOC, |
782 "Could not allocate '%s' block! " | 808 "Could not allocate '%s' block! " |
783 "op #%d, offs=%d ($%04x), bank=%d, size=%d ($%04x) @ %d ($%04x)\n", | 809 "op #%d, offs=%d ($%04x), bank=%d, size=%d ($%04x) @ %d ($%04x)\n", |
784 blkname, i, op->offs, op->offs, op->bank, size, size, len, len); | 810 blkname, i, op->offs, op->offs, op->bank, size, size, buf->len, buf->len); |
785 } | 811 } |
786 switch (op->type) | 812 switch (op->type) |
787 { | 813 { |
788 case DO_COPY: | 814 case DO_COPY: |
789 memcpy(blk->data, src, size); | 815 memcpy(blk->data, src, size); |
830 | 856 |
831 default: | 857 default: |
832 return dmError(DMERR_INTERNAL, | 858 return dmError(DMERR_INTERNAL, |
833 "Unhandled subject %d in " | 859 "Unhandled subject %d in " |
834 "op #%d, offs=%d ($%04x), bank=%d, size=%d ($%04x) @ %d ($%04x)\n", | 860 "op #%d, offs=%d ($%04x), bank=%d, size=%d ($%04x) @ %d ($%04x)\n", |
835 op->subject, i, op->offs, op->offs, op->bank, size, size, len, len); | 861 op->subject, i, op->offs, op->offs, op->bank, size, size, buf->len, buf->len); |
836 } | 862 } |
837 break; | 863 break; |
838 | 864 |
839 case DO_CHAR_CFG: | 865 case DO_CHAR_CFG: |
840 switch (op->subject) | 866 switch (op->subject) |
852 | 878 |
853 default: | 879 default: |
854 return dmError(DMERR_INTERNAL, | 880 return dmError(DMERR_INTERNAL, |
855 "Unhandled DO_CHAR_CFG mode %d in ", | 881 "Unhandled DO_CHAR_CFG mode %d in ", |
856 "op #%d, bank=%d, size=%d ($%04x) @ %d ($%04x)\n", | 882 "op #%d, bank=%d, size=%d ($%04x) @ %d ($%04x)\n", |
857 op->subject, i, op->bank, size, size, len, len); | 883 op->subject, i, op->bank, size, size, buf->len, buf->len); |
858 } | 884 } |
859 break; | 885 break; |
860 | 886 |
861 case DO_DEC_FUNC: | 887 case DO_DEC_FUNC: |
862 if (op->decFunction == NULL) | 888 if (op->decFunction == NULL) |
863 { | 889 { |
864 return dmError(DMERR_INTERNAL, | 890 return dmError(DMERR_INTERNAL, |
865 "Decode op is a function, but function ptr is NULL: " | 891 "Decode op is a function, but function ptr is NULL: " |
866 "op #%d, offs=%d ($%04x), bank=%d, size=%d ($%04x) @ %d ($%04x)\n", | 892 "op #%d, offs=%d ($%04x), bank=%d, size=%d ($%04x) @ %d ($%04x)\n", |
867 i, op->offs, op->offs, op->bank, size, size, len, len); | 893 i, op->offs, op->offs, op->bank, size, size, buf->len, buf->len); |
868 } | 894 } |
869 if (!op->decFunction(img, op, buf, len, fmt)) | 895 if (!op->decFunction(img, op, buf, fmt)) |
870 { | 896 { |
871 return dmError(DMERR_INTERNAL, | 897 return dmError(DMERR_INTERNAL, |
872 "Decode op custom function failed: op #%d, " | 898 "Decode op custom function failed: op #%d, " |
873 "offs=%d ($%04x), bank=%d, size=%d ($%04x) @ %d ($%04x)\n", | 899 "offs=%d ($%04x), bank=%d, size=%d ($%04x) @ %d ($%04x)\n", |
874 i, op->offs, op->offs, op->bank, size, size, len, len); | 900 i, op->offs, op->offs, op->bank, size, size, buf->len, buf->len); |
875 } | 901 } |
876 break; | 902 break; |
877 } | 903 } |
878 } | 904 } |
879 | 905 |
933 if (!dmC64GetOpSize(op, fmt, &size)) | 959 if (!dmC64GetOpSize(op, fmt, &size)) |
934 { | 960 { |
935 res = dmError(DMERR_INVALID_DATA, | 961 res = dmError(DMERR_INVALID_DATA, |
936 "Encode op SIZE out of bounds, op #%d type=%d, offs=%d ($%04x), " | 962 "Encode op SIZE out of bounds, op #%d type=%d, offs=%d ($%04x), " |
937 "bank=%d, size=%d ($%04x) vs. allocated %d ($%04x)\n", | 963 "bank=%d, size=%d ($%04x) vs. allocated %d ($%04x)\n", |
938 i, op->type, op->offs, op->offs, op->bank, size, size, op->size, op->size); | 964 i, op->type, op->offs, op->offs, op->bank, size, size, buf->size, buf->size); |
939 goto err; | 965 goto err; |
940 } | 966 } |
941 | 967 |
942 // Do we need to reallocate some more space? | 968 // Do we need to reallocate some more space? |
943 chksize = buf->offs + op->offs + size; | 969 chksize = buf->offs + op->offs + size; |
946 res = dmError(DMERR_MALLOC, | 972 res = dmError(DMERR_MALLOC, |
947 "Could not re-allocate %d bytes of memory for C64 image encoding buffer.\n", | 973 "Could not re-allocate %d bytes of memory for C64 image encoding buffer.\n", |
948 chksize); | 974 chksize); |
949 goto err; | 975 goto err; |
950 } | 976 } |
951 | |
952 if (chksize > buf->len) | |
953 buf->len = chksize; | |
954 | 977 |
955 // Perform operation | 978 // Perform operation |
956 Uint8 *dst = buf->data + buf->offs + op->offs; | 979 Uint8 *dst = buf->data + buf->offs + op->offs; |
957 switch (op->type) | 980 switch (op->type) |
958 { | 981 { |
965 case DS_SCREEN_RAM: | 988 case DS_SCREEN_RAM: |
966 case DS_BITMAP_RAM: | 989 case DS_BITMAP_RAM: |
967 case DS_CHAR_DATA: | 990 case DS_CHAR_DATA: |
968 case DS_EXTRA_DATA: | 991 case DS_EXTRA_DATA: |
969 dmC64GetOpMemBlockAndName(img, op->subject, op->bank, &blk, &blkname); | 992 dmC64GetOpMemBlockAndName(img, op->subject, op->bank, &blk, &blkname); |
970 if (blk->data == NULL) | |
971 { | |
972 res = dmError(DMERR_NULLPTR, | |
973 "'%s' block is NULL in " | |
974 "op #%d, offs=%d ($%04x), bank=%d, size=%d ($%04x) @ %d ($%04x)\n", | |
975 blkname, i, op->offs, op->offs, op->bank, size, size, buf->len, buf->len); | |
976 goto err; | |
977 } | |
978 if (size > blk->size) | |
979 { | |
980 res = dmError(DMERR_INTERNAL, | |
981 "'%s' size mismatch %d <> %d in " | |
982 "op #%d, offs=%d ($%04x), bank=%d, size=%d ($%04x) @ %d ($%04x)\n", | |
983 blkname, op->size, blk->size, i, op->offs, op->offs, op->bank, size, size, buf->len, buf->len); | |
984 goto err; | |
985 } | |
986 switch (op->type) | 993 switch (op->type) |
987 { | 994 { |
988 case DO_COPY: | 995 case DO_COPY: |
996 if (blk->data == NULL) | |
997 { | |
998 res = dmError(DMERR_NULLPTR, | |
999 "'%s' block is NULL in " | |
1000 "op #%d, offs=%d ($%04x), bank=%d, size=%d ($%04x) @ %d ($%04x)\n", | |
1001 blkname, i, op->offs, op->offs, op->bank, size, size, buf->len, buf->len); | |
1002 goto err; | |
1003 } | |
1004 if (size > blk->size) | |
1005 { | |
1006 res = dmError(DMERR_INTERNAL, | |
1007 "'%s' size mismatch %d <> %d in " | |
1008 "op #%d, offs=%d ($%04x), bank=%d, size=%d ($%04x) @ %d ($%04x)\n", | |
1009 blkname, i, op->offs, op->offs, op->bank, size, size, buf->len, buf->len); | |
1010 goto err; | |
1011 } | |
989 memcpy(dst, blk->data, size); | 1012 memcpy(dst, blk->data, size); |
990 break; | 1013 break; |
991 | 1014 |
992 case DO_SET_MEM: | 1015 case DO_SET_MEM: |
993 // This operation makes no sense | 1016 // This operation makes no sense, so do nothing |
994 res = dmError(DMERR_INTERNAL, | 1017 break; |
995 "'%s' block DO_SET_MEM (which makes no sense) in " | |
996 "op #%d, offs=%d ($%04x), bank=%d, size=%d ($%04x) @ %d ($%04x)\n", | |
997 blkname, op->size, blk->size, i, op->offs, op->offs, op->bank, size, size, buf->len, buf->len); | |
998 goto err; | |
999 | 1018 |
1000 case DO_SET_OP: | 1019 case DO_SET_OP: |
1001 memset(dst, op->offs, size); | 1020 memset(dst, op->offs, size); |
1002 break; | 1021 break; |
1003 } | 1022 } |
1024 case DO_SET_MEM: | 1043 case DO_SET_MEM: |
1025 *dst = value; | 1044 *dst = value; |
1026 break; | 1045 break; |
1027 | 1046 |
1028 case DO_SET_OP: | 1047 case DO_SET_OP: |
1029 // This operation makes no sense | 1048 // Do nothing in this case |
1030 res = dmError(DMERR_INTERNAL, | 1049 break; |
1031 "'%s' block DO_SET_OP (which makes no sense) in " | |
1032 "op #%d, offs=%d ($%04x), bank=%d, size=%d ($%04x) @ %d ($%04x)\n", | |
1033 blkname, op->size, blk->size, i, op->offs, op->offs, op->bank, size, size, buf->len, buf->len); | |
1034 goto err; | |
1035 } | 1050 } |
1036 break; | 1051 break; |
1037 | 1052 |
1038 default: | 1053 default: |
1039 return dmError(DMERR_INTERNAL, | 1054 return dmError(DMERR_INTERNAL, |
1232 | 1247 |
1233 return res; | 1248 return res; |
1234 } | 1249 } |
1235 | 1250 |
1236 | 1251 |
1237 int dmC64DecodeBMP(DMC64Image **img, const Uint8 *buf, const size_t len, | 1252 int dmC64DecodeBMP(DMC64Image **img, const DMGrowBuf *buf, |
1238 const size_t probeOffs, const size_t loadOffs, | 1253 const size_t probeOffs, const size_t loadOffs, |
1239 const DMC64ImageFormat **fmt, const DMC64ImageFormat *forced) | 1254 const DMC64ImageFormat **fmt, const DMC64ImageFormat *forced) |
1240 { | 1255 { |
1241 if (img == NULL) | 1256 DMGrowBuf tmp; |
1257 | |
1258 if (img == NULL || buf == NULL) | |
1242 return DMERR_NULLPTR; | 1259 return DMERR_NULLPTR; |
1243 | 1260 |
1244 // Check for forced format | 1261 // Check for forced format |
1245 if (forced != NULL) | 1262 if (forced != NULL) |
1246 *fmt = forced; | 1263 *fmt = forced; |
1247 else | 1264 else |
1248 { | 1265 { |
1249 // Nope, perform a generic probe | 1266 // Nope, perform a generic probe |
1250 if (probeOffs >= len) | 1267 if (probeOffs >= buf->len) |
1251 return DMERR_OUT_OF_DATA; | 1268 return DMERR_OUT_OF_DATA; |
1252 | 1269 |
1253 if (dmC64ProbeBMP(buf + probeOffs, len - probeOffs, fmt) == DM_PROBE_SCORE_FALSE) | 1270 dmGrowBufCreateFromOffs(&tmp, buf, probeOffs); |
1271 if (dmC64ProbeBMP(tmp.data, tmp.len, fmt) == DM_PROBE_SCORE_FALSE) | |
1254 return DMERR_NOT_SUPPORTED; | 1272 return DMERR_NOT_SUPPORTED; |
1255 } | 1273 } |
1256 | 1274 |
1257 if (loadOffs >= len) | 1275 if (loadOffs >= tmp.len) |
1258 return DMERR_INVALID_ARGS; | 1276 return DMERR_INVALID_ARGS; |
1259 | 1277 |
1260 if (*fmt == NULL) | 1278 if (*fmt == NULL) |
1261 return DMERR_NOT_SUPPORTED; | 1279 return DMERR_NOT_SUPPORTED; |
1262 | 1280 |
1281 // Format supports only reading? | |
1263 if (((*fmt)->flags & DM_FMT_RD) == 0) | 1282 if (((*fmt)->flags & DM_FMT_RD) == 0) |
1264 return DMERR_NOT_SUPPORTED; | 1283 return DMERR_NOT_SUPPORTED; |
1265 | 1284 |
1266 // Allocate memory | 1285 // Allocate memory |
1267 if ((*img = dmC64ImageAlloc(*fmt)) == NULL) | 1286 if ((*img = dmC64ImageAlloc(*fmt)) == NULL) |
1268 return DMERR_MALLOC; | 1287 return DMERR_MALLOC; |
1269 | 1288 |
1289 dmGrowBufCreateFromOffs(&tmp, buf, loadOffs); | |
1290 | |
1270 // Decode the bitmap to memory layout | 1291 // Decode the bitmap to memory layout |
1271 if ((*fmt)->decode != NULL) | 1292 if ((*fmt)->decode != NULL) |
1272 return (*fmt)->decode(*img, buf + loadOffs, len - loadOffs, *fmt); | 1293 return (*fmt)->decode(*img, &tmp, *fmt); |
1273 else | 1294 else |
1274 return dmC64DecodeGenericBMP(*img, buf + loadOffs, len - loadOffs, *fmt); | 1295 return dmC64DecodeGenericBMP(*img, &tmp, *fmt); |
1275 } | 1296 } |
1276 | 1297 |
1277 | 1298 |
1278 // Convert a generic bitmap image to DMC64Image | 1299 // Convert a generic bitmap image to DMC64Image |
1279 int dmC64ConvertGenericImage2BMP(DMC64Image *dst, const DMImage *src, const DMC64ImageFormat *fmt) | 1300 int dmC64ConvertGenericImage2BMP(DMC64Image *dst, const DMImage *src, const DMC64ImageFormat *fmt) |