bool OleMainStream::readParagraphStyleTable(const char *headerBuffer, const OleEntry &tableEntry) { //PlcBtePapx structure is table with formatting for all paragraphs unsigned int beginParagraphInfo = OleUtil::getU4Bytes(headerBuffer, 0x102); // address of PlcBtePapx structure std::size_t paragraphInfoLength = (std::size_t)OleUtil::getU4Bytes(headerBuffer, 0x106); // length of PlcBtePapx structure if (paragraphInfoLength < 4) { return false; } OleStream tableStream(myStorage, tableEntry, myBaseStream); std::string buffer; if (!readToBuffer(buffer, beginParagraphInfo, paragraphInfoLength, tableStream)) { return false; } static const unsigned int PAPX_SIZE = 4; std::size_t size = calcCountOfPLC(paragraphInfoLength, PAPX_SIZE); std::vector<unsigned int> paragraphBlocks; for (std::size_t index = 0, tOffset = (size + 1) * 4; index < size; ++index, tOffset += PAPX_SIZE) { paragraphBlocks.push_back(OleUtil::getU4Bytes(buffer.c_str(), tOffset)); } char *formatPageBuffer = new char[OleStorage::BBD_BLOCK_SIZE]; for (std::size_t index = 0; index < paragraphBlocks.size(); ++index) { seek(paragraphBlocks.at(index) * OleStorage::BBD_BLOCK_SIZE, true); if (read(formatPageBuffer, OleStorage::BBD_BLOCK_SIZE) != OleStorage::BBD_BLOCK_SIZE) { return false; } const unsigned int paragraphsCount = OleUtil::getU1Byte(formatPageBuffer, 0x1ff); //offset with 'cpara' value (count of paragraphs) for (unsigned int index2 = 0; index2 < paragraphsCount; ++index2) { const unsigned int offset = OleUtil::getU4Bytes(formatPageBuffer, index2 * 4); unsigned int papxOffset = OleUtil::getU1Byte(formatPageBuffer, (paragraphsCount + 1) * 4 + index2 * 13) * 2; if (papxOffset <= 0) { continue; } unsigned int len = OleUtil::getU1Byte(formatPageBuffer, papxOffset) * 2; if (len == 0) { ++papxOffset; len = OleUtil::getU1Byte(formatPageBuffer, papxOffset) * 2; } const unsigned int styleId = OleUtil::getU2Bytes(formatPageBuffer, papxOffset + 1); Style styleInfo = getStyleFromStylesheet(styleId, myStyleSheet); if (len >= 3) { getStyleInfo(papxOffset, formatPageBuffer + 3, len - 3, styleInfo); } unsigned int charPos = 0; if (!offsetToCharPos(offset, charPos, myPieces)) { continue; } myStyleInfoList.push_back(CharPosToStyle(charPos, styleInfo)); } } delete[] formatPageBuffer; return true; }
bool OleMainStream::readCharInfoTable(const char *headerBuffer, const OleEntry &tableEntry) { //PlcfbteChpx structure is table with formatting for particular run of text unsigned int beginCharInfo = OleUtil::getU4Bytes(headerBuffer, 0xfa); // address of PlcfbteChpx structure std::size_t charInfoLength = (std::size_t)OleUtil::getU4Bytes(headerBuffer, 0xfe); // length of PlcfbteChpx structure if (charInfoLength < 4) { return false; } OleStream tableStream(myStorage, tableEntry, myBaseStream); std::string buffer; if (!readToBuffer(buffer, beginCharInfo, charInfoLength, tableStream)) { return false; } static const unsigned int CHPX_SIZE = 4; std::size_t size = calcCountOfPLC(charInfoLength, CHPX_SIZE); std::vector<unsigned int> charBlocks; for (std::size_t index = 0, offset = (size + 1) * 4; index < size; ++index, offset += CHPX_SIZE) { charBlocks.push_back(OleUtil::getU4Bytes(buffer.c_str(), offset)); } char *formatPageBuffer = new char[OleStorage::BBD_BLOCK_SIZE]; for (std::size_t index = 0; index < charBlocks.size(); ++index) { seek(charBlocks.at(index) * OleStorage::BBD_BLOCK_SIZE, true); if (read(formatPageBuffer, OleStorage::BBD_BLOCK_SIZE) != OleStorage::BBD_BLOCK_SIZE) { return false; } unsigned int crun = OleUtil::getU1Byte(formatPageBuffer, 0x1ff); //offset with crun (count of 'run of text') for (unsigned int index2 = 0; index2 < crun; ++index2) { unsigned int offset = OleUtil::getU4Bytes(formatPageBuffer, index2 * 4); unsigned int chpxOffset = 2 * OleUtil::getU1Byte(formatPageBuffer, (crun + 1) * 4 + index2); unsigned int len = OleUtil::getU1Byte(formatPageBuffer, chpxOffset); unsigned int charPos = 0; if (!offsetToCharPos(offset, charPos, myPieces)) { continue; } unsigned int styleId = getStyleIdByCharPos(charPos, myStyleInfoList); CharInfo charInfo = getStyleFromStylesheet(styleId, myStyleSheet).CurrentCharInfo; if (chpxOffset != 0) { getCharInfo(chpxOffset, styleId, formatPageBuffer + 1, len - 1, charInfo); } myCharInfoList.push_back(CharPosToCharInfo(charPos, charInfo)); if (chpxOffset != 0) { InlineImageInfo pictureInfo; if (getInlineImageInfo(chpxOffset, formatPageBuffer + 1, len - 1, pictureInfo)) { myInlineImageInfoList.push_back(CharPosToInlineImageInfo(charPos, pictureInfo)); } } } } delete[] formatPageBuffer; return true; }
bool OleMainStream::readFloatingImages(const char *headerBuffer, const OleEntry &tableEntry) { //Plcspa structure is a table with information for FSPA (File Shape Address) unsigned int beginPicturesInfo = OleUtil::getU4Bytes(headerBuffer, 0x01DA); // address of Plcspa structure if (beginPicturesInfo == 0) { return true; //there's no office art objects } unsigned int picturesInfoLength = OleUtil::getU4Bytes(headerBuffer, 0x01DE); // length of Plcspa structure if (picturesInfoLength < 4) { return false; } OleStream tableStream(myStorage, tableEntry, myBaseStream); std::string buffer; if (!readToBuffer(buffer, beginPicturesInfo, picturesInfoLength, tableStream)) { return false; } static const unsigned int SPA_SIZE = 26; size_t size = calcCountOfPLC(picturesInfoLength, SPA_SIZE); std::vector<unsigned int> picturesBlocks; for (size_t index = 0, tOffset = 0; index < size; ++index, tOffset += 4) { picturesBlocks.push_back(OleUtil::getU4Bytes(buffer.c_str(), tOffset)); } for (size_t index = 0, tOffset = (size + 1) * 4; index < size; ++index, tOffset += SPA_SIZE) { unsigned int spid = OleUtil::getU4Bytes(buffer.c_str(), tOffset); FloatImageInfo info; unsigned int charPos = picturesBlocks.at(index); info.ShapeId = spid; myFloatImageInfoList.push_back(CharPosToFloatImageInfo(charPos, info)); } //DggInfo structure is office art object table data unsigned int beginOfficeArtContent = OleUtil::getU4Bytes(headerBuffer, 0x22A); // address of DggInfo structure if (beginOfficeArtContent == 0) { return true; //there's no office art objects } unsigned int officeArtContentLength = OleUtil::getU4Bytes(headerBuffer, 0x022E); // length of DggInfo structure if (officeArtContentLength < 4) { return false; } shared_ptr<OleStream> newTableStream = new OleStream(myStorage, tableEntry, myBaseStream); shared_ptr<OleStream> newMainStream = new OleStream(myStorage, myOleEntry, myBaseStream); if (newTableStream->open() && newMainStream->open()) { myFLoatImageReader = new DocFloatImageReader(beginOfficeArtContent, officeArtContentLength, newTableStream, newMainStream); myFLoatImageReader->readAll(); } return true; }
bool OleMainStream::readSectionsInfoTable(const char *headerBuffer, const OleEntry &tableEntry) { //PlcfSed structure is a section table unsigned int beginOfText = OleUtil::getU4Bytes(headerBuffer, 0x18); //address of text's begin in main stream unsigned int beginSectInfo = OleUtil::getU4Bytes(headerBuffer, 0xca); //address if PlcfSed structure std::size_t sectInfoLen = (std::size_t)OleUtil::getU4Bytes(headerBuffer, 0xce); //length of PlcfSed structure if (sectInfoLen < 4) { return false; } OleStream tableStream(myStorage, tableEntry, myBaseStream); std::string buffer; if (!readToBuffer(buffer, beginSectInfo, sectInfoLen, tableStream)) { return false; } static const unsigned int SED_SIZE = 12; std::size_t decriptorsCount = calcCountOfPLC(sectInfoLen, SED_SIZE); //saving the section offsets (in character positions) std::vector<unsigned int> charPos; for (std::size_t index = 0, tOffset = 0; index < decriptorsCount; ++index, tOffset += 4) { unsigned int ulTextOffset = OleUtil::getU4Bytes(buffer.c_str(), tOffset); charPos.push_back(beginOfText + ulTextOffset); } //saving sepx offsets std::vector<unsigned int> sectPage; for (std::size_t index = 0, tOffset = (decriptorsCount + 1) * 4; index < decriptorsCount; ++index, tOffset += SED_SIZE) { sectPage.push_back(OleUtil::getU4Bytes(buffer.c_str(), tOffset + 2)); } //reading the section properties char tmpBuffer[2]; for (std::size_t index = 0; index < sectPage.size(); ++index) { if (sectPage.at(index) == 0xffffffffUL) { //check for invalid record, to make default section info SectionInfo sectionInfo; sectionInfo.CharPosition = charPos.at(index); mySectionInfoList.push_back(sectionInfo); continue; } //getting number of bytes to read if (!seek(sectPage.at(index), true)) { continue; } if (read(tmpBuffer, 2) != 2) { continue; } std::size_t bytes = 2 + (std::size_t)OleUtil::getU2Bytes(tmpBuffer, 0); if (!seek(sectPage.at(index), true)) { continue; } char *formatPageBuffer = new char[bytes]; if (read(formatPageBuffer, bytes) != bytes) { delete[] formatPageBuffer; continue; } SectionInfo sectionInfo; sectionInfo.CharPosition = charPos.at(index); getSectionInfo(formatPageBuffer + 2, bytes - 2, sectionInfo); mySectionInfoList.push_back(sectionInfo); delete[] formatPageBuffer; } return true; }
bool OleMainStream::readStylesheet(const char *headerBuffer, const OleEntry &tableEntry) { //STSH structure is a stylesheet unsigned int beginStshInfo = OleUtil::getU4Bytes(headerBuffer, 0xa2); // address of STSH structure std::size_t stshInfoLength = (std::size_t)OleUtil::getU4Bytes(headerBuffer, 0xa6); // length of STSH structure OleStream tableStream(myStorage, tableEntry, myBaseStream); char *buffer = new char[stshInfoLength]; if (!tableStream.seek(beginStshInfo, true)) { ZLLogger::Instance().println("DocPlugin", "problems with reading STSH structure"); return false; } if (tableStream.read(buffer, stshInfoLength) != stshInfoLength) { ZLLogger::Instance().println("DocPlugin", "problems with reading STSH structure, invalid length"); return false; } std::size_t stdCount = (std::size_t)OleUtil::getU2Bytes(buffer, 2); std::size_t stdBaseInFile = (std::size_t)OleUtil::getU2Bytes(buffer, 4); myStyleSheet.resize(stdCount); std::vector<bool> isFilled; isFilled.resize(stdCount, false); std::size_t stdLen = 0; bool styleSheetWasChanged = false; do { //make it in while loop, because some base style can be after their successors styleSheetWasChanged = false; for (std::size_t index = 0, offset = 2 + (std::size_t)OleUtil::getU2Bytes(buffer, 0); index < stdCount; index++, offset += 2 + stdLen) { stdLen = (std::size_t)OleUtil::getU2Bytes(buffer, offset); if (isFilled.at(index)) { continue; } if (stdLen == 0) { //if record is empty, left it default isFilled[index] = true; continue; } Style styleInfo = myStyleSheet.at(index); const unsigned int styleAndBaseType = OleUtil::getU2Bytes(buffer, offset + 4); const unsigned int styleType = styleAndBaseType % 16; const unsigned int baseStyleId = styleAndBaseType / 16; if (baseStyleId == Style::STYLE_NIL || baseStyleId == Style::STYLE_USER) { //if based on nil or user style, left default } else { int baseStyleIndex = getStyleIndex(baseStyleId, isFilled, myStyleSheet); if (baseStyleIndex < 0) { //this base style is not filled yet, so pass it at some time continue; } styleInfo = myStyleSheet.at(baseStyleIndex); styleInfo.StyleIdCurrent = Style::STYLE_INVALID; } // parse STD structure unsigned int tmp = OleUtil::getU2Bytes(buffer, offset + 6); unsigned int upxCount = tmp % 16; styleInfo.StyleIdNext = tmp / 16; //adding current style myStyleSheet[index] = styleInfo; isFilled[index] = true; styleSheetWasChanged = true; std::size_t pos = 2 + stdBaseInFile; std::size_t nameLen = (std::size_t)OleUtil::getU2Bytes(buffer, offset + pos); nameLen = nameLen * 2 + 2; //from Unicode characters to bytes + Unicode null charachter length pos += 2 + nameLen; if (pos % 2 != 0) { ++pos; } if (pos >= stdLen) { continue; } std::size_t upxLen = (std::size_t)OleUtil::getU2Bytes(buffer, offset + pos); if (pos + upxLen > stdLen) { //UPX length too large continue; } //for style info styleType must be equal 1 if (styleType == 1 && upxCount >= 1) { if (upxLen >= 2) { styleInfo.StyleIdCurrent = OleUtil::getU2Bytes(buffer, offset + pos + 2); getStyleInfo(0, buffer + offset + pos + 4, upxLen - 2, styleInfo); myStyleSheet[index] = styleInfo; } pos += 2 + upxLen; if (pos % 2 != 0) { ++pos; } upxLen = (std::size_t)OleUtil::getU2Bytes(buffer, offset + pos); } if (upxLen == 0 || pos + upxLen > stdLen) { //too small/too large continue; } //for char info styleType can be equal 1 or 2 if ((styleType == 1 && upxCount >= 2) || (styleType == 2 && upxCount >= 1)) { CharInfo charInfo; getCharInfo(0, Style::STYLE_INVALID, buffer + offset + pos + 2, upxLen, charInfo); styleInfo.CurrentCharInfo = charInfo; myStyleSheet[index] = styleInfo; } } } while (styleSheetWasChanged); delete[] buffer; return true; }
bool OleMainStream::readBookmarks(const char *headerBuffer, const OleEntry &tableEntry) { //SttbfBkmk structure is a table of bookmark name strings unsigned int beginNamesInfo = OleUtil::getU4Bytes(headerBuffer, 0x142); // address of SttbfBkmk structure std::size_t namesInfoLength = (std::size_t)OleUtil::getU4Bytes(headerBuffer, 0x146); // length of SttbfBkmk structure if (namesInfoLength == 0) { return true; //there's no bookmarks } OleStream tableStream(myStorage, tableEntry, myBaseStream); std::string buffer; if (!readToBuffer(buffer, beginNamesInfo, namesInfoLength, tableStream)) { return false; } unsigned int recordsNumber = OleUtil::getU2Bytes(buffer.c_str(), 0x2); //count of records std::vector<std::string> names; unsigned int offset = 0x6; //initial offset for (unsigned int i = 0; i < recordsNumber; ++i) { if (buffer.size() < offset + 2) { ZLLogger::Instance().println("DocPlugin", "problmes with reading bookmarks names"); break; } unsigned int length = OleUtil::getU2Bytes(buffer.c_str(), offset) * 2; //length of string in bytes ZLUnicodeUtil::Ucs2String name; for (unsigned int j = 0; j < length; j+=2) { char ch1 = buffer.at(offset + 2 + j); char ch2 = buffer.at(offset + 2 + j + 1); ZLUnicodeUtil::Ucs2Char ucs2Char = (unsigned int)ch1 | ((unsigned int)ch2 << 8); name.push_back(ucs2Char); } std::string utf8Name; ZLUnicodeUtil::ucs2ToUtf8(utf8Name, name); names.push_back(utf8Name); offset += length + 2; } //plcfBkmkf structure is table recording beginning CPs of bookmarks unsigned int beginCharPosInfo = OleUtil::getU4Bytes(headerBuffer, 0x14A); // address of plcfBkmkf structure std::size_t charPosInfoLen = (std::size_t)OleUtil::getU4Bytes(headerBuffer, 0x14E); // length of plcfBkmkf structure if (charPosInfoLen == 0) { return true; //there's no bookmarks } if (!readToBuffer(buffer, beginCharPosInfo, charPosInfoLen, tableStream)) { return false; } static const unsigned int BKF_SIZE = 4; std::size_t size = calcCountOfPLC(charPosInfoLen, BKF_SIZE); std::vector<unsigned int> charPage; for (std::size_t index = 0, offset = 0; index < size; ++index, offset += 4) { charPage.push_back(OleUtil::getU4Bytes(buffer.c_str(), offset)); } for (std::size_t i = 0; i < names.size(); ++i) { if (i >= charPage.size()) { break; //for the case if something in these structures goes wrong, to not to lose all bookmarks } Bookmark bookmark; bookmark.CharPosition = charPage.at(i); bookmark.Name = names.at(i); myBookmarks.push_back(bookmark); } return true; }
bool OleMainStream::readPieceTable(const char *headerBuffer, const OleEntry &tableEntry) { OleStream tableStream(myStorage, tableEntry, myBaseStream); std::string piecesTableBuffer = getPiecesTableBuffer(headerBuffer, tableStream); if (piecesTableBuffer.empty()) { return false; } //getting count of Character Positions for different types of subdocuments in Main Stream int ccpText = OleUtil::get4Bytes(headerBuffer, 0x004C); //text int ccpFtn = OleUtil::get4Bytes(headerBuffer, 0x0050); //footnote subdocument int ccpHdd = OleUtil::get4Bytes(headerBuffer, 0x0054); //header subdocument int ccpMcr = OleUtil::get4Bytes(headerBuffer, 0x0058); //macro subdocument int ccpAtn = OleUtil::get4Bytes(headerBuffer, 0x005C); //comment subdocument int ccpEdn = OleUtil::get4Bytes(headerBuffer, 0x0060); //endnote subdocument int ccpTxbx = OleUtil::get4Bytes(headerBuffer, 0x0064); //textbox subdocument int ccpHdrTxbx = OleUtil::get4Bytes(headerBuffer, 0x0068); //textbox subdocument of the header int lastCP = ccpFtn + ccpHdd + ccpMcr + ccpAtn + ccpEdn + ccpTxbx + ccpHdrTxbx; if (lastCP != 0) { ++lastCP; } lastCP += ccpText; //getting the CP (character positions) and CP descriptors std::vector<int> cp; //array of character positions for pieces unsigned int j = 0; for (j = 0; ; j += 4) { if (piecesTableBuffer.size() < j + 4) { ZLLogger::Instance().println("DocPlugin", "invalid piece table, cp ends not with a lastcp"); break; } int curCP = OleUtil::get4Bytes(piecesTableBuffer.c_str(), j); cp.push_back(curCP); if (curCP == lastCP) { break; } } if (cp.size() < 2) { ZLLogger::Instance().println("DocPlugin", "invalid piece table, < 2 pieces"); return false; } std::vector<std::string> descriptors; for (std::size_t k = 0; k < cp.size() - 1; ++k) { //j + 4, because it should be taken after CP in PiecesTable Buffer //k * 8, because it should be taken 8 byte for each descriptor std::size_t substrFrom = j + 4 + k * 8; if (piecesTableBuffer.size() < substrFrom + 8) { ZLLogger::Instance().println("DocPlugin", "invalid piece table, problems with descriptors reading"); break; } descriptors.push_back(piecesTableBuffer.substr(substrFrom, 8)); } //filling the Pieces vector std::size_t minValidSize = std::min(cp.size() - 1, descriptors.size()); if (minValidSize == 0) { ZLLogger::Instance().println("DocPlugin", "invalid piece table, there are no pieces"); return false; } for (std::size_t i = 0; i < minValidSize; ++i) { //4byte integer with offset and ANSI flag int fcValue = OleUtil::get4Bytes(descriptors.at(i).c_str(), 0x2); //offset for piece structure Piece piece; piece.IsANSI = (fcValue & 0x40000000) == 0x40000000; //ansi flag piece.Offset = fcValue & 0x3FFFFFFF; //gettting offset for current piece piece.Length = cp.at(i + 1) - cp.at(i); myPieces.push_back(piece); } //split pieces into different types Pieces piecesText, piecesFootnote, piecesOther; splitPieces(myPieces, piecesText, piecesFootnote, Piece::PIECE_TEXT, Piece::PIECE_FOOTNOTE, ccpText); splitPieces(piecesFootnote, piecesFootnote, piecesOther, Piece::PIECE_FOOTNOTE, Piece::PIECE_OTHER, ccpFtn); myPieces.clear(); for (std::size_t i = 0; i < piecesText.size(); ++i) { myPieces.push_back(piecesText.at(i)); } for (std::size_t i = 0; i < piecesFootnote.size(); ++i) { myPieces.push_back(piecesFootnote.at(i)); } for (std::size_t i = 0; i < piecesOther.size(); ++i) { myPieces.push_back(piecesOther.at(i)); } //converting length and offset depending on isANSI for (std::size_t i = 0; i < myPieces.size(); ++i) { Piece &piece = myPieces.at(i); if (!piece.IsANSI) { piece.Length *= 2; } else { piece.Offset /= 2; } } //filling startCP field unsigned int curStartCP = 0; for (std::size_t i = 0; i < myPieces.size(); ++i) { Piece &piece = myPieces.at(i); piece.startCP = curStartCP; if (piece.IsANSI) { curStartCP += piece.Length; } else { curStartCP += piece.Length / 2; } } return true; }
bool HuffmanCoder::LoadHuffmanTableFromFile(const char* fileName) { if (mDebug > kInfo) std::cout << "Huffman table will be loaded from file " << fileName << std::endl; if (mHuffmanTableExists) { if (mDebug > kWarning) std::cout << "WARNING: Huffman table is already available" << std::endl; return true; } std::ifstream tableStream(fileName,std::ios::in); if (tableStream.is_open()) { std::string temp; getline(tableStream,temp,'\n'); // Skip first lines of file while (temp != "Huffman codes:") getline(tableStream,temp,'\n'); int value = 0; int length = 0; float weight = 0; std::string code = ""; std::string truncatedHuffmanMarkerCandidate = ""; // read file and parse the lines do { // read line getline(tableStream,temp,'\n'); // parse values value = atoi(temp.substr(temp.find("=")+1,temp.find("weight")).c_str()); temp = temp.substr(temp.find("weight")); weight = atof(temp.substr(temp.find("=")+1,temp.find("length")).c_str()); temp = temp.substr(temp.find("length")); length = atoi(temp.substr(temp.find("=")+1,temp.find("code")).c_str()); temp = temp.substr(temp.find("code")); code = temp.substr(temp.find("=")+1); code = code.substr(code.size()-length); // // Look for raw data marker in file // if (value == 0 && weight != 0) { // mRawDataMarker = code; // mRawDataMarkerSize = code.size(); // } // Store Huffman code in map HuffmanCode hCode(value, length, weight, code); if (mHuffmanTable.find(value) == mHuffmanTable.end()) { mHuffmanTable[value] = hCode; } else { if (mDebug > kWarning) std::cout << "WARNING: Huffman code for value " << value << " exists already in Huffman table" << std::endl; } // if Huffman code is short enough, it is stored in the truncated Huffman table if ((unsigned int) length <= mMaxCodeLength) { if (mTruncatedHuffmanTable.find(value) == mTruncatedHuffmanTable.end()) { mTruncatedHuffmanTable[value] = hCode; } else { if (mDebug > kWarning) std::cout << "WARNING: Huffman code for value " << value << " exists already in truncated Huffman table" << std::endl; } } else if ((unsigned int) length < truncatedHuffmanMarkerCandidate.size() || truncatedHuffmanMarkerCandidate.size() == 0) { // else, a possible marker is stored truncatedHuffmanMarkerCandidate = code; } } while ((unsigned int) value < (mHuffmanRange-1)); // done, closing file, creating raw data marker if not found and return if (mDebug > kInfo) std::cout << "Reading of Huffman table done." << std::endl; tableStream.close(); if (mRawDataMarkerSize == 0) { // if no raw data marker was found, one of the shortest codes which were thrown away // is used. mRawDataMarker = truncatedHuffmanMarkerCandidate; mRawDataMarkerSize = mRawDataMarker.size(); if (mDebug > kWarning) std::cout << "WARNING: No raw data marker was found, it is set to " << mRawDataMarker << std::endl; } mHuffmanTableExists = true; mMapToUse = &mTruncatedHuffmanTable; mMarkerToUse = mRawDataMarker; mMarkerLengthToUse = mRawDataMarkerSize; return true; } else { if (mDebug > kError) std::cerr << "ERROR: Could not open file " << fileName << " to read the Huffman Table, no table is loaded!" << std::endl; return false; } }