mirror of
https://github.com/rh-hideout/pokeemerald-expansion.git
synced 2026-03-21 18:04:50 -05:00
1332 lines
41 KiB
C++
1332 lines
41 KiB
C++
#include "compressAlgo.h"
|
|
|
|
ShortCopy::ShortCopy(size_t index, size_t length, size_t offset, unsigned short firstSymbol)
|
|
{
|
|
this->index = index;
|
|
this->length = length;
|
|
this->offset = offset;
|
|
this->firstSymbol = firstSymbol;
|
|
}
|
|
|
|
bool getShortCopies(std::vector<unsigned short> *pInput, size_t minLength, std::vector<ShortCopy> *pShortCopies)
|
|
{
|
|
size_t iteration = 0;
|
|
std::vector<char> checkVec(pInput->size());
|
|
for (size_t i = 0; i < checkVec.size(); i++)
|
|
checkVec[i] = ' ';
|
|
for (size_t startIndex = 1; startIndex < pInput->size(); startIndex++)
|
|
{
|
|
size_t longestLength = 0;
|
|
size_t longestOffset;
|
|
for (size_t searchOffset = 1; searchOffset <= startIndex && searchOffset < 32767; searchOffset++)
|
|
{
|
|
size_t currLength = 0;
|
|
while (startIndex + currLength < pInput->size()
|
|
&& (*pInput)[startIndex + currLength] == (*pInput)[startIndex + currLength - searchOffset])
|
|
currLength++;
|
|
|
|
if (currLength > longestLength)
|
|
{
|
|
longestLength = currLength;
|
|
longestOffset = searchOffset;
|
|
}
|
|
}
|
|
|
|
if (longestLength > 32767)
|
|
longestLength = 32767;
|
|
if (longestLength >= minLength)
|
|
{
|
|
// Handle non-copies
|
|
if (startIndex > 0)
|
|
checkVec[startIndex - 1] = 'X';
|
|
|
|
for (size_t i = 0; i < longestLength; i++)
|
|
{
|
|
checkVec[startIndex + i] = 'X';
|
|
}
|
|
for (size_t i = 0; i < startIndex - 1; i++)
|
|
{
|
|
if (checkVec[i] == ' ')
|
|
{
|
|
size_t extraIndex = i;
|
|
checkVec[extraIndex] = 'O';
|
|
size_t extraLength = 1;
|
|
while (checkVec[extraIndex + extraLength] == ' ')
|
|
{
|
|
checkVec[extraIndex + extraLength] = 'O';
|
|
extraLength++;
|
|
}
|
|
pShortCopies->push_back(ShortCopy(extraIndex, extraLength, 0, 0));
|
|
break;
|
|
}
|
|
}
|
|
|
|
pShortCopies->push_back(ShortCopy(startIndex, longestLength, longestOffset, (*pInput)[startIndex - 1]));
|
|
startIndex += longestLength;
|
|
}
|
|
}
|
|
|
|
// Handle trailing characters
|
|
if (checkVec.back() == ' ')
|
|
{
|
|
size_t index = 0;
|
|
if (pShortCopies->size() > 0)
|
|
{
|
|
index = pShortCopies->back().index + pShortCopies->back().length;
|
|
size_t length = checkVec.size() - index;
|
|
pShortCopies->push_back(ShortCopy(index, length, 0, 0));
|
|
}
|
|
else
|
|
{
|
|
pShortCopies->push_back(ShortCopy(0, checkVec.size(), 0, 0));
|
|
}
|
|
}
|
|
|
|
return verifyShortCopies(pShortCopies, pInput);
|
|
}
|
|
|
|
bool verifyShortCopies(std::vector<ShortCopy> *pCopies, std::vector<unsigned short> *pImage)
|
|
{
|
|
size_t totalLength = 0;
|
|
for (ShortCopy copy : (*pCopies))
|
|
{
|
|
totalLength += copy.length;
|
|
if (copy.offset != 0)
|
|
{
|
|
totalLength++;
|
|
}
|
|
|
|
if (copy.offset != 0)
|
|
{
|
|
if (copy.firstSymbol != (*pImage)[copy.index - 1])
|
|
return false;
|
|
|
|
for (size_t i = 0; i < copy.length; i++)
|
|
{
|
|
if ((*pImage)[copy.index + i] != (*pImage)[copy.index + i - copy.offset])
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
if (totalLength != pImage->size())
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool getShortInstructions(std::vector<ShortCopy> *pCopies, std::vector<ShortCompressionInstruction> *pInstructions, std::vector<unsigned short> *pInput)
|
|
{
|
|
for (ShortCopy copy : (*pCopies))
|
|
{
|
|
ShortCompressionInstruction currInstruction;
|
|
currInstruction.index = copy.index;
|
|
currInstruction.offset = copy.offset;
|
|
currInstruction.length = copy.length;
|
|
currInstruction.firstSymbol = copy.firstSymbol;
|
|
currInstruction.buildBytes(pInput);
|
|
pInstructions->push_back(currInstruction);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void getLosFromInstructions(std::vector<ShortCompressionInstruction> *pInstructions, std::vector<unsigned char> *pOutput)
|
|
{
|
|
for (ShortCompressionInstruction instruction : (*pInstructions))
|
|
{
|
|
for (unsigned char uc : instruction.loBytes)
|
|
pOutput->push_back(uc);
|
|
}
|
|
}
|
|
|
|
void getSymsFromInstructions(std::vector<ShortCompressionInstruction> *pInstructions, std::vector<unsigned short> *pOutput)
|
|
{
|
|
for (ShortCompressionInstruction instruction : (*pInstructions))
|
|
{
|
|
for (unsigned short us : instruction.symShorts)
|
|
pOutput->push_back(us);
|
|
}
|
|
}
|
|
|
|
void ShortCompressionInstruction::buildBytes(std::vector<unsigned short> *pInput)
|
|
{
|
|
if (offset != 0)
|
|
{
|
|
// Current pattern either exists earlier in the image
|
|
// or it's a long run of the same value
|
|
size_t currLength = length;
|
|
loBytes.push_back(currLength & LO_LOW_BITS_MASK);
|
|
currLength = currLength >> LO_NUM_LOW_BITS;
|
|
if (currLength != 0)
|
|
{
|
|
loBytes[loBytes.size() - 1] += LO_CONTINUE_BIT;
|
|
loBytes.push_back(currLength & BYTE_MASK);
|
|
}
|
|
size_t currOffset = offset;
|
|
loBytes.push_back(currOffset & LO_LOW_BITS_MASK);
|
|
currOffset = currOffset >> LO_NUM_LOW_BITS;
|
|
if (currOffset != 0)
|
|
{
|
|
loBytes[loBytes.size() - 1] += LO_CONTINUE_BIT;
|
|
loBytes.push_back(currOffset & BYTE_MASK);
|
|
}
|
|
symShorts.push_back(firstSymbol);
|
|
}
|
|
else
|
|
{
|
|
// The current pattern doesn't exist earlier in the image
|
|
// it has to be written section by section
|
|
// Set LENGTH parameter to 0, and use OFFSET parameter as length
|
|
loBytes.push_back(0);
|
|
size_t currLength = length;
|
|
loBytes.push_back(currLength & LO_LOW_BITS_MASK);
|
|
currLength = currLength >> LO_NUM_LOW_BITS;
|
|
if (currLength != 0)
|
|
{
|
|
loBytes[loBytes.size() - 1] += LO_CONTINUE_BIT;
|
|
loBytes.push_back(currLength & BYTE_MASK);
|
|
}
|
|
for (size_t i = 0; i < length; i++)
|
|
{
|
|
symShorts.push_back((*pInput)[index + i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool verifyBytesShort(std::vector<unsigned char> *pLoVec, std::vector<unsigned short> *pSymVec, std::vector<unsigned short> *pImage)
|
|
{
|
|
std::vector<unsigned short> decodedImage;
|
|
size_t loIndex = 0;
|
|
size_t symIndex = 0;
|
|
while (loIndex < pLoVec->size())
|
|
{
|
|
size_t currLength = 0;
|
|
size_t currOffset = 0;
|
|
currLength += (*pLoVec)[loIndex] & LO_LOW_BITS_MASK;
|
|
loIndex++;
|
|
if (((*pLoVec)[loIndex-1] & LO_CONTINUE_BIT) == LO_CONTINUE_BIT)
|
|
{
|
|
currLength += (*pLoVec)[loIndex] << LO_NUM_LOW_BITS;
|
|
loIndex++;
|
|
}
|
|
currOffset += (*pLoVec)[loIndex] & LO_LOW_BITS_MASK;
|
|
loIndex++;
|
|
if (((*pLoVec)[loIndex-1] & LO_CONTINUE_BIT) == LO_CONTINUE_BIT)
|
|
{
|
|
currOffset += (*pLoVec)[loIndex] << LO_NUM_LOW_BITS;
|
|
loIndex++;
|
|
}
|
|
if (currLength != 0)
|
|
{
|
|
decodedImage.push_back((*pSymVec)[symIndex]);
|
|
symIndex++;
|
|
for (size_t i = 0; i < currLength; i++)
|
|
decodedImage.push_back(decodedImage[decodedImage.size() - currOffset]);
|
|
}
|
|
else
|
|
{
|
|
for (size_t i = 0; i < currOffset; i++)
|
|
{
|
|
decodedImage.push_back((*pSymVec)[symIndex]);
|
|
symIndex++;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool compareVectorsShort(std::vector<unsigned short> *pVec1, std::vector<unsigned short> *pVec2)
|
|
{
|
|
if (pVec1->size() != pVec2->size())
|
|
return false;
|
|
for (size_t i = 0; i < pVec1->size(); i++)
|
|
if ((*pVec1)[i] != (*pVec2)[i])
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
bool isModeLoEncoded(CompressionMode mode)
|
|
{
|
|
if (mode == ENCODE_LO
|
|
|| mode == ENCODE_BOTH
|
|
|| mode == ENCODE_BOTH_DELTA_SYMS)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
bool isModeSymEncoded(CompressionMode mode)
|
|
{
|
|
if (mode == ENCODE_SYMS
|
|
|| mode == ENCODE_DELTA_SYMS
|
|
|| mode == ENCODE_BOTH
|
|
|| mode == ENCODE_BOTH_DELTA_SYMS)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
bool isModeSymDelta(CompressionMode mode)
|
|
{
|
|
if (mode == ENCODE_DELTA_SYMS
|
|
|| mode == ENCODE_BOTH_DELTA_SYMS)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
std::vector<int> getNormalizedCounts(std::vector<size_t> *input)
|
|
{
|
|
std::vector<int> tempVec(16);
|
|
for (size_t i = 0; i < input->size(); i++)
|
|
tempVec[i] = (*input)[i];
|
|
tempVec = normalizeCounts(tempVec, TANS_TABLE_SIZE);
|
|
bool shouldAdjust = false;
|
|
for (int i = 0; i < 16; i++)
|
|
if (tempVec[i] == TANS_TABLE_SIZE)
|
|
{
|
|
shouldAdjust = true;
|
|
tempVec[i]--;
|
|
}
|
|
if (shouldAdjust)
|
|
for (size_t i = 0; i < 16; i++)
|
|
if (tempVec[i] == 0)
|
|
{
|
|
tempVec[i]++;
|
|
break;
|
|
}
|
|
std::vector<int> returnVec(16);
|
|
for (size_t i = 0; i < 16; i++)
|
|
returnVec[i] = tempVec[i];
|
|
return returnVec;
|
|
}
|
|
|
|
std::vector<unsigned int> getFreqWriteInts(std::vector<int> input)
|
|
{
|
|
std::vector<unsigned int> returnVec(3);
|
|
for (size_t i = 0; i < 5; i++)
|
|
{
|
|
unsigned int val1 = input[i];
|
|
unsigned int val2 = input[5 + i];
|
|
unsigned int val3 = input[10 + i];
|
|
val1 = val1 << (i*6);
|
|
val2 = val2 << (i*6);
|
|
val3 = val3 << (i*6);
|
|
returnVec[0] += val1;
|
|
returnVec[1] += val2;
|
|
returnVec[2] += val3;
|
|
}
|
|
unsigned int lastVal = input[15];
|
|
returnVec[0] += (lastVal & 0x3) << 30;
|
|
returnVec[1] += (lastVal & 0xc) << 28;
|
|
returnVec[2] += (lastVal & 0x30) << 26;
|
|
return returnVec;
|
|
}
|
|
|
|
std::vector<int> getTestFreqs(std::vector<int> freqs, std::string name)
|
|
{
|
|
if (name.find("test/compression/table_") == std::string::npos)
|
|
return freqs;
|
|
if (name.find("table_63_1") != std::string::npos)
|
|
{
|
|
freqs.clear();
|
|
freqs.resize(16);
|
|
freqs[0] = 63;
|
|
freqs[1] = 1;
|
|
}
|
|
if (name.find("table_62_2") != std::string::npos)
|
|
{
|
|
freqs.clear();
|
|
freqs.resize(16);
|
|
freqs[0] = 62;
|
|
freqs[1] = 2;
|
|
}
|
|
if (name.find("table_61_3") != std::string::npos)
|
|
{
|
|
freqs.clear();
|
|
freqs.resize(16);
|
|
freqs[0] = 61;
|
|
freqs[1] = 3;
|
|
}
|
|
if (name.find("table_60_4") != std::string::npos)
|
|
{
|
|
freqs.clear();
|
|
freqs.resize(16);
|
|
freqs[0] = 60;
|
|
freqs[1] = 4;
|
|
}
|
|
if (name.find("table_59_5") != std::string::npos)
|
|
{
|
|
freqs.clear();
|
|
freqs.resize(16);
|
|
freqs[0] = 59;
|
|
freqs[1] = 5;
|
|
}
|
|
if (name.find("table_58_6") != std::string::npos)
|
|
{
|
|
freqs.clear();
|
|
freqs.resize(16);
|
|
freqs[0] = 58;
|
|
freqs[1] = 6;
|
|
}
|
|
if (name.find("table_57_7") != std::string::npos)
|
|
{
|
|
freqs.clear();
|
|
freqs.resize(16);
|
|
freqs[0] = 57;
|
|
freqs[1] = 7;
|
|
}
|
|
if (name.find("table_56_8") != std::string::npos)
|
|
{
|
|
freqs.clear();
|
|
freqs.resize(16);
|
|
freqs[0] = 56;
|
|
freqs[1] = 8;
|
|
}
|
|
if (name.find("table_55_9") != std::string::npos)
|
|
{
|
|
freqs.clear();
|
|
freqs.resize(16);
|
|
freqs[0] = 55;
|
|
freqs[1] = 9;
|
|
}
|
|
if (name.find("table_54_10") != std::string::npos)
|
|
{
|
|
freqs.clear();
|
|
freqs.resize(16);
|
|
freqs[0] = 54;
|
|
freqs[1] = 10;
|
|
}
|
|
if (name.find("table_53_11") != std::string::npos)
|
|
{
|
|
freqs.clear();
|
|
freqs.resize(16);
|
|
freqs[0] = 53;
|
|
freqs[1] = 11;
|
|
}
|
|
if (name.find("table_52_12") != std::string::npos)
|
|
{
|
|
freqs.clear();
|
|
freqs.resize(16);
|
|
freqs[0] = 52;
|
|
freqs[1] = 12;
|
|
}
|
|
if (name.find("table_51_13") != std::string::npos)
|
|
{
|
|
freqs.clear();
|
|
freqs.resize(16);
|
|
freqs[0] = 51;
|
|
freqs[1] = 13;
|
|
}
|
|
if (name.find("table_50_14") != std::string::npos)
|
|
{
|
|
freqs.clear();
|
|
freqs.resize(16);
|
|
freqs[0] = 50;
|
|
freqs[1] = 14;
|
|
}
|
|
if (name.find("table_49_15") != std::string::npos)
|
|
{
|
|
freqs.clear();
|
|
freqs.resize(16);
|
|
freqs[0] = 49;
|
|
freqs[1] = 15;
|
|
}
|
|
if (name.find("table_48_16") != std::string::npos)
|
|
{
|
|
freqs.clear();
|
|
freqs.resize(16);
|
|
freqs[0] = 48;
|
|
freqs[1] = 16;
|
|
}
|
|
if (name.find("table_47_17") != std::string::npos)
|
|
{
|
|
freqs.clear();
|
|
freqs.resize(16);
|
|
freqs[0] = 47;
|
|
freqs[1] = 17;
|
|
}
|
|
if (name.find("table_46_18") != std::string::npos)
|
|
{
|
|
freqs.clear();
|
|
freqs.resize(16);
|
|
freqs[0] = 46;
|
|
freqs[1] = 18;
|
|
}
|
|
if (name.find("table_45_19") != std::string::npos)
|
|
{
|
|
freqs.clear();
|
|
freqs.resize(16);
|
|
freqs[0] = 45;
|
|
freqs[1] = 19;
|
|
}
|
|
if (name.find("table_44_20") != std::string::npos)
|
|
{
|
|
freqs.clear();
|
|
freqs.resize(16);
|
|
freqs[0] = 44;
|
|
freqs[1] = 20;
|
|
}
|
|
if (name.find("table_43_21") != std::string::npos)
|
|
{
|
|
freqs.clear();
|
|
freqs.resize(16);
|
|
freqs[0] = 43;
|
|
freqs[1] = 21;
|
|
}
|
|
if (name.find("table_42_22") != std::string::npos)
|
|
{
|
|
freqs.clear();
|
|
freqs.resize(16);
|
|
freqs[0] = 42;
|
|
freqs[1] = 22;
|
|
}
|
|
if (name.find("table_41_23") != std::string::npos)
|
|
{
|
|
freqs.clear();
|
|
freqs.resize(16);
|
|
freqs[0] = 41;
|
|
freqs[1] = 23;
|
|
}
|
|
if (name.find("table_40_24") != std::string::npos)
|
|
{
|
|
freqs.clear();
|
|
freqs.resize(16);
|
|
freqs[0] = 40;
|
|
freqs[1] = 24;
|
|
}
|
|
if (name.find("table_39_25") != std::string::npos)
|
|
{
|
|
freqs.clear();
|
|
freqs.resize(16);
|
|
freqs[0] = 39;
|
|
freqs[1] = 25;
|
|
}
|
|
if (name.find("table_38_26") != std::string::npos)
|
|
{
|
|
freqs.clear();
|
|
freqs.resize(16);
|
|
freqs[0] = 38;
|
|
freqs[1] = 26;
|
|
}
|
|
if (name.find("table_37_27") != std::string::npos)
|
|
{
|
|
freqs.clear();
|
|
freqs.resize(16);
|
|
freqs[0] = 37;
|
|
freqs[1] = 27;
|
|
}
|
|
if (name.find("table_36_28") != std::string::npos)
|
|
{
|
|
freqs.clear();
|
|
freqs.resize(16);
|
|
freqs[0] = 36;
|
|
freqs[1] = 28;
|
|
}
|
|
if (name.find("table_35_29") != std::string::npos)
|
|
{
|
|
freqs.clear();
|
|
freqs.resize(16);
|
|
freqs[0] = 35;
|
|
freqs[1] = 29;
|
|
}
|
|
if (name.find("table_34_30") != std::string::npos)
|
|
{
|
|
freqs.clear();
|
|
freqs.resize(16);
|
|
freqs[0] = 34;
|
|
freqs[1] = 30;
|
|
}
|
|
if (name.find("table_33_31") != std::string::npos)
|
|
{
|
|
freqs.clear();
|
|
freqs.resize(16);
|
|
freqs[0] = 33;
|
|
freqs[1] = 31;
|
|
}
|
|
if (name.find("table_32_32") != std::string::npos)
|
|
{
|
|
freqs.clear();
|
|
freqs.resize(16);
|
|
freqs[0] = 32;
|
|
freqs[1] = 32;
|
|
}
|
|
return freqs;
|
|
}
|
|
|
|
void deltaEncode(std::vector<unsigned char> *buffer, int length)
|
|
{
|
|
unsigned char last = 0;
|
|
for (int i = 0; i < length; i++)
|
|
{
|
|
unsigned char current =(*buffer)[i];
|
|
(*buffer)[i] = (current-last) & 0xf;
|
|
last = current;
|
|
}
|
|
}
|
|
|
|
void deltaDecode(std::vector<unsigned char> *buffer, int length)
|
|
{
|
|
unsigned char last = 0;
|
|
for (int i = 0; i < length; i++)
|
|
{
|
|
unsigned char delta =(*buffer)[i];
|
|
(*buffer)[i] = (delta+last) & 0xf;
|
|
last = (*buffer)[i];
|
|
}
|
|
}
|
|
|
|
int findInitialState(EncodeCol *encodeCol, unsigned char firstSymbol)
|
|
{
|
|
for (size_t i = 0; i < encodeCol->symbols.size(); i++)
|
|
{
|
|
if (encodeCol->symbols[i].symbol == firstSymbol)
|
|
return encodeCol->symbols[i].nextState;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
size_t decodeNibbles(std::vector<DecodeCol> decodeTable, std::vector<unsigned int> *bits, int *currState, std::vector<unsigned char> *nibbleVec, size_t currBitIndex, size_t numNibbles, bool lastThing)
|
|
{
|
|
for (size_t i = 0; i < numNibbles; i++)
|
|
{
|
|
(*nibbleVec)[i] = decodeTable[*currState].symbol;
|
|
|
|
if (i + 1 == nibbleVec->size() && lastThing)
|
|
return currBitIndex;
|
|
|
|
int currK = decodeTable[*currState].k;
|
|
int nextState = decodeTable[*currState].y << currK;
|
|
for (size_t j = 0; j < currK; j++)
|
|
{
|
|
nextState += (*bits)[currBitIndex] << j;
|
|
currBitIndex++;
|
|
}
|
|
*currState = nextState - TANS_TABLE_SIZE;
|
|
}
|
|
return currBitIndex;
|
|
}
|
|
|
|
std::vector<unsigned int> getNewHeaders(CompressionMode mode, size_t imageSize, size_t symLength, int initialState, size_t bitstreamSize, size_t loLength)
|
|
{
|
|
if (initialState == -1)
|
|
initialState = 0;
|
|
std::vector<unsigned int> returnVec(2);
|
|
|
|
returnVec[0] += (unsigned int)mode; // 4 bits
|
|
returnVec[0] += (imageSize/IMAGE_SIZE_MODIFIER) << IMAGE_SIZE_OFFSET; // 14 bits
|
|
returnVec[0] += (symLength) << SYM_SIZE_OFFSET; // 14 bits
|
|
// 32 total
|
|
|
|
returnVec[1] += initialState; // 6 bits
|
|
returnVec[1] += bitstreamSize << BITSTREAM_SIZE_OFFSET; // 13 bits
|
|
returnVec[1] += loLength << LO_SIZE_OFFSET; // 13 bits
|
|
// 32 total
|
|
|
|
return returnVec;
|
|
}
|
|
|
|
bool fillCompressVec(std::vector<unsigned char> *pLoVec, std::vector<unsigned short> *pSymVec, CompressionMode mode, size_t imageBytes, std::string name, CompressedImage *pOutput)
|
|
{
|
|
bool loEncoded = isModeLoEncoded(mode);
|
|
bool symEncoded = isModeSymEncoded(mode);
|
|
bool symDelta = isModeSymDelta(mode);
|
|
|
|
std::vector<unsigned char> loNibbles(2 * pLoVec->size());
|
|
std::vector<unsigned char> symNibbles(4 * pSymVec->size());
|
|
std::vector<DecodeCol> loDecode;
|
|
std::vector<DecodeCol> symDecode;
|
|
std::vector<unsigned char> symbols = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
|
|
|
|
if (loEncoded)
|
|
{
|
|
for (size_t i = 0; i < pLoVec->size(); i++)
|
|
{
|
|
loNibbles[2*i] = (*pLoVec)[i] & 0xf;
|
|
loNibbles[2*i + 1] = ((*pLoVec)[i] >> 4) & 0xf;
|
|
}
|
|
std::vector<size_t> loCounts(16);
|
|
for (unsigned char uc : loNibbles)
|
|
loCounts[uc]++;
|
|
std::vector<int> loFreqs = getNormalizedCounts(&loCounts);
|
|
std::vector<unsigned int> freqs = getFreqWriteInts(loFreqs);
|
|
pOutput->loFreqs[0] = freqs[0];
|
|
pOutput->loFreqs[1] = freqs[1];
|
|
pOutput->loFreqs[2] = freqs[2];
|
|
loDecode = createDecodingTable(symbols, loFreqs);
|
|
}
|
|
|
|
if (symEncoded)
|
|
{
|
|
for (size_t i = 0; i < pSymVec->size(); i++)
|
|
{
|
|
for (size_t j = 0; j < 4; j++)
|
|
symNibbles[4*i + j] = ((*pSymVec)[i] >> (4*j)) & 0xf;
|
|
}
|
|
std::vector<size_t> symCounts(16);
|
|
if (symDelta)
|
|
deltaEncode(&symNibbles, symNibbles.size());
|
|
for (unsigned char uc : symNibbles)
|
|
symCounts[uc]++;
|
|
std::vector<int> symFreqs = getNormalizedCounts(&symCounts);
|
|
symFreqs = getTestFreqs(symFreqs, name);
|
|
std::vector<unsigned int> freqs = getFreqWriteInts(symFreqs);
|
|
pOutput->symFreqs[0] = freqs[0];
|
|
pOutput->symFreqs[1] = freqs[1];
|
|
pOutput->symFreqs[2] = freqs[2];
|
|
symDecode = createDecodingTable(symbols, symFreqs);
|
|
}
|
|
|
|
int currState = -1;
|
|
std::vector<unsigned int> bitstream;
|
|
if (symEncoded)
|
|
{
|
|
std::vector<unsigned char> reversedVec;
|
|
for (size_t i = 0; i < symNibbles.size(); i++)
|
|
reversedVec.push_back(symNibbles[symNibbles.size() - i - 1]);
|
|
std::vector<EncodeCol> symEncode = createEncodingTable(symDecode, symbols);
|
|
size_t startIndex = 0;
|
|
if (currState == -1)
|
|
{
|
|
currState = findInitialState(&symEncode[0], reversedVec[0]) - TANS_TABLE_SIZE;
|
|
startIndex = 1;
|
|
}
|
|
for (size_t i = startIndex; i < reversedVec.size(); i++)
|
|
currState = encodeSingleSymbol(symEncode[currState], reversedVec[i], &bitstream) - TANS_TABLE_SIZE;
|
|
}
|
|
|
|
if (loEncoded)
|
|
{
|
|
std::vector<unsigned char> reversedVec;
|
|
for (size_t i = 0; i < loNibbles.size(); i++)
|
|
reversedVec.push_back(loNibbles[loNibbles.size() - i - 1]);
|
|
std::vector<EncodeCol> loEncode = createEncodingTable(loDecode, symbols);
|
|
size_t startIndex = 0;
|
|
if (currState == -1)
|
|
{
|
|
currState = findInitialState(&loEncode[0], reversedVec[0]) - TANS_TABLE_SIZE;
|
|
startIndex = 1;
|
|
}
|
|
for (size_t i = startIndex; i < reversedVec.size(); i++)
|
|
currState = encodeSingleSymbol(loEncode[currState], reversedVec[i], &bitstream) - TANS_TABLE_SIZE;
|
|
}
|
|
|
|
std::vector<unsigned int> reversedBitstream(bitstream.size());
|
|
for (size_t i = 0; i < bitstream.size(); i++)
|
|
reversedBitstream[reversedBitstream.size() - 1 - i] = bitstream[i];
|
|
bitstream = reversedBitstream;
|
|
std::vector<unsigned int> checkBits = bitstream;
|
|
int checkState = currState;
|
|
size_t currBitIndex = 0;
|
|
|
|
if (loEncoded)
|
|
{
|
|
bool lastThing = !symEncoded;
|
|
std::vector<unsigned char> checkLoNibbles(loNibbles.size());
|
|
currBitIndex = decodeNibbles(loDecode, &checkBits, &checkState, &checkLoNibbles, currBitIndex, loNibbles.size(), lastThing);
|
|
for (size_t i = 0; i < loNibbles.size(); i++)
|
|
{
|
|
if (loNibbles[i] != checkLoNibbles[i])
|
|
{
|
|
fprintf(stderr, "LO Mismatch\n");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (symEncoded)
|
|
{
|
|
std::vector<unsigned char> checkSymNibbles(symNibbles.size());
|
|
currBitIndex = decodeNibbles(symDecode, &checkBits, &checkState, &checkSymNibbles, currBitIndex, symNibbles.size(), true);
|
|
for (size_t i = 0; i < symNibbles.size(); i++)
|
|
{
|
|
if (symNibbles[i] != checkSymNibbles[i])
|
|
{
|
|
fprintf(stderr, "Symbol Mismatch\n");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
std::vector<unsigned int> tANSbits;
|
|
unsigned int currInt = 0;
|
|
for (size_t i = 0; i < bitstream.size(); i++)
|
|
{
|
|
currInt += bitstream[i] << (i%32);
|
|
if ((i+1) % 32 == 0)
|
|
{
|
|
tANSbits.push_back(currInt);
|
|
currInt = 0;
|
|
}
|
|
}
|
|
if (bitstream.size() % 32 != 0)
|
|
tANSbits.push_back(currInt);
|
|
|
|
pOutput->headers = getNewHeaders(mode, imageBytes, pSymVec->size(), currState, tANSbits.size(), pLoVec->size());
|
|
pOutput->tANSbits = tANSbits;
|
|
pOutput->symVec = *pSymVec;
|
|
pOutput->loVec = *pLoVec;
|
|
pOutput->initialState = currState;
|
|
return true;
|
|
}
|
|
|
|
bool verifyCompressionShort(CompressedImage *pInput, std::vector<unsigned short> *pImage)
|
|
{
|
|
std::vector<unsigned short> decodedImage = decodeImageShort(pInput);
|
|
return compareVectorsShort(&decodedImage, pImage);
|
|
}
|
|
|
|
std::vector<unsigned short> decodeImageShort(CompressedImage *pInput)
|
|
{
|
|
DataVecs dataVecs = decodeDataVectorsNew(pInput);
|
|
return decodeBytesShort(&dataVecs.loVec, &dataVecs.symVec);
|
|
}
|
|
|
|
std::vector<unsigned short> decodeBytesShort(std::vector<unsigned char> *pLoVec, std::vector<unsigned short> *pSymVec)
|
|
{
|
|
std::vector<unsigned short> decodedImage;
|
|
size_t loIndex = 0;
|
|
size_t symIndex = 0;
|
|
while (loIndex < pLoVec->size())
|
|
{
|
|
size_t currLength = 0;
|
|
size_t currOffset = 0;
|
|
currLength += (*pLoVec)[loIndex] & LO_LOW_BITS_MASK;
|
|
loIndex++;
|
|
if (((*pLoVec)[loIndex-1] & LO_CONTINUE_BIT) == LO_CONTINUE_BIT)
|
|
{
|
|
currLength += (*pLoVec)[loIndex] << LO_NUM_LOW_BITS;
|
|
loIndex++;
|
|
}
|
|
currOffset += (*pLoVec)[loIndex] & LO_LOW_BITS_MASK;
|
|
loIndex++;
|
|
if (((*pLoVec)[loIndex-1] & LO_CONTINUE_BIT) == LO_CONTINUE_BIT)
|
|
{
|
|
currOffset += (*pLoVec)[loIndex] << LO_NUM_LOW_BITS;
|
|
loIndex++;
|
|
}
|
|
if (currLength != 0)
|
|
{
|
|
decodedImage.push_back((*pSymVec)[symIndex]);
|
|
symIndex++;
|
|
for (size_t i = 0; i < currLength; i++)
|
|
decodedImage.push_back(decodedImage[decodedImage.size() - currOffset]);
|
|
}
|
|
else
|
|
{
|
|
for (size_t i = 0; i < currOffset; i++)
|
|
{
|
|
decodedImage.push_back((*pSymVec)[symIndex]);
|
|
symIndex++;
|
|
}
|
|
}
|
|
}
|
|
return decodedImage;
|
|
}
|
|
|
|
DataVecs decodeDataVectorsNew(CompressedImage *pInput)
|
|
{
|
|
CompressedImage headerValues;
|
|
readNewHeader(&pInput->headers, &headerValues);
|
|
size_t loSize = headerValues.loSize;
|
|
size_t symSize = headerValues.symSize;
|
|
CompressionMode mode = headerValues.mode;
|
|
bool loEncoded = isModeLoEncoded(mode);
|
|
bool symEncoded = isModeSymEncoded(mode);
|
|
bool symDelta = isModeSymDelta(mode);
|
|
std::vector<unsigned char> symbols = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
|
|
std::vector<DecodeCol> loDecode;
|
|
std::vector<DecodeCol> symDecode;
|
|
|
|
std::vector<unsigned char> loVec(loSize);
|
|
std::vector<unsigned short> symVec(symSize);
|
|
std::vector<unsigned char> loNibbles(loSize*2);
|
|
std::vector<unsigned char> symNibbles(symSize*4);
|
|
|
|
if (loEncoded)
|
|
{
|
|
std::vector<int> loFreqs = unpackFrequencies(&pInput->loFreqs[0]);
|
|
loDecode = createDecodingTable(symbols, loFreqs);
|
|
}
|
|
if (symEncoded)
|
|
{
|
|
std::vector<int> symFreqs = unpackFrequencies(&pInput->symFreqs[0]);
|
|
symDecode = createDecodingTable(symbols, symFreqs);
|
|
}
|
|
|
|
std::vector<unsigned int> allBits(pInput->tANSbits.size()*32);
|
|
size_t currIndex = 0;
|
|
for (unsigned int ui : pInput->tANSbits)
|
|
for (size_t i = 0; i < 32; i++)
|
|
{
|
|
unsigned int currVal = (ui >> i) & 0x1;
|
|
allBits[currIndex] = currVal;
|
|
currIndex++;
|
|
}
|
|
|
|
if (!symEncoded)
|
|
for (size_t i = 0; i < symSize; i++)
|
|
symVec[i] = pInput->symVec[i];
|
|
if (!loEncoded)
|
|
for (size_t i = 0; i < loSize; i++)
|
|
loVec[i] = pInput->loVec[i];
|
|
|
|
size_t bitIndex = 0;
|
|
int currState = pInput->initialState;
|
|
if (loEncoded)
|
|
{
|
|
bitIndex = decodeNibbles(loDecode, &allBits, &currState, &loNibbles, bitIndex, loSize*2, !symEncoded);
|
|
}
|
|
if (loEncoded)
|
|
for (size_t i = 0; i < loVec.size(); i++)
|
|
loVec[i] = loNibbles[2*i] + (loNibbles[2*i + 1] << 4);
|
|
|
|
if (symEncoded)
|
|
{
|
|
bitIndex = decodeNibbles(symDecode, &allBits, &currState, &symNibbles, bitIndex, symSize*4, true);
|
|
if (symDelta)
|
|
deltaDecode(&symNibbles, symNibbles.size());
|
|
}
|
|
if (symEncoded)
|
|
for (size_t i = 0; i < symVec.size(); i++)
|
|
for (size_t j = 0; j < 4; j++)
|
|
symVec[i] += (unsigned short)symNibbles[i*4 + j] << (j*4);
|
|
|
|
DataVecs returnData;
|
|
returnData.loVec = loVec;
|
|
returnData.symVec = symVec;
|
|
return returnData;
|
|
}
|
|
|
|
void readNewHeader(std::vector<unsigned int> *pInput, CompressedImage *pOutput)
|
|
{
|
|
std::vector<unsigned int> headers(2);
|
|
headers[0] = (*pInput)[0];
|
|
headers[1] = (*pInput)[1];
|
|
pOutput->mode = (CompressionMode)(headers[0] & MODE_MASK);
|
|
pOutput->rawNumBytes = ((headers[0] >> IMAGE_SIZE_OFFSET) & IMAGE_SIZE_MASK) * IMAGE_SIZE_MODIFIER;
|
|
pOutput->symSize = ((headers[0] >> SYM_SIZE_OFFSET) & SYM_SIZE_MASK);
|
|
|
|
pOutput->initialState = headers[1] & INITIAL_STATE_MASK;
|
|
pOutput->bitreamSize = (headers[1] >> BITSTREAM_SIZE_OFFSET) & BITSTREAM_SIZE_MASK;
|
|
pOutput->loSize = (headers[1] >> LO_SIZE_OFFSET) & LO_SIZE_MASK;
|
|
pOutput->headers = headers;
|
|
}
|
|
|
|
std::vector<int> unpackFrequencies(unsigned int pInts[3])
|
|
{
|
|
std::vector<int> returnVec;
|
|
int freq15 = 0;
|
|
for (size_t i = 0; i < 3; i++)
|
|
{
|
|
for (size_t j = 0; j < 5; j++)
|
|
{
|
|
int currVal = (pInts[i] >> (6*j)) & 0x3f;
|
|
returnVec.push_back(currVal);
|
|
}
|
|
freq15 += ((pInts[i] >> 30) & 0x3) << (2*i);
|
|
}
|
|
returnVec.push_back(freq15);
|
|
return returnVec;
|
|
}
|
|
|
|
void getUIntVecFromData(CompressedImage *pImage, std::vector<unsigned int> *pOutput)
|
|
{
|
|
CompressedImage otherImage;
|
|
readNewHeader(&pImage->headers, &otherImage);
|
|
pOutput->push_back(pImage->headers[0]);
|
|
pOutput->push_back(pImage->headers[1]);
|
|
if (isModeLoEncoded(otherImage.mode))
|
|
for (size_t i = 0; i < 3; i++)
|
|
pOutput->push_back(pImage->loFreqs[i]);
|
|
if (isModeSymEncoded(otherImage.mode))
|
|
for (size_t i = 0; i < 3; i++)
|
|
pOutput->push_back(pImage->symFreqs[i]);
|
|
if (isModeLoEncoded(otherImage.mode) || isModeSymEncoded(otherImage.mode))
|
|
for (unsigned int ui : pImage->tANSbits)
|
|
pOutput->push_back(ui);
|
|
unsigned int currInt = 0;
|
|
unsigned int currOffset = 0;
|
|
if (!isModeSymEncoded(otherImage.mode))
|
|
{
|
|
for (size_t i = 0; i < pImage->symVec.size(); i++)
|
|
{
|
|
currInt += pImage->symVec[i] << (8*(currOffset % 4));
|
|
currOffset += 2;
|
|
if (currOffset % 4 == 0)
|
|
{
|
|
pOutput->push_back(currInt);
|
|
currInt = 0;
|
|
}
|
|
}
|
|
}
|
|
if (!isModeLoEncoded(otherImage.mode))
|
|
{
|
|
for (size_t i = 0; i < pImage->loVec.size(); i++)
|
|
{
|
|
currInt += 0;
|
|
currInt += pImage->loVec[i] << (8*(currOffset % 4));
|
|
currOffset++;
|
|
if (currOffset % 4 == 0)
|
|
{
|
|
pOutput->push_back(currInt);
|
|
currInt = 0;
|
|
}
|
|
}
|
|
}
|
|
if (currOffset % 4 != 0)
|
|
pOutput->push_back(currInt);
|
|
}
|
|
|
|
void readRawDataVecs(std::vector<unsigned int> *pInput, std::vector<unsigned short> *pOutput)
|
|
{
|
|
CompressedImage readImage;
|
|
readNewHeader(pInput, &readImage);
|
|
bool loEncoded = isModeLoEncoded(readImage.mode);
|
|
bool symEncoded = isModeSymEncoded(readImage.mode);
|
|
bool symDelta = isModeSymDelta(readImage.mode);
|
|
size_t readIndex = 2;
|
|
std::vector<unsigned int> tANSbits;
|
|
std::vector<unsigned int> allBits;
|
|
std::vector<unsigned short> symVec(readImage.symSize);
|
|
std::vector<unsigned char> loVec(readImage.loSize);
|
|
std::vector<DecodeCol> symDecode(TANS_TABLE_SIZE);
|
|
std::vector<DecodeCol> loDecode(TANS_TABLE_SIZE);
|
|
int currState = readImage.initialState;
|
|
if (loEncoded)
|
|
{
|
|
for (size_t i = 0; i < 3; i++)
|
|
readImage.loFreqs[i] = (*pInput)[readIndex + i];
|
|
readIndex += 3;
|
|
std::vector<int> loFreqs = unpackFrequencies(&readImage.loFreqs[0]);
|
|
size_t currCol = 0;
|
|
for (size_t i = 0; i < 16; i++)
|
|
{
|
|
for (size_t j = 0; j < loFreqs[i]; j++)
|
|
{
|
|
loDecode[currCol].state = TANS_TABLE_SIZE + currCol;
|
|
loDecode[currCol].symbol = i;
|
|
loDecode[currCol].y = loFreqs[i] + j;
|
|
int currK = 0;
|
|
while ((loDecode[currCol].y << currK) < TANS_TABLE_SIZE)
|
|
currK++;
|
|
loDecode[currCol].k = currK;
|
|
currCol++;
|
|
}
|
|
}
|
|
}
|
|
if (symEncoded)
|
|
{
|
|
for (size_t i = 0; i < 3; i++)
|
|
readImage.symFreqs[i] = (*pInput)[readIndex + i];
|
|
readIndex += 3;
|
|
std::vector<int> symFreqs = unpackFrequencies(&readImage.symFreqs[0]);
|
|
size_t currCol = 0;
|
|
for (size_t i = 0; i < 16; i++)
|
|
{
|
|
for (size_t j = 0; j < symFreqs[i]; j++)
|
|
{
|
|
symDecode[currCol].state = TANS_TABLE_SIZE + currCol;
|
|
symDecode[currCol].symbol = i;
|
|
symDecode[currCol].y = symFreqs[i] + j;
|
|
int currK = 0;
|
|
while ((symDecode[currCol].y << currK) < TANS_TABLE_SIZE)
|
|
currK++;
|
|
symDecode[currCol].k = currK;
|
|
currCol++;
|
|
}
|
|
}
|
|
}
|
|
if (loEncoded || symEncoded)
|
|
{
|
|
tANSbits.resize(readImage.bitreamSize);
|
|
for (size_t i = 0; i < readImage.bitreamSize; i++)
|
|
tANSbits[i] = (*pInput)[readIndex + i];
|
|
readIndex += readImage.bitreamSize;
|
|
allBits.resize(tANSbits.size()*32);
|
|
size_t currIndex = 0;
|
|
for (unsigned int ui : tANSbits)
|
|
{
|
|
for (size_t i = 0; i < 32; i++)
|
|
{
|
|
unsigned int currVal = (ui >> i) & 0x1;
|
|
allBits[currIndex] = currVal;
|
|
currIndex++;
|
|
}
|
|
}
|
|
}
|
|
bool leftOverValues = false;
|
|
if (!symEncoded)
|
|
{
|
|
for (size_t i = 0; i < readImage.symSize; i++)
|
|
{
|
|
symVec[i] = ((*pInput)[readIndex] >> (16*(i%2))) & 0xffff;
|
|
if ((i+1) % 2 == 0)
|
|
{
|
|
readIndex++;
|
|
leftOverValues = false;
|
|
}
|
|
else
|
|
{
|
|
leftOverValues = true;
|
|
}
|
|
}
|
|
}
|
|
if (!loEncoded)
|
|
{
|
|
size_t offsetMod = 0;
|
|
if (leftOverValues)
|
|
offsetMod = 2;
|
|
for (size_t i = 0; i < readImage.loSize; i++)
|
|
{
|
|
loVec[i] = ((*pInput)[readIndex] >> (8*((i%4) + offsetMod))) & 0xff;
|
|
if ((i+offsetMod+1) % 4 == 0)
|
|
readIndex++;
|
|
}
|
|
}
|
|
size_t bitIndex = 0;
|
|
if (loEncoded)
|
|
{
|
|
std::vector<unsigned char> loNibbles(readImage.loSize*2);
|
|
bitIndex = decodeNibbles(loDecode, &allBits, &currState, &loNibbles, bitIndex, readImage.loSize*2, !symEncoded);
|
|
for (size_t i = 0; i < readImage.loSize; i++)
|
|
loVec[i] = loNibbles[2*i] + (loNibbles[2*i + 1] << 4);
|
|
}
|
|
if (symEncoded)
|
|
{
|
|
std::vector<unsigned char> symNibbles(readImage.symSize*4);
|
|
bitIndex = decodeNibbles(symDecode, &allBits, &currState, &symNibbles, bitIndex, readImage.symSize*4, true);
|
|
if (symDelta)
|
|
deltaDecode(&symNibbles, symNibbles.size());
|
|
for (size_t i = 0; i < readImage.symSize; i++)
|
|
for (size_t j = 0; j < 4; j++)
|
|
symVec[i] += (unsigned short)symNibbles[i*4 + j] << (4*j);
|
|
}
|
|
*pOutput = decodeBytesShort(&loVec, &symVec);
|
|
}
|
|
|
|
InputSettings::InputSettings() {}
|
|
|
|
InputSettings::InputSettings(bool canEncodeLO, bool canEncodeSyms, bool canDeltaSyms)
|
|
{
|
|
this->canEncodeLO = canEncodeLO;
|
|
this->canEncodeSyms = canEncodeSyms;
|
|
this->canDeltaSyms = canDeltaSyms;
|
|
}
|
|
|
|
bool readFileAsUC(std::string filePath, std::vector<unsigned char> *pFileData)
|
|
{
|
|
std::ifstream iStream;
|
|
iStream.open(filePath.c_str(), std::ios::binary);
|
|
if (!iStream.is_open())
|
|
{
|
|
fprintf(stderr, "Error: Couldn't open %s for reading bytes\n", filePath.c_str());
|
|
return false;
|
|
}
|
|
|
|
iStream.ignore( std::numeric_limits<std::streamsize>::max() );
|
|
std::streamsize size = iStream.gcount();
|
|
iStream.clear();
|
|
iStream.seekg( 0, std::ios_base::beg );
|
|
pFileData->resize(size);
|
|
iStream.read((char *)(pFileData->data()), size);
|
|
iStream.close();
|
|
return true;
|
|
}
|
|
|
|
bool readFileAsUInt(std::string filePath, std::vector<unsigned int> *pFileData)
|
|
{
|
|
std::ifstream iStream;
|
|
iStream.open(filePath.c_str(), std::ios::binary);
|
|
if (!iStream.is_open())
|
|
{
|
|
fprintf(stderr, "Error: Couldn't open %s for reading bytes\n", filePath.c_str());
|
|
return false;
|
|
}
|
|
|
|
iStream.ignore( std::numeric_limits<std::streamsize>::max() );
|
|
std::streamsize size = iStream.gcount();
|
|
iStream.clear();
|
|
iStream.seekg( 0, std::ios_base::beg );
|
|
pFileData->resize(size/4);
|
|
iStream.read((char *)(pFileData->data()), size);
|
|
iStream.close();
|
|
return true;
|
|
}
|
|
|
|
CompressedImage processImage(std::string fileName, InputSettings settings)
|
|
{
|
|
CompressedImage image;
|
|
std::vector<unsigned char> input;
|
|
if (!readFileAsUC(fileName, &input))
|
|
{
|
|
fprintf(stderr, "Compression failure\n");
|
|
return image;
|
|
}
|
|
if (!processImageData(&input, &image, settings, fileName))
|
|
{
|
|
fprintf(stderr, "Fail\n");
|
|
}
|
|
return image;
|
|
}
|
|
|
|
// Not implemented yet
|
|
CompressedImage processImageFrames(std::string fileName, InputSettings settings)
|
|
{
|
|
CompressedImage image;
|
|
return image;
|
|
}
|
|
|
|
bool processImageData(std::vector<unsigned char> *pInput, CompressedImage *pImage, InputSettings settings, std::string fileName)
|
|
{
|
|
CompressionMode someMode;
|
|
bool hasImage = false;
|
|
bool byteFail = false;
|
|
bool copyFail = false;
|
|
bool compressionFail = false;
|
|
bool uIntConversionFail = false;
|
|
|
|
std::vector<unsigned short> usBase(pInput->size() / 2);
|
|
memcpy(usBase.data(), pInput->data(), pInput->size());
|
|
|
|
std::vector<unsigned char> bestLO;
|
|
std::vector<unsigned short> bestSym;
|
|
std::vector<ShortCompressionInstruction> bestInstructions;
|
|
|
|
for (size_t minCodeLength = 2; minCodeLength <= 15; minCodeLength++)
|
|
{
|
|
std::vector<ShortCopy> shortCopies;
|
|
if (!getShortCopies(&usBase, minCodeLength, &shortCopies))
|
|
{
|
|
copyFail = true;
|
|
printf("ERROR: %zu\n", minCodeLength);
|
|
continue;
|
|
}
|
|
|
|
std::vector<ShortCompressionInstruction> shortInstructions;
|
|
if (!getShortInstructions(&shortCopies, &shortInstructions, &usBase))
|
|
{
|
|
printf("ERROR\n");
|
|
return false;
|
|
}
|
|
|
|
std::vector<unsigned char> loVec;
|
|
std::vector<unsigned short> symVec;
|
|
getLosFromInstructions(&shortInstructions, &loVec);
|
|
getSymsFromInstructions(&shortInstructions, &symVec);
|
|
if (!verifyBytesShort(&loVec, &symVec, &usBase))
|
|
{
|
|
byteFail = true;
|
|
printf("Byte veri\n");
|
|
continue;
|
|
}
|
|
|
|
CompressionMode mode = BASE_ONLY;
|
|
std::vector<CompressionMode> modesToUse = {BASE_ONLY, ENCODE_SYMS, ENCODE_DELTA_SYMS, ENCODE_LO, ENCODE_BOTH, ENCODE_BOTH_DELTA_SYMS};
|
|
if (fileName.find("test/compression/") != std::string::npos)
|
|
{
|
|
if (fileName.find("mode_0.4bpp") != std::string::npos)
|
|
modesToUse = {BASE_ONLY};
|
|
else if (fileName.find("mode_1.4bpp") != std::string::npos)
|
|
modesToUse = {ENCODE_SYMS};
|
|
else if (fileName.find("mode_2.4bpp") != std::string::npos)
|
|
modesToUse = {ENCODE_DELTA_SYMS};
|
|
else if (fileName.find("mode_3.4bpp") != std::string::npos)
|
|
modesToUse = {ENCODE_LO};
|
|
else if (fileName.find("mode_4.4bpp") != std::string::npos)
|
|
modesToUse = {ENCODE_BOTH};
|
|
else if (fileName.find("mode_5.4bpp") != std::string::npos)
|
|
modesToUse = {ENCODE_BOTH_DELTA_SYMS};
|
|
else if (fileName.find("test/compression/table_") != std::string::npos)
|
|
modesToUse = {ENCODE_SYMS};
|
|
|
|
if (modesToUse.size() == 1)
|
|
{
|
|
settings.canDeltaSyms = true;
|
|
settings.canEncodeLO = true;
|
|
settings.canEncodeSyms = true;
|
|
}
|
|
}
|
|
for (CompressionMode currMode : modesToUse)
|
|
{
|
|
CompressedImage currImg;
|
|
mode = currMode;
|
|
if (!settings.canDeltaSyms
|
|
&& (mode == ENCODE_DELTA_SYMS
|
|
|| mode == ENCODE_BOTH_DELTA_SYMS))
|
|
continue;
|
|
if (!settings.canEncodeLO
|
|
&& (mode == ENCODE_LO
|
|
|| mode == ENCODE_BOTH
|
|
|| mode == ENCODE_BOTH_DELTA_SYMS))
|
|
continue;
|
|
if (!settings.canEncodeSyms
|
|
&& (mode == ENCODE_SYMS
|
|
|| mode == ENCODE_BOTH
|
|
|| mode == ENCODE_DELTA_SYMS
|
|
|| mode == ENCODE_BOTH_DELTA_SYMS))
|
|
continue;
|
|
if (!fillCompressVec(&loVec, &symVec, mode, pInput->size(), fileName, &currImg))
|
|
{
|
|
printf("ERROR\n");
|
|
}
|
|
|
|
if (!verifyCompressionShort(&currImg, &usBase))
|
|
{
|
|
compressionFail = true;
|
|
printf("ERROR\n");
|
|
continue;
|
|
}
|
|
std::vector<unsigned int> uiVec;
|
|
getUIntVecFromData(&currImg, &uiVec);
|
|
std::vector<unsigned short> decodedImage;
|
|
readRawDataVecs(&uiVec, &decodedImage);
|
|
if (!compareVectorsShort(&decodedImage, &usBase))
|
|
{
|
|
uIntConversionFail = true;
|
|
printf("ERROR\n");
|
|
continue;
|
|
}
|
|
currImg.compressedSize = uiVec.size() * 4;
|
|
if (!hasImage)
|
|
{
|
|
bestLO = loVec;
|
|
bestSym = symVec;
|
|
bestInstructions = shortInstructions;
|
|
*pImage = currImg;
|
|
hasImage = true;
|
|
pImage->writeVec = uiVec;
|
|
someMode = mode;
|
|
}
|
|
else if (currImg.compressedSize < pImage->compressedSize)
|
|
{
|
|
bestLO = loVec;
|
|
bestSym = symVec;
|
|
bestInstructions = shortInstructions;
|
|
*pImage = currImg;
|
|
hasImage = true;
|
|
pImage->writeVec = uiVec;
|
|
someMode = mode;
|
|
}
|
|
}
|
|
}
|
|
pImage->mode = someMode;
|
|
pImage->fileName = fileName;
|
|
pImage->rawNumBytes = pInput->size();
|
|
if (hasImage)
|
|
{
|
|
pImage->isValid = true;
|
|
}
|
|
else
|
|
{
|
|
fprintf(stderr, "Failed to compress image %s\nErrors: ", fileName.c_str());
|
|
if (copyFail)
|
|
fprintf(stderr, "CopyProcessing ");
|
|
if (byteFail)
|
|
fprintf(stderr, "ByteConversion ");
|
|
if (compressionFail)
|
|
fprintf(stderr, "Compression ");
|
|
if (uIntConversionFail)
|
|
fprintf(stderr, "uIntConversion ");
|
|
printf("\n");
|
|
}
|
|
|
|
return true;
|
|
}
|