#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 *pInput, size_t minLength, std::vector *pShortCopies) { size_t iteration = 0; std::vector 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 *pCopies, std::vector *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 *pCopies, std::vector *pInstructions, std::vector *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 *pInstructions, std::vector *pOutput) { for (ShortCompressionInstruction instruction : (*pInstructions)) { for (unsigned char uc : instruction.loBytes) pOutput->push_back(uc); } } void getSymsFromInstructions(std::vector *pInstructions, std::vector *pOutput) { for (ShortCompressionInstruction instruction : (*pInstructions)) { for (unsigned short us : instruction.symShorts) pOutput->push_back(us); } } void ShortCompressionInstruction::buildBytes(std::vector *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 *pLoVec, std::vector *pSymVec, std::vector *pImage) { std::vector 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 *pVec1, std::vector *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 getNormalizedCounts(std::vector *input) { std::vector 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 returnVec(16); for (size_t i = 0; i < 16; i++) returnVec[i] = tempVec[i]; return returnVec; } std::vector getFreqWriteInts(std::vector input) { std::vector 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 getTestFreqs(std::vector 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 *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 *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 decodeTable, std::vector *bits, int *currState, std::vector *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 getNewHeaders(CompressionMode mode, size_t imageSize, size_t symLength, int initialState, size_t bitstreamSize, size_t loLength) { if (initialState == -1) initialState = 0; std::vector 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 *pLoVec, std::vector *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 loNibbles(2 * pLoVec->size()); std::vector symNibbles(4 * pSymVec->size()); std::vector loDecode; std::vector symDecode; std::vector 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 loCounts(16); for (unsigned char uc : loNibbles) loCounts[uc]++; std::vector loFreqs = getNormalizedCounts(&loCounts); std::vector 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 symCounts(16); if (symDelta) deltaEncode(&symNibbles, symNibbles.size()); for (unsigned char uc : symNibbles) symCounts[uc]++; std::vector symFreqs = getNormalizedCounts(&symCounts); symFreqs = getTestFreqs(symFreqs, name); std::vector 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 bitstream; if (symEncoded) { std::vector reversedVec; for (size_t i = 0; i < symNibbles.size(); i++) reversedVec.push_back(symNibbles[symNibbles.size() - i - 1]); std::vector 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 reversedVec; for (size_t i = 0; i < loNibbles.size(); i++) reversedVec.push_back(loNibbles[loNibbles.size() - i - 1]); std::vector 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 reversedBitstream(bitstream.size()); for (size_t i = 0; i < bitstream.size(); i++) reversedBitstream[reversedBitstream.size() - 1 - i] = bitstream[i]; bitstream = reversedBitstream; std::vector checkBits = bitstream; int checkState = currState; size_t currBitIndex = 0; if (loEncoded) { bool lastThing = !symEncoded; std::vector 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 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 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 *pImage) { std::vector decodedImage = decodeImageShort(pInput); return compareVectorsShort(&decodedImage, pImage); } std::vector decodeImageShort(CompressedImage *pInput) { DataVecs dataVecs = decodeDataVectorsNew(pInput); return decodeBytesShort(&dataVecs.loVec, &dataVecs.symVec); } std::vector decodeBytesShort(std::vector *pLoVec, std::vector *pSymVec) { std::vector 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 symbols = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; std::vector loDecode; std::vector symDecode; std::vector loVec(loSize); std::vector symVec(symSize); std::vector loNibbles(loSize*2); std::vector symNibbles(symSize*4); if (loEncoded) { std::vector loFreqs = unpackFrequencies(&pInput->loFreqs[0]); loDecode = createDecodingTable(symbols, loFreqs); } if (symEncoded) { std::vector symFreqs = unpackFrequencies(&pInput->symFreqs[0]); symDecode = createDecodingTable(symbols, symFreqs); } std::vector 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 *pInput, CompressedImage *pOutput) { std::vector 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 unpackFrequencies(unsigned int pInts[3]) { std::vector 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 *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 *pInput, std::vector *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 tANSbits; std::vector allBits; std::vector symVec(readImage.symSize); std::vector loVec(readImage.loSize); std::vector symDecode(TANS_TABLE_SIZE); std::vector 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 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 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 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 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 *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::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 *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::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 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 *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 usBase(pInput->size() / 2); memcpy(usBase.data(), pInput->data(), pInput->size()); std::vector bestLO; std::vector bestSym; std::vector bestInstructions; for (size_t minCodeLength = 2; minCodeLength <= 15; minCodeLength++) { std::vector shortCopies; if (!getShortCopies(&usBase, minCodeLength, &shortCopies)) { copyFail = true; printf("ERROR: %zu\n", minCodeLength); continue; } std::vector shortInstructions; if (!getShortInstructions(&shortCopies, &shortInstructions, &usBase)) { printf("ERROR\n"); return false; } std::vector loVec; std::vector 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 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 uiVec; getUIntVecFromData(&currImg, &uiVec); std::vector 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; }