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)