#include "compressAlgo.h" std::vector getShortCopies(std::vector input, size_t minLength) { std::vector copies; for (size_t startIndex = 1; startIndex < input.size(); startIndex++) { size_t longestLength = 0; size_t longestOffset; for (size_t searchOffset = 1; searchOffset <= startIndex && searchOffset < 32767; searchOffset++) { size_t currLength = 0; while (input[startIndex + currLength] == input[startIndex + currLength - searchOffset] && startIndex + currLength < input.size()) currLength++; if (currLength > longestLength) { longestLength = currLength; longestOffset = searchOffset; } } if (longestLength > 32767) longestLength = 32767; if (longestLength >= minLength) { std::vector::const_iterator start = input.begin() + startIndex; std::vector::const_iterator end = input.begin() + startIndex + longestLength; copies.push_back(ShortCopy(startIndex, longestLength, longestOffset, std::vector(start, end))); copies[copies.size() - 1].firstSymbol = input[startIndex - 1]; startIndex += longestLength; } } std::vector checkVec(input.size()); for (ShortCopy copy : copies) for (size_t i = 0; i <= copy.length; i++) checkVec[copy.index + i - 1]++; size_t currStart = 0; size_t currLength = 1; unsigned short prevSym = checkVec[0]; for (size_t i = 1; i < checkVec.size(); i++) { unsigned short currSym = checkVec[i]; if (currSym == 0 && prevSym == 0) currLength++; else if (currSym == 0 && prevSym == 1) { currStart = i; currLength = 1; } else if (currSym == 1 && prevSym == 0) { std::vector::const_iterator start = input.begin() + currStart; std::vector::const_iterator end = input.begin() + currStart + currLength; copies.push_back(ShortCopy(currStart, currLength, 0, std::vector(start, end))); } prevSym = currSym; } if (prevSym == 0) { std::vector::const_iterator start = input.begin() + currStart; std::vector::const_iterator end = input.begin() + currStart + currLength; copies.push_back(ShortCopy(currStart, currLength, 0, std::vector(start, end))); } return copies; } bool verifyShortCopies(std::vector *pCopies, std::vector *pImage) { std::vector decodedImage(pImage->size()); for (ShortCopy copy : (*pCopies)) { if (copy.offset == 0) { for (size_t i = 0; i < copy.length; i++) decodedImage[copy.index + i] = copy.usSequence[i]; } else { decodedImage[copy.index - 1] = copy.firstSymbol; for (size_t i = 0; i < copy.length; i++) decodedImage[copy.index + i] = (*pImage)[copy.index + i - copy.offset]; } } for (size_t i = 0; i < decodedImage.size(); i++) if (decodedImage[i] != (*pImage)[i]) return false; return true; } SortedShortElement::SortedShortElement() {} SortedShortElement::SortedShortElement(size_t index, ShortCopy copy) { this->index = index; this->copy = copy; isCopy = true; } std::vector getShortInstructions(std::vector copies, size_t lengthMod) { std::vector instructions; std::vector unsortedElements; std::vector sortedElements; for (ShortCopy copy : copies) unsortedElements.push_back(SortedShortElement(copy.index, copy)); while (unsortedElements.size() != 0) { size_t smallestIndex = 0; for (size_t i = 0; i < unsortedElements.size(); i++) { if (unsortedElements[i].index < unsortedElements[smallestIndex].index) { smallestIndex = i; } } sortedElements.push_back(unsortedElements[smallestIndex]); unsortedElements.erase(unsortedElements.begin() + smallestIndex); } for (size_t i = 0; i < sortedElements.size(); i++) { ShortCompressionInstruction currInstruction; currInstruction.index = sortedElements[i].index; currInstruction.offset = sortedElements[i].copy.offset; currInstruction.length = sortedElements[i].copy.length; currInstruction.symbols = sortedElements[i].copy.usSequence; currInstruction.firstSymbol = sortedElements[i].copy.firstSymbol; currInstruction.buildBytes(); instructions.push_back(currInstruction); } return instructions; } void ShortCompressionInstruction::buildBytes() { 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 (unsigned short currSymbol : symbols) symShorts.push_back(currSymbol); } } void CompressionInstruction::buildBytes() { std::vector currBytes; if (offset != 0) { size_t currLength = length; currBytes.push_back(currLength & 0x7f); currLength = currLength >> 7; if (currLength != 0) { currBytes[currBytes.size() - 1] += 128; currBytes.push_back(currLength & 0xff); } size_t currOffset = offset; currBytes.push_back(currOffset & 0x7f); currOffset = currOffset >> 7; if (currOffset != 0) { currBytes[currBytes.size() - 1] += 128; currBytes.push_back(currOffset & 0xff); } currBytes.push_back(firstSymbol); } else { currBytes.push_back(0); size_t currLength = length; currBytes.push_back(currLength & 0x7f); currLength = currLength >> 7; if (currLength != 0) { currBytes[currBytes.size() - 1] += 128; currBytes.push_back(currLength & 0xff); } for (unsigned char currSymbol : symbols) currBytes.push_back(currSymbol); } bytes = currBytes; } std::vector getLosFromInstructions(std::vector instructions) { std::vector loVec; for (ShortCompressionInstruction instruction : instructions) { for (unsigned char uc : instruction.loBytes) loVec.push_back(uc); } return loVec; } std::vector getSymsFromInstructions(std::vector instructions) { std::vector symvec; for (ShortCompressionInstruction instruction : instructions) { for (unsigned short uc : instruction.symShorts) symvec.push_back(uc); } return 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; } bool verifyBytesShort(std::vector *pLoVec, std::vector *pSymVec, std::vector *pImage) { std::vector shorts = decodeBytesShort(pLoVec, pSymVec); return compareVectorsShort(&shorts, pImage); } 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; } std::vector readFileAsUC(std::string filePath) { 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 std::vector(0); } iStream.ignore( std::numeric_limits::max() ); std::streamsize size = iStream.gcount(); iStream.clear(); iStream.seekg( 0, std::ios_base::beg ); std::vector ucVec(size); iStream.read((char*)(&ucVec[0]), size); iStream.close(); return ucVec; } CompressedImage processImage(std::string fileName, InputSettings settings) { CompressedImage image; std::vector input = readFileAsUC(fileName); if (settings.useFrames) { /* // Determine number of frames size_t totalPixels = input.size()*2; // Split input and append size_t smallFrames = totalPixels/OVERWORLD_16X16; size_t largeFrames = totalPixels/OVERWORLD_32X32; */ } else { image = processImageData(input, settings, fileName); } return image; } CompressedImage processImageFrames(std::string fileName, InputSettings settings) { CompressedImage image; std::vector input = readFileAsUC(fileName); std::vector> allInputs(4); size_t totalSize = input.size(); size_t partialSize = totalSize/4; size_t subIndex = 0; size_t inputIndex = 0; std::vector frameOffsets; for (unsigned char currChar : input) { frameOffsets.push_back(image.otherBits.size()); if (subIndex == partialSize) { subIndex = 0; inputIndex++; } allInputs[inputIndex].push_back(currChar); subIndex++; } for (size_t i = 0; i < 4; i++) { CompressedImage tempImage = processImageData(allInputs[i], settings, fileName); for (unsigned int currVal : tempImage.writeVec) image.otherBits.push_back(currVal); } unsigned int header = IS_FRAME_CONTAINER; image.writeVec.push_back(header); for (size_t i = 0; i < 4; i++) image.writeVec.push_back((unsigned int)frameOffsets[i]); for (unsigned int currVal : image.otherBits) image.writeVec.push_back(currVal); image.isValid = true; return image; } CompressedImage processImageData(std::vector input, InputSettings settings, std::string fileName) { CompressedImage bestImage; CompressionMode someMode; bool hasImage = false; std::vector rawBase = input; std::vector usBase(rawBase.size()/2); memcpy(usBase.data(), rawBase.data(), rawBase.size()); size_t baseLZsize = 0; bool byteFail = false; bool copyFail = false; bool compressionFail = false; bool uIntConversionFail = false; if (settings.shouldCompare) { std::string lzName = fileName + ".lz"; baseLZsize = getFileSize(lzName); } std::vector bestLO; std::vector bestSym; std::vector bestInstructions; for (size_t minCodeLength = 2; minCodeLength <= 15; minCodeLength++) { std::vector shortCopies = getShortCopies(usBase, minCodeLength); if (!verifyShortCopies(&shortCopies, &usBase)) { copyFail = true; continue; } std::vector shortInstructions = getShortInstructions(shortCopies, minCodeLength-1); std::vector loVec = getLosFromInstructions(shortInstructions); std::vector symVec = getSymsFromInstructions(shortInstructions); if (!verifyBytesShort(&loVec, &symVec, &usBase)) { byteFail = true; continue; } CompressionMode mode = BASE_ONLY; //std::vector modesToUse = {ENCODE_SYMS}; 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) { 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; CompressedImage image = fillCompressVecNew(loVec, symVec, mode,rawBase.size(), fileName); if (!verifyCompressionShort(&image, &usBase)) { compressionFail = true; continue; } std::vector uiVec = getUIntVecFromData(&image); std::vector decodedImage = readRawDataVecs(&uiVec); if (!compareVectorsShort(&decodedImage, &usBase)) { uIntConversionFail = true; continue; } image.compressedSize = uiVec.size() * 4; if (!hasImage) { bestLO = loVec; bestSym = symVec; bestInstructions = shortInstructions; bestImage = image; hasImage = true; bestImage.writeVec = uiVec; someMode = mode; } else if (image.compressedSize < bestImage.compressedSize) { bestLO = loVec; bestSym = symVec; bestInstructions = shortInstructions; bestImage = image; hasImage = true; bestImage.writeVec = uiVec; someMode = mode; } } } bestImage.mode = someMode; bestImage.fileName = fileName; bestImage.lzSize = baseLZsize; bestImage.rawNumBytes = rawBase.size(); if (hasImage) bestImage.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 bestImage; } CompressedImage getDataFromUIntVec(std::vector *pInput) { CompressedImage image = readNewHeader(pInput); size_t readIndex = 2; bool loEncoded = isModeLoEncoded(image.mode); bool symEncoded = isModeSymEncoded(image.mode); if (loEncoded) { image.loFreqs[0] = (*pInput)[readIndex]; image.loFreqs[1] = (*pInput)[readIndex + 1]; image.loFreqs[2] = (*pInput)[readIndex + 2]; readIndex += 3; } if (symEncoded) { image.symFreqs[0] = (*pInput)[readIndex]; image.symFreqs[1] = (*pInput)[readIndex + 1]; image.symFreqs[2] = (*pInput)[readIndex + 2]; readIndex += 3; } if (loEncoded || symEncoded) { for (size_t i = 0; i < image.bitreamSize; i++) { image.tANSbits.push_back((*pInput)[readIndex]); readIndex++; } } std::vector remainders; while (readIndex < pInput->size()) { unsigned int currInt = (*pInput)[readIndex]; for (size_t i = 0; i < 4; i++) remainders.push_back((currInt >> (8*i)) & 0xff); readIndex++; } size_t remIndex = 0; if (!symEncoded) { for (size_t i = 0; i < image.symSize; i++) { unsigned short currSym = remainders[remIndex]; remIndex++; currSym += remainders[remIndex] << 8; remIndex++; image.symVec.push_back(currSym); } } if (!loEncoded) { for (size_t i = 0; i < image.loSize; i++) { unsigned char currChar = remainders[remIndex]; remIndex++; image.loVec.push_back(currChar); } } return image; } 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); } DataVecs decodeDataVectorsNew(CompressedImage *pInput) { CompressedImage headerValues = readNewHeader(&pInput->headers); 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 loFreqs = unpackFrequencies(&pInput->loFreqs[0]); std::vector symFreqs = unpackFrequencies(&pInput->symFreqs[0]); 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) { loDecode = createDecodingTable(symbols, loFreqs); } if (symEncoded) { 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); } 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); 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 analyzeImages(std::vector *allImages, std::mutex *imageMutex, FileDispatcher *dispatcher, std::mutex *dispatchMutex, InputSettings settings) { std::string fileName = "Initial Value"; while (fileName != "") { dispatchMutex->lock(); fileName = dispatcher->requestFileName(); dispatchMutex->unlock(); if (fileName == "") break; std::string uncompressedFileName = fileName.substr(0, fileName.size()-3); CompressedImage currImage = processImage(uncompressedFileName, settings); imageMutex->lock(); allImages->push_back(currImage); imageMutex->unlock(); } } ShortCopy::ShortCopy() {} ShortCopy::ShortCopy(size_t index, size_t length, size_t offset, std::vector usSequence) { this->index = index; this->length = length; this->offset = offset; this->usSequence = usSequence; } 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 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; } 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; } /* mode 5 state 6 11 bitstream 12 23 8628 max so far, divide by 4 loLength 12 23 2922 max so far symLength 14 37 14k max so far imageSize 10 47 16384 max so far, divide by 16 u32:5 mode+lz u32:10 image size, divided by 32 u32:14 symlength, divided by 2 u32:6 state u32:12 bitstream, in ints u32:12 loLength, in bytes */ 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 return returnVec; } CompressedImage readNewHeader(std::vector *pInput) { CompressedImage image; std::vector headers(2); headers[0] = (*pInput)[0]; headers[1] = (*pInput)[1]; image.mode = (CompressionMode)(headers[0] & MODE_MASK); image.rawNumBytes = ((headers[0] >> IMAGE_SIZE_OFFSET) & IMAGE_SIZE_MASK) * IMAGE_SIZE_MODIFIER; image.symSize = ((headers[0] >> SYM_SIZE_OFFSET) & SYM_SIZE_MASK); image.initialState = headers[1] & INITIAL_STATE_MASK; image.bitreamSize = (headers[1] >> BITSTREAM_SIZE_OFFSET) & BITSTREAM_SIZE_MASK; image.loSize = (headers[1] >> LO_SIZE_OFFSET) & LO_SIZE_MASK; image.headers = headers; return image; } InputSettings::InputSettings() {} InputSettings::InputSettings(bool canEncodeLO, bool canEncodeSyms, bool canDeltaSyms) { this->canEncodeLO = canEncodeLO; this->canEncodeSyms = canEncodeSyms; this->canDeltaSyms = canDeltaSyms; } std::vector getUIntVecFromData(CompressedImage *pImage) { CompressedImage otherImage = readNewHeader(&pImage->headers); std::vector returnVec; returnVec.push_back(pImage->headers[0]); returnVec.push_back(pImage->headers[1]); if (isModeLoEncoded(otherImage.mode)) for (size_t i = 0; i < 3; i++) returnVec.push_back(pImage->loFreqs[i]); if (isModeSymEncoded(otherImage.mode)) for (size_t i = 0; i < 3; i++) returnVec.push_back(pImage->symFreqs[i]); if (isModeLoEncoded(otherImage.mode) || isModeSymEncoded(otherImage.mode)) for (unsigned int ui : pImage->tANSbits) returnVec.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) { returnVec.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) { returnVec.push_back(currInt); currInt = 0; } } } if (currOffset != 0) returnVec.push_back(currInt); return returnVec; } bool verifyUIntVecShort(std::vector *pInput, std::vector *pImage) { CompressedImage image = getDataFromUIntVec(pInput); return verifyCompressionShort(&image, pImage); } std::vector readFileAsUInt(std::string filePath) { std::vector returnVec; std::vector ucVec; std::ifstream iStream; iStream.open(filePath.c_str(), std::ios::binary); if (!iStream.is_open()) { fprintf(stderr, "Error: Couldn't open file %s for reading\n", filePath.c_str()); return returnVec; } iStream.ignore( std::numeric_limits::max() ); std::streamsize size = iStream.gcount(); ucVec.resize(size); iStream.clear(); iStream.seekg( 0, std::ios_base::beg ); iStream.read((char*)(&ucVec[0]), size); iStream.close(); unsigned int *pUInt = reinterpret_cast(ucVec.data()); for (size_t i = 0; i < ucVec.size()/4; i++) returnVec.push_back(pUInt[i]); return returnVec; } 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; } CompressedImage fillCompressVecNew(std::vector loVec, std::vector symVec, CompressionMode mode, size_t imageBytes, std::string name) { CompressedImage image; bool loEncoded = isModeLoEncoded(mode); bool symEncoded = isModeSymEncoded(mode); bool symDelta = isModeSymDelta(mode); std::vector loNibbles(2*loVec.size()); std::vector symNibbles(4*symVec.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 < loVec.size(); i++) { loNibbles[2*i] = (loVec)[i] & 0xf; loNibbles[2*i + 1] = ((loVec)[i] >> 4) & 0xf; } std::vector loCounts(16); for (unsigned char uc : loNibbles) loCounts[uc]++; std::vector loFreqs = getNormalizedCounts(loCounts); std::vector freqs = getFreqWriteInts(loFreqs); image.loFreqs[0] = freqs[0]; image.loFreqs[1] = freqs[1]; image.loFreqs[2] = freqs[2]; loDecode = createDecodingTable(symbols, loFreqs); } if (symEncoded) { for (size_t i = 0; i < symVec.size(); i++) { for (size_t j = 0; j < 4; j++) symNibbles[4*i + j] = (symVec[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); image.symFreqs[0] = freqs[0]; image.symFreqs[1] = freqs[1]; image.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) { std::vector checkLoNibbles(loNibbles.size()); currBitIndex = decodeNibbles(loDecode, &checkBits, &checkState, &checkLoNibbles, currBitIndex, loNibbles.size()); 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()); 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); image.headers = getNewHeaders(mode, imageBytes, symVec.size(), currState, tANSbits.size(), loVec.size()); image.tANSbits = tANSbits; image.symVec = symVec; image.loVec = loVec; image.initialState = currState; return image; } size_t decodeNibbles(std::vector decodeTable, std::vector *bits, int *currState, std::vector *nibbleVec, size_t currBitIndex, size_t numNibbles) { for (size_t i = 0; i < numNibbles; i++) { (*nibbleVec)[i] = decodeTable[*currState].symbol; 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 readRawDataVecs(std::vector *pInput) { std::vector imageVec; CompressedImage readImage = readNewHeader(pInput); 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); 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); 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); } imageVec = decodeBytesShort(&loVec, &symVec); return imageVec; } 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]; } } 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; }