MOTO_MAP_pack() : implements the optimized packing algorithm
This commit is contained in:
parent
245b251a43
commit
830ba85329
@ -5361,16 +5361,24 @@ void Load_MOTO(T_IO_Context * context)
|
||||
}
|
||||
|
||||
/**
|
||||
* Pack a stream of byte in the format used by Thomson MO/TO MAP files.
|
||||
*
|
||||
* - 00 cc xx yy .. : encodes a "copy run" (cc = bytes to copy)
|
||||
* - cc xx : encodes a "repeat run" (cc > 0 : count)
|
||||
*/
|
||||
#define MOTO_MAP_NOPACKING
|
||||
//#define MOTO_MAP_NOPACKING
|
||||
static unsigned int MOTO_MAP_pack(byte * packed, const byte * unpacked, unsigned int unpacked_len)
|
||||
{
|
||||
unsigned int src;
|
||||
unsigned int dst = 0;
|
||||
unsigned int repeat;
|
||||
unsigned int count;
|
||||
#ifndef MOTO_MAP_NOPACKING
|
||||
unsigned int repeat;
|
||||
unsigned int i;
|
||||
word * counts;
|
||||
#endif
|
||||
|
||||
GFX2_Log(GFX2_DEBUG, "MOTO_MAP_pack(%p, %p, %u)\n", packed, unpacked, unpacked_len);
|
||||
if (unpacked_len == 0)
|
||||
return 0;
|
||||
if (unpacked_len == 1)
|
||||
@ -5398,9 +5406,12 @@ static unsigned int MOTO_MAP_pack(byte * packed, const byte * unpacked, unsigned
|
||||
src += count;
|
||||
return dst;
|
||||
#else
|
||||
counts = malloc(sizeof(word) * (unpacked_len + 1));
|
||||
i = 0;
|
||||
repeat = (unpacked[0] == unpacked[1]);
|
||||
count = 2;
|
||||
src = 2;
|
||||
// 1st step : count lenght of the Copy runs and Repeat runs
|
||||
while (src < unpacked_len)
|
||||
{
|
||||
if (repeat)
|
||||
@ -5409,9 +5420,8 @@ static unsigned int MOTO_MAP_pack(byte * packed, const byte * unpacked, unsigned
|
||||
count++;
|
||||
else
|
||||
{
|
||||
// flush run
|
||||
packed[dst++] = count;
|
||||
packed[dst++] = unpacked[src-1];
|
||||
// flush the repeat run
|
||||
counts[i++] = count | 0x8000; // 0x8000 is the marker for repeat runs
|
||||
count = 1;
|
||||
repeat = 0;
|
||||
}
|
||||
@ -5427,21 +5437,158 @@ static unsigned int MOTO_MAP_pack(byte * packed, const byte * unpacked, unsigned
|
||||
}
|
||||
else
|
||||
{
|
||||
// verifier le nombre de repetitions > 3
|
||||
if (unpacked[src] != unpacked[src+1] || unpacked[src] != unpacked[src+2])
|
||||
{
|
||||
src += 2;
|
||||
count += 3;
|
||||
}
|
||||
// flush the copy run
|
||||
counts[i++] = (count-1) | (count == 2 ? 0x8000 : 0); // mark copy run of 1 as repeat of 1
|
||||
count = 2;
|
||||
repeat = 1;
|
||||
}
|
||||
}
|
||||
src++;
|
||||
}
|
||||
// commit
|
||||
// flush the last run
|
||||
counts[i++] = ((repeat || count == 1) ? 0x8000 : 0) | count;
|
||||
counts[i++] = 0; // end marker
|
||||
// check consistency of counts
|
||||
count = 0;
|
||||
for (i = 0; counts[i] != 0; i++)
|
||||
count += (counts[i] & ~0x8000);
|
||||
if (count != unpacked_len)
|
||||
GFX2_Log(GFX2_ERROR, "*** encoding error in MOTO_MAP_pack() *** count=%u unpacked_len=%u\n",
|
||||
count, unpacked_len);
|
||||
// output optimized packed stream
|
||||
// repeat run are encoded cc xx
|
||||
// copy run are encoded 00 cc xx xx xx xx
|
||||
i = 0;
|
||||
src = 0;
|
||||
while (counts[i] != 0)
|
||||
{
|
||||
while (counts[i] & 0x8000) // repeat run
|
||||
{
|
||||
count = counts[i] & ~0x8000;
|
||||
GFX2_Log(GFX2_DEBUG, "MOTO_MAP_pack() %4u %4u repeat %u times %02x\n", src, i, count, unpacked[src]);
|
||||
while(count > 255)
|
||||
{
|
||||
packed[dst++] = 255;
|
||||
packed[dst++] = unpacked[src];
|
||||
count -= 255;
|
||||
src += 255;
|
||||
}
|
||||
packed[dst++] = count;
|
||||
packed[dst++] = unpacked[src];
|
||||
src += count;
|
||||
i++;
|
||||
}
|
||||
while (counts[i] != 0 && !(counts[i] & 0x8000)) // copy run
|
||||
{
|
||||
// calculate the "savings" of repeat runs between 2 copy run
|
||||
int savings = 0;
|
||||
unsigned int j;
|
||||
GFX2_Log(GFX2_DEBUG, "MOTO_MAP_pack() %4u %4u copy %u bytes\n", src, i, counts[i]);
|
||||
for (j = i + 1; counts[j] & 0x8000; j++) // check repeat runs until the next copy run
|
||||
{
|
||||
count = counts[j] & ~0x8000;
|
||||
if (savings < 0 && (savings + (int)count - 2) > 0)
|
||||
break;
|
||||
savings += count - 2; // a repeat run outputs 2 bytes for count bytes of input
|
||||
}
|
||||
count = counts[i];
|
||||
GFX2_Log(GFX2_DEBUG, " savings=%d i=%u j=%u (counts[j]=0x%04x)\n", savings, i, j, counts[j]);
|
||||
if (savings < 2 && (j > i + 1))
|
||||
{
|
||||
unsigned int k;
|
||||
if (counts[j] == 0) // go to the end of stream
|
||||
{
|
||||
for (k = i + 1; k < j; k++)
|
||||
count += (counts[k] & ~0x8000);
|
||||
GFX2_Log(GFX2_DEBUG, "MOTO_MAP_pack() src=%u extend copy from %u to %u\n", src, counts[i], count);
|
||||
i = j - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (k = i + 1; k < j; k++)
|
||||
count += (counts[k] & ~0x8000);
|
||||
if (!(counts[j] & 0x8000))
|
||||
{ // merge with the next copy run (and the repeat runs between)
|
||||
GFX2_Log(GFX2_DEBUG, "MOTO_MAP_pack() src=%u merge savings=%d\n", src, savings);
|
||||
i = j;
|
||||
counts[i] += count;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{ // merge with the next few repeat runs
|
||||
GFX2_Log(GFX2_DEBUG, "MOTO_MAP_pack() src=%u extends savings=%d\n", src, savings);
|
||||
i = j - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
while (count > 255)
|
||||
{
|
||||
packed[dst++] = 0;
|
||||
packed[dst++] = 255;
|
||||
memcpy(packed+dst, unpacked+src, 255);
|
||||
dst += 255;
|
||||
src += 255;
|
||||
count -= 255;
|
||||
}
|
||||
packed[dst++] = 0;
|
||||
packed[dst++] = count;
|
||||
memcpy(packed+dst, unpacked+src, count);
|
||||
dst += count;
|
||||
src += count;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
free(counts);
|
||||
return dst;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if 0
|
||||
void Test_MOTO_MAP_pack(void)
|
||||
{
|
||||
unsigned int i, j;
|
||||
byte buffer[1024];
|
||||
byte buffer2[1024];
|
||||
unsigned int packed_len, unpacked_len, original_len;
|
||||
static const char * tests[] = {
|
||||
//"12345AAAAAAA@", // best : 00 05 "12345" 07 'A' 01 '@' : 11
|
||||
"123AABAA123@@@@@", // best : 00 0B "123AABAA123" 05 '@' : 15
|
||||
"123AAAAA123AABAA", // best : 00 03 "123" 05 'A' 00 06 "123AAB" 02 'A' : 17
|
||||
"123AAAAA123AAB", // best : 00 03 "123" 05 'A' 00 06 "123AAB" : 15
|
||||
"abcAABAAdddddddd", // best : 00 08 "abcAABAA" 08 'd' : 12
|
||||
NULL
|
||||
};
|
||||
|
||||
GFX2_Log(GFX2_DEBUG, "Test_MOTO_MAP_pack\n");
|
||||
for (i = 0; tests[i]; i++)
|
||||
{
|
||||
original_len = strlen(tests[i]);
|
||||
packed_len = MOTO_MAP_pack(buffer, (const byte *)tests[i], original_len);
|
||||
GFX2_Log(GFX2_DEBUG, " %s (%u) packed to %u\n", tests[i], original_len, packed_len);
|
||||
unpacked_len = 0;
|
||||
j = 0;
|
||||
// unpack to test
|
||||
while (j < packed_len)
|
||||
{
|
||||
if (buffer[j] == 0)
|
||||
{ // copy
|
||||
memcpy(buffer2 + unpacked_len, buffer + j + 2, buffer[j+1]);
|
||||
unpacked_len += buffer[j+1];
|
||||
j += 2 + buffer[j+1];
|
||||
}
|
||||
else
|
||||
{ // repeat
|
||||
memset(buffer2 + unpacked_len, buffer[j+1], buffer[j]);
|
||||
unpacked_len += buffer[j];
|
||||
j += 2;
|
||||
}
|
||||
}
|
||||
if (unpacked_len != original_len || 0 != memcmp(tests[i], buffer2, original_len))
|
||||
GFX2_Log(GFX2_ERROR, "*** %u %s != %u %s ***\n", original_len, tests[i], unpacked_len, buffer2);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* GUI window to choose Thomson MO/TO saving parameters
|
||||
*
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user