MetaFillregionRecord::MetaFillregionRecord(QIODevice &device) : MetafileRecord(device) { if((this->getRecordFunction() & 0x00FF) != (META_FILLREGION & 0x00FF)) { throw std::runtime_error("Not a META_FILLREGION record"); } this->region = readUnsignedWord(device); this->brush = readUnsignedWord(device); }
BitmapCoreHeaderObject::BitmapCoreHeaderObject(QIODevice &device) { this->headerSize = readUnsignedDWord(device); if(this->headerSize != 12) { throw std::runtime_error("Invalid bitmap core header size"); } this->width = readUnsignedWord(device); this->height = readUnsignedWord(device); this->planes = readUnsignedWord(device); if(this->planes != 1) { throw std::runtime_error("Invalid bitmap planes count"); } this->bitCount = readUnsignedWord(device); }
BTreeIndexEntry::BTreeIndexEntry(QFile &file, qint64 off) { PRINT_DBG("Reading BTree index entry at %lld", off); seekFile(file, off); QTextCodec *codec = getDefaultTextCodec(); qint64 length = 0; this->fileName = readNullTerminatedString(file, codec, length); PRINT_DBG(" Filename: %s", this->fileName.toLocal8Bit().data()); this->pageNumber = readUnsignedWord(file); PRINT_DBG(" Page Number: %d", this->pageNumber); this->sz = length + Q_INT64_C(2); PRINT_DBG(" BTree index entry size: %lld", this->sz); PRINT_DBG("BTree index entry loaded successfully"); }
quint16 readCompressedUnsignedWord(QIODevice &device) { qint64 pos = device.pos(); quint8 lowByte = readUnsignedByte(device); if((lowByte & 1) != 0) { seekFile(device, pos); return readUnsignedWord(device) / 2; } else { return static_cast<quint16>(lowByte) / 2; } }
MetaCreatepatternbrushRecord::MetaCreatepatternbrushRecord(QIODevice &device) : MetafileRecord(device), patternBits() { this->type = readUnsignedWord(device); this->width = readUnsignedWord(device); this->height = readUnsignedWord(device); this->widthBytes = readUnsignedWord(device); this->planes = readUnsignedByte(device); if(this->planes != 1) { throw std::runtime_error("Invalid patternBitsLength value"); } this->bitsPerPixel = readUnsignedByte(device); seekDevice(device, Q_INT64_C(22)); quint16 wb = (this->width * static_cast<quint16>(this->bitsPerPixel) + 15)/16; quint16 realWidthBytes = wb * 2; if(realWidthBytes != this->widthBytes) { throw std::runtime_error("Invalid widthBytes value"); } this->patternBitsLength = this->widthBytes * this->height; QScopedArrayPointer<quint8>(new quint8[this->patternBitsLength]).swap(this->patternBits); fillBuffer(device, static_cast<qint64>(this->patternBitsLength), reinterpret_cast<void *>(this->patternBits.data()), static_cast<size_t>(this->patternBitsLength)); }
MetaPolylineRecord::MetaPolylineRecord(QIODevice &device) : MetafileRecord(device) { if((this->getRecordFunction() & 0x00FF) != (META_POLYLINE & 0x00FF)) { throw std::runtime_error("Not a META_POLYLINE record"); } this->numberOfPoints = readUnsignedWord(device); if(numberOfPoints > 0) { this->points = QVector<QPoint>(this->numberOfPoints); for(quint16 i = 0; i < this->numberOfPoints; i++) { this->points[i] = readPointShort(device); } } }
qint32 readCompressedSignedDWord(QIODevice &device) { qint64 pos = device.pos(); quint8 lowByte = readUnsignedByte(device); if((lowByte & 1) != 0) { seekFile(device, pos); return static_cast<qint32>((static_cast<qint64>(readUnsignedDWord( device)) - Q_INT64_C(0x80000000)) / Q_INT64_C(2)); } else { seekFile(device, pos); return static_cast<qint32>((static_cast<qint64>(readUnsignedWord(device)) - Q_INT64_C(0x8000)) / Q_INT64_C(2)); } }
NewFontDescriptor::NewFontDescriptor(QFile &file, qint64 off) : FontDescriptor(NEW_FONT_DESCRIPTOR) { PRINT_DBG("Reading New font descriptor at %lld", off); seekFile(file, off); quint8 unknownByte1 = readUnsignedByte(file); PRINT_DBG(" Unknown byte 1: %d", unknownByte1); this->facenameIndex = readUnsignedWord(file); PRINT_DBG(" Facename index: %d", this->facenameIndex); this->fgColor = readRGBBytes(file); PRINT_DBG(" Fg Red: %d", qRed(this->fgColor)); PRINT_DBG(" Fg Green: %d", qGreen(this->fgColor)); PRINT_DBG(" Fg Blue: %d", qBlue(this->fgColor)); this->bgColor = readRGBBytes(file); PRINT_DBG(" Bg Red: %d", qRed(this->bgColor)); PRINT_DBG(" Bg Green: %d", qGreen(this->bgColor)); PRINT_DBG(" Bg Blue: %d", qBlue(this->bgColor)); quint8 unknownBytes2[5] = { 0, 0, 0, 0, 0 }; fillBuffer(file, Q_INT64_C( 5), reinterpret_cast<void *>(&unknownBytes2), static_cast<size_t>(5)); PRINT_DBG(" Unknown byte 2-1: %d", unknownBytes2[0]); PRINT_DBG(" Unknown byte 2-2: %d", unknownBytes2[1]); PRINT_DBG(" Unknown byte 2-3: %d", unknownBytes2[2]); PRINT_DBG(" Unknown byte 2-4: %d", unknownBytes2[3]); PRINT_DBG(" Unknown byte 2-5: %d", unknownBytes2[4]); this->height = readSignedDWord(file); PRINT_DBG(" Height: %d", this->height); this->width = readSignedDWord(file); PRINT_DBG(" Width: %d", this->width); this->escapement = readSignedDWord(file); PRINT_DBG(" Escapement: %d", this->escapement); this->orientation = readSignedDWord(file); PRINT_DBG(" Orientation: %d", this->orientation); this->weight = readSignedDWord(file); PRINT_DBG(" Weight: %d", this->weight); quint8 italicByte = readUnsignedByte(file); this->italic = false; if(italicByte != 0) { this->italic = true; PRINT_DBG(" Italic font"); } quint8 underlineByte = readUnsignedByte(file); this->underline = false; if(underlineByte != 0) { this->underline = true; PRINT_DBG(" Underline font"); } quint8 strikeoutByte = readUnsignedByte(file); this->strikeOut = false; if(strikeoutByte != 0) { this->strikeOut = true; PRINT_DBG(" Strike out font"); } this->charset = readUnsignedByte(file); PRINT_DBG(" Charset: %d", this->charset); this->outPrecision = readUnsignedByte(file); PRINT_DBG(" Out precision: %d", this->outPrecision); this->clipPrecision = readUnsignedByte(file); PRINT_DBG(" Clip precision: %d", this->clipPrecision); this->quality = readUnsignedByte(file); PRINT_DBG(" Quality: %d", this->quality); quint8 pitchAndFamily = readUnsignedByte(file); this->pitch = pitchAndFamily & 0x03; PRINT_DBG(" Pitch: %d", this->pitch); this->family = (((pitchAndFamily & 0xF0) >> 4) & 0x0F); PRINT_DBG(" Family: %d", this->family); PRINT_DBG("New font descriptor loaded successfully"); }
WindowHpjRecord::WindowHpjRecord(QFile &file, qint64 off, QTextCodec *codec) { PRINT_DBG("Reading WindowHpj record at %lld", off); seekFile(file, off); SystemRecordHeader hdr(file, off); if (hdr.getRecordSize() < Q_INT64_C(90)) { qDebug() << "WindowHpj record size is too small: " << hdr.getRecordSize(); } quint8 flagsLIn = readUnsignedByte(file); PRINT_DBG(" Flags low byte: %d", flagsLIn); this->typeIsValid = false; if ((flagsLIn & 0x1) != 0) { this->typeIsValid = true; PRINT_DBG(" Window type field is valid"); } ; this->nameIsValid = false; if ((flagsLIn & 0x2) != 0) { this->nameIsValid = true; PRINT_DBG(" Window name field is valid"); } ; this->captionIsValid = false; if ((flagsLIn & 0x4) != 0) { this->captionIsValid = true; PRINT_DBG(" Window caption field is valid"); } ; this->xIsValid = false; if ((flagsLIn & 0x8) != 0) { this->xIsValid = true; PRINT_DBG(" X field is valid"); } ; this->yIsValid = false; if ((flagsLIn & 0x10) != 0) { this->yIsValid = true; PRINT_DBG(" Y field is valid"); } ; this->widthIsValid = false; if ((flagsLIn & 0x20) != 0) { this->widthIsValid = true; PRINT_DBG(" Width field is valid"); } ; this->heightIsValid = false; if ((flagsLIn & 0x40) != 0) { this->heightIsValid = true; PRINT_DBG(" Height type field is valid"); } ; this->maximizeWindow = false; if ((flagsLIn & 0x80) != 0) { this->maximizeWindow = true; PRINT_DBG(" Maximize field is valid"); } ; quint8 flagsHIn = readUnsignedByte(file); PRINT_DBG(" Flags high byte: %d", flagsHIn); this->rgbIsValid = false; if ((flagsHIn & 0x1) != 0) { this->rgbIsValid = true; PRINT_DBG(" RGB field is valid"); } ; this->rgbNsrIsValid = false; if ((flagsHIn & 0x2) != 0) { this->rgbNsrIsValid = true; PRINT_DBG(" RGB nsr field is valid"); } ; this->windowsAlwaysOnTop = false; if ((flagsHIn & 0x4) != 0) { this->windowsAlwaysOnTop = true; PRINT_DBG(" Window always on top flag is set"); } ; this->autoSizeHeight = false; if ((flagsHIn & 0x8) != 0) { this->autoSizeHeight = true; PRINT_DBG(" Auto size height flag is set"); } ; this->windowType = readFixedLengthString(file, 10, codec); PRINT_DBG(" Window type: %s", this->windowType.toLocal8Bit().data()); this->windowName = readFixedLengthString(file, 9, codec); PRINT_DBG(" Window name: %s", this->windowName.toLocal8Bit().data()); this->windowCaption = readFixedLengthString(file, 51, codec); PRINT_DBG(" Window caption: %s", this->windowCaption.toLocal8Bit().data()); this->x = readUnsignedWord(file); PRINT_DBG(" X: %d", this->x); this->y = readUnsignedWord(file); PRINT_DBG(" Y: %d", this->y); this->width = readUnsignedWord(file); PRINT_DBG(" Width: %d", this->width); this->height = readUnsignedWord(file); PRINT_DBG(" Height: %d", this->height); this->maximize = readUnsignedWord(file); PRINT_DBG(" Maximize: %d", this->maximize); this->rgbColor = readRGBDword(file); PRINT_DBG(" Red: %d", qRed(this->rgbColor)); PRINT_DBG(" Green: %d", qGreen(this->rgbColor)); PRINT_DBG(" Blue: %d", qBlue(this->rgbColor)); this->rgbNsrColor = readRGBDword(file); PRINT_DBG(" Red nsr: %d", qRed(this->rgbNsrColor)); PRINT_DBG(" Green nsr: %d", qGreen(this->rgbNsrColor)); PRINT_DBG(" Blue nsr: %d", qBlue(this->rgbNsrColor)); PRINT_DBG("WindowHpj record loaded successfully"); }
MetafileRecord::MetafileRecord(QIODevice &device) { this->recordSizeInWords = readUnsignedDWord(device); this->recordFunction = readUnsignedWord(device); bool validRecordType = false; switch(this->recordFunction & 0x00FF) { case (META_EOF & 0x00FF): validRecordType = true; break; case (META_REALIZEPALETTE & 0x00FF): validRecordType = true; break; case (META_SETPALENTRIES & 0x00FF): validRecordType = true; break; case (META_SETBKMODE & 0x00FF): validRecordType = true; break; case (META_SETMAPMODE & 0x00FF): validRecordType = true; break; case (META_SETROP2 & 0x00FF): validRecordType = true; break; case (META_SETRELABS & 0x00FF): validRecordType = true; break; case (META_SETPOLYFILLMODE & 0x00FF): validRecordType = true; break; case (META_SETSTRETCHBLTMODE & 0x00FF): validRecordType = true; break; case (META_SETTEXTCHAREXTRA & 0x00FF): validRecordType = true; break; case (META_RESTOREDC & 0x00FF): validRecordType = true; break; case (META_RESIZEPALETTE & 0x00FF): validRecordType = true; break; case (META_DIBCREATEPATTERNBRUSH & 0x00FF): validRecordType = true; break; case (META_SETLAYOUT & 0x00FF): validRecordType = true; break; case (META_SETBKCOLOR & 0x00FF): validRecordType = true; break; case (META_SETTEXTCOLOR & 0x00FF): validRecordType = true; break; case (META_OFFSETVIEWPORTORG & 0x00FF): validRecordType = true; break; case (META_LINETO & 0x00FF): validRecordType = true; break; case (META_MOVETO & 0x00FF): validRecordType = true; break; case (META_OFFSETCLIPRGN & 0x00FF): validRecordType = true; break; case (META_FILLREGION & 0x00FF): validRecordType = true; break; case (META_SETMAPPERFLAGS & 0x00FF): validRecordType = true; break; case (META_SELECTPALETTE & 0x00FF): validRecordType = true; break; case (META_POLYGON & 0x00FF): validRecordType = true; break; case (META_POLYLINE & 0x00FF): validRecordType = true; break; case (META_SETTEXTJUSTIFICATION & 0x00FF): validRecordType = true; break; case (META_SETWINDOWORG & 0x00FF): validRecordType = true; break; case (META_SETWINDOWEXT & 0x00FF): validRecordType = true; break; case (META_SETVIEWPORTORG & 0x00FF): validRecordType = true; break; case (META_SETVIEWPORTEXT & 0x00FF): validRecordType = true; break; case (META_OFFSETWINDOWORG & 0x00FF): validRecordType = true; break; case (META_SCALEWINDOWEXT & 0x00FF): validRecordType = true; break; case (META_SCALEVIEWPORTEXT & 0x00FF): validRecordType = true; break; case (META_EXCLUDECLIPRECT & 0x00FF): validRecordType = true; break; case (META_INTERSECTCLIPRECT & 0x00FF): validRecordType = true; break; case (META_ELLIPSE & 0x00FF): validRecordType = true; break; case (META_FLOODFILL & 0x00FF): validRecordType = true; break; case (META_FRAMEREGION & 0x00FF): validRecordType = true; break; case (META_ANIMATEPALETTE & 0x00FF): validRecordType = true; break; case (META_TEXTOUT & 0x00FF): validRecordType = true; break; case (META_POLYPOLYGON & 0x00FF): validRecordType = true; break; case (META_EXTFLOODFILL & 0x00FF): validRecordType = true; break; case (META_RECTANGLE & 0x00FF): validRecordType = true; break; case (META_SETPIXEL & 0x00FF): validRecordType = true; break; case (META_ROUNDRECT & 0x00FF): validRecordType = true; break; case (META_PATBLT & 0x00FF): validRecordType = true; break; case (META_SAVEDC & 0x00FF): validRecordType = true; break; case (META_PIE & 0x00FF): validRecordType = true; break; case (META_STRETCHBLT & 0x00FF): validRecordType = true; break; case (META_ESCAPE & 0x00FF): validRecordType = true; break; case (META_INVERTREGION & 0x00FF): validRecordType = true; break; case (META_PAINTREGION & 0x00FF): validRecordType = true; break; case (META_SELECTCLIPREGION & 0x00FF): validRecordType = true; break; case (META_SELECTOBJECT & 0x00FF): validRecordType = true; break; case (META_SETTEXTALIGN & 0x00FF): validRecordType = true; break; case (META_ARC & 0x00FF): validRecordType = true; break; case (META_CHORD & 0x00FF): validRecordType = true; break; case (META_BITBLT & 0x00FF): validRecordType = true; break; case (META_EXTTEXTOUT & 0x00FF): validRecordType = true; break; case (META_SETDIBTODEV & 0x00FF): validRecordType = true; break; case (META_DIBBITBLT & 0x00FF): validRecordType = true; break; case (META_DIBSTRETCHBLT & 0x00FF): validRecordType = true; break; case (META_STRETCHDIB & 0x00FF): validRecordType = true; break; case (META_DELETEOBJECT & 0x00FF): validRecordType = true; break; case (META_CREATEPALETTE & 0x00FF): validRecordType = true; break; case (META_CREATEPATTERNBRUSH & 0x00FF): validRecordType = true; break; case (META_CREATEPENINDIRECT & 0x00FF): validRecordType = true; break; case (META_CREATEFONTINDIRECT & 0x00FF): validRecordType = true; break; case (META_CREATEBRUSHINDIRECT & 0x00FF): validRecordType = true; break; case (META_CREATEREGION & 0x00FF): validRecordType = true; break; default: validRecordType = false; }; if(!validRecordType) { throw std::runtime_error("Invalid record function"); } }
WinHelpPhraseFile::WinHelpPhraseFile(QFile &file, qint64 off, QTextCodec *codec, bool compressed, bool mvbHint) : phrases(), phrasesRaw() { PRINT_DBG("Loading WinHelp phrase file at %lld", off); if (codec == NULL) { throw std::runtime_error("Codec is NULL"); } seekFile(file, off); InternalDirectoryFileHeader hdr(file, off); if (compressed) { if (mvbHint) { seekFile(file, off + InternalDirectoryFileHeader::size); quint16 eightHundr = readUnsignedWord(file); quint16 nPhr = readUnsignedWord(file); quint16 oneHundr = readUnsignedWord(file); if ((eightHundr == 0x0800) && (oneHundr == 0x0100) && (nPhr != 0)) { PRINT_DBG( "Loading compressed WinHelp phrase file, MVB alternative"); seekFile(file, off + InternalDirectoryFileHeader::size); quint16 eightHundred = readUnsignedWord(file); PRINT_DBG(" Eight hundred: %d", eightHundred); quint16 numPhrases = readUnsignedWord(file); PRINT_DBG(" Num phrases: %d", numPhrases); quint16 oneHundred = readUnsignedWord(file); PRINT_DBG(" One hundred: %d", oneHundred); if (oneHundred != 0x0100) { throw std::runtime_error("Not a WinHelp phrase file"); } quint32 uncompressedSize = readUnsignedDWord(file); PRINT_DBG(" Uncompressed size: %d", uncompressedSize); for (int i = 0; i < 30; i++) { quint8 unused = readUnsignedByte(file); PRINT_DBG(" Unused: %d", unused); } QScopedArrayPointer<uint> phraseOffset( new uint[static_cast<size_t> (numPhrases + 1)]); PRINT_DBG("Reading phrase offsets at %lld", file.pos()); for (quint16 index = 0; index < numPhrases + 1; index++) { phraseOffset[index] = static_cast<uint> (readUnsignedWord( file)); PRINT_DBG(" Phrase offset: %d", phraseOffset[index]); } qint64 inputLength = off + hdr.getReservedSpace() - file.pos(); PRINT_DBG("Reading compressed phrases at %lld", file.pos()); QScopedArrayPointer<quint8> uncompressedPhrases( new quint8[static_cast<size_t> (uncompressedSize)]); unpackLZ77(file, file.pos(), inputLength, uncompressedPhrases.data(), static_cast<size_t> (uncompressedSize)); size_t pointer = static_cast<size_t> (0); for (quint16 index = 0; index < numPhrases; index++) { uint size = phraseOffset[index + 1] - phraseOffset[index]; QString phrase = readFixedLengthStringFromBuffer( uncompressedPhrases.data(), static_cast<size_t> (uncompressedSize), pointer, size, codec); this->phrases.append(phrase); QScopedArrayPointer<quint8> phraseRaw( new quint8[static_cast<size_t> (size)]); copyBytesFromBuffer( reinterpret_cast<const void *> (uncompressedPhrases. data()), static_cast<size_t> (uncompressedSize), pointer, static_cast<size_t> (size), reinterpret_cast<void *> (phraseRaw.data()), static_cast<size_t> (size)); this->phrasesRaw.append(QByteArray( reinterpret_cast<const char *> (phraseRaw.data()), static_cast<int> (size))); pointer += static_cast<size_t> (size); PRINT_DBG(" Phrase: %s", phrase.toLocal8Bit().data()); } } else { PRINT_DBG("Loading compressed WinHelp phrase file"); seekFile(file, off + InternalDirectoryFileHeader::size); quint16 numPhrases = readUnsignedWord(file); PRINT_DBG(" Num phrases: %d", numPhrases); quint16 oneHundred = readUnsignedWord(file); PRINT_DBG(" One hundred: %d", oneHundred); if (oneHundred != 0x0100) { throw std::runtime_error("Not a WinHelp phrase file"); } quint32 uncompressedSize = readUnsignedDWord(file); PRINT_DBG(" Uncompressed size: %d", uncompressedSize); QScopedArrayPointer<uint> phraseOffset( new uint[static_cast<size_t> (numPhrases + 1)]); PRINT_DBG("Reading phrase offsets at %lld", file.pos()); for (quint16 index = 0; index < numPhrases + 1; index++) { phraseOffset[index] = static_cast<uint> (readUnsignedWord( file)); PRINT_DBG(" Phrase offset: %d", phraseOffset[index]); } PRINT_DBG("Reading compressed phrases at %lld", file.pos()); qint64 inputLength = off + hdr.getReservedSpace() - file.pos(); QScopedArrayPointer<quint8> uncompressedPhrases( new quint8[static_cast<size_t> (uncompressedSize)]); unpackLZ77(file, file.pos(), inputLength, uncompressedPhrases.data(), static_cast<size_t> (uncompressedSize)); size_t pointer = static_cast<size_t> (0); for (quint16 index = 0; index < numPhrases; index++) { uint size = phraseOffset[index + 1] - phraseOffset[index]; QString phrase = readFixedLengthStringFromBuffer( uncompressedPhrases.data(), static_cast<size_t> (uncompressedSize), pointer, size, codec); this->phrases.append(phrase); QScopedArrayPointer<quint8> phraseRaw( new quint8[static_cast<size_t> (size)]); copyBytesFromBuffer( reinterpret_cast<const void *> (uncompressedPhrases. data()), static_cast<size_t> (uncompressedSize), pointer, static_cast<size_t> (size), reinterpret_cast<void *> (phraseRaw.data()), static_cast<size_t> (size)); this->phrasesRaw.append(QByteArray( reinterpret_cast<const char *> (phraseRaw.data()), static_cast<int> (size))); pointer += static_cast<size_t> (size); PRINT_DBG(" Phrase: %s", phrase.toLocal8Bit().data()); } } } else { PRINT_DBG("Loading compressed WinHelp phrase file"); seekFile(file, off + InternalDirectoryFileHeader::size); quint16 numPhrases = readUnsignedWord(file); PRINT_DBG(" Num phrases: %d", numPhrases); quint16 oneHundred = readUnsignedWord(file); PRINT_DBG(" One hundred: %d", oneHundred); if (oneHundred != 0x0100) { throw std::runtime_error("Not a WinHelp phrase file"); } quint32 uncompressedSize = readUnsignedDWord(file); PRINT_DBG(" Uncompressed size: %d", uncompressedSize); QScopedArrayPointer<uint> phraseOffset( new uint[static_cast<size_t> (numPhrases + 1)]); PRINT_DBG("Reading phrase offsets at %lld", file.pos()); for (quint16 index = 0; index < numPhrases + 1; index++) { phraseOffset[index] = static_cast<uint> (readUnsignedWord(file)); PRINT_DBG(" Phrase offset: %d", phraseOffset[index]); } PRINT_DBG("Reading compressed phrases at %lld", file.pos()); qint64 inputLength = off + hdr.getReservedSpace() - file.pos(); QScopedArrayPointer<quint8> uncompressedPhrases( new quint8[static_cast<size_t> (uncompressedSize)]); unpackLZ77(file, file.pos(), inputLength, uncompressedPhrases.data(), static_cast<size_t> (uncompressedSize)); size_t pointer = static_cast<size_t> (0); for (quint16 index = 0; index < numPhrases; index++) { uint size = phraseOffset[index + 1] - phraseOffset[index]; QString phrase = readFixedLengthStringFromBuffer( uncompressedPhrases.data(), static_cast<size_t> (uncompressedSize), pointer, size, codec); this->phrases.append(phrase); QScopedArrayPointer<quint8> phraseRaw( new quint8[static_cast<size_t> (size)]); copyBytesFromBuffer( reinterpret_cast<const void *> (uncompressedPhrases.data()), static_cast<size_t> (uncompressedSize), pointer, static_cast<size_t> (size), reinterpret_cast<void *> (phraseRaw.data()), static_cast<size_t> (size)); this->phrasesRaw.append(QByteArray( reinterpret_cast<const char *> (phraseRaw.data()), static_cast<int> (size))); pointer += static_cast<size_t> (size); PRINT_DBG(" Phrase: %s", phrase.toLocal8Bit().data()); } } } else { PRINT_DBG("Loading uncompressed WinHelp phrase file"); seekFile(file, off + InternalDirectoryFileHeader::size); quint16 numPhrases = readUnsignedWord(file); PRINT_DBG(" Num phrases: %d", numPhrases); quint16 oneHundred = readUnsignedWord(file); PRINT_DBG(" One hundred: %d", oneHundred); if (oneHundred != 0x0100) { throw std::runtime_error("Not a WinHelp phrase file"); } QScopedArrayPointer<uint> phraseOffset( new uint[static_cast<size_t> (numPhrases + 1)]); PRINT_DBG("Reading phrase offsets at %lld", file.pos()); for (quint16 index = 0; index < numPhrases + 1; index++) { phraseOffset[index] = static_cast<uint> (readUnsignedWord(file)); PRINT_DBG(" Phrase offset: %d", phraseOffset[index]); } PRINT_DBG("Reading phrases at %lld", file.pos()); for (quint16 index = 0; index < numPhrases; index++) { uint size = phraseOffset[index + 1] - phraseOffset[index]; qint64 posMem = file.pos(); QString phrase = readFixedLengthString(file, size, codec); this->phrases.append(phrase); QScopedArrayPointer<quint8> phraseRaw( new quint8[static_cast<size_t> (size)]); seekFile(file, posMem); fillBuffer(file, static_cast<qint64> (size), reinterpret_cast<void *> (phraseRaw.data()), static_cast<size_t> (size)); this->phrasesRaw.append(QByteArray( reinterpret_cast<const char *> (phraseRaw.data()), static_cast<int> (size))); PRINT_DBG(" Phrase: %s", phrase.toLocal8Bit().data()); } } PRINT_DBG("WinHelp phrase file loaded successfully"); }
static unsigned long readUnsignedDWord(ZLInputStream &stream) { unsigned long lowPart = readUnsignedWord(stream); unsigned long highPart = readUnsignedWord(stream); return (highPart << 16) + lowPart; }
bool CHMFileInfo::init(ZLInputStream &stream) { { // header start if (readString(stream, 4) != "ITSF") { return false; } unsigned long version = readUnsignedDWord(stream); // DWORD total length // DWORD unknown // DWORD timestamp // DWORD language id // 0x10 bytes 1st GUID // 0x10 bytes 2nd GUID // QWORD section 0 offset // QWORD section 0 length stream.seek(4 * 4 + 2 * 0x10 + 2 * 8, false); unsigned long long sectionOffset1 = readUnsignedQWord(stream); unsigned long long sectionLength1 = readUnsignedQWord(stream); mySection0Offset = sectionOffset1 + sectionLength1; // header end // additional header data start if (version > 2) { mySection0Offset = readUnsignedQWord(stream); } // additional header data end stream.seek(sectionOffset1, true); // header section 1 start // directory header start if (readString(stream, 4) != "ITSP") { return false; } // DWORD version // DWORD length // DWORD 0x000A // DWORD chunk size // DWORD density // DWORD depth // DWORD root chunk number // DWORD first chunk number // DWORD last chunk number // DWORD -1 stream.seek(10 * 4, false); unsigned long dirChunkNumber = readUnsignedDWord(stream); // ... stream.seek(36, false); // header section 1 end std::size_t nextOffset = stream.offset(); for (unsigned long i = 0; i < dirChunkNumber; ++i) { nextOffset += 4096; std::string header = readString(stream, 4); if (header == "PMGL") { unsigned long quickRefAreaSize = readUnsignedDWord(stream) % 4096; stream.seek(12, false); std::size_t startOffset = stream.offset(); std::size_t oldOffset = startOffset; while (startOffset < nextOffset - quickRefAreaSize) { int nameLength = readEncodedInteger(stream); std::string name = readString(stream, nameLength); int contentSection = readEncodedInteger(stream); int offset = readEncodedInteger(stream); int length = readEncodedInteger(stream); if (name.substr(0, 2) != "::") { name = ZLUnicodeUtil::toLower(name); } myRecords.insert( std::make_pair( name, CHMFileInfo::RecordInfo(contentSection, offset, length) ) ); startOffset = stream.offset(); if (oldOffset == startOffset) { break; } oldOffset = startOffset; } } else if (header == "PMGI") { unsigned long quickRefAreaSize = readUnsignedDWord(stream); std::size_t startOffset = stream.offset(); std::size_t oldOffset = startOffset; while (startOffset < nextOffset - quickRefAreaSize) { int nameLength = readEncodedInteger(stream); std::string name = readString(stream, nameLength); // chunk number readEncodedInteger(stream); startOffset = stream.offset(); if (oldOffset == startOffset) { break; } oldOffset = startOffset; } } stream.seek(nextOffset, true); if (stream.offset() != nextOffset) { break; } } } { if (!moveToEntry(stream, "::DataSpace/NameList")) { return false; } stream.seek(2, false); const int sectionNumber = readUnsignedWord(stream); for (int i = 0; i < sectionNumber; ++i) { const int length = readUnsignedWord(stream); std::string sectionName; sectionName.reserve(length); for (int j = 0; j < length; ++j) { sectionName += (char)readUnsignedWord(stream); } stream.seek(2, false); mySectionNames.push_back(sectionName); } } { for (unsigned int i = 1; i < mySectionNames.size(); ++i) { RecordMap::const_iterator it = myRecords.find("::DataSpace/Storage/" + mySectionNames[i] + "/Content"); if (it == myRecords.end()) { return false; } RecordInfo recordInfo = it->second; if (recordInfo.Section != 0) { return false; } mySectionInfos.push_back(SectionInfo()); SectionInfo &info = mySectionInfos.back(); info.Offset = mySection0Offset + recordInfo.Offset; info.Length = recordInfo.Length; if (!moveToEntry(stream, "::DataSpace/Storage/" + mySectionNames[i] + "/ControlData")) { return false; } stream.seek(4, false); std::string lzxc = readString(stream, 4); if (lzxc != "LZXC") { return false; } const int version = readUnsignedDWord(stream); if ((version <= 0) || (version > 2)) { return false; } info.ResetInterval = readUnsignedDWord(stream); if (version == 1) { info.ResetInterval /= 0x8000; } info.WindowSizeIndex = (version == 1) ? 0 : 15; { int ws = readUnsignedDWord(stream); if (ws > 0) { while ((ws & 1) == 0) { ws >>= 1; info.WindowSizeIndex++; } } } if (!moveToEntry(stream, "::DataSpace/Storage/" + mySectionNames[i] + "/Transform/{7FC28940-9D31-11D0-9B27-00A0C91E9C7C}/InstanceData/ResetTable")) { return false; } stream.seek(4, false); const std::size_t entriesNumber = readUnsignedDWord(stream); if (entriesNumber == 0) { return false; } if (entriesNumber > 2048) { // file size is greater than 60 Mb return false; } info.ResetTable.reserve(entriesNumber); stream.seek(8, false); info.UncompressedSize = readUnsignedQWord(stream); if ((info.UncompressedSize - 1) / 0x8000 != entriesNumber - 1) { return false; } info.CompressedSize = readUnsignedQWord(stream); stream.seek(8, false); std::size_t previous = 0; for (std::size_t j = 0; j < entriesNumber; ++j) { std::size_t value = readUnsignedQWord(stream); if ((j > 0) == (value <= previous)) { return false; } info.ResetTable.push_back(value); previous = value; } } } return true; }
WinHelpIcon::WinHelpIcon(QFile &file, qint64 off) : images() { PRINT_DBG("Loading icon"); seekFile(file, off); quint16 magicIn = readUnsignedWord(file); if (magicIn != 0) { throw std::runtime_error("Not an icon resource header"); } PRINT_DBG(" Icon resource header magic: %d", magicIn); quint16 resourceTypeIn = readUnsignedWord(file); if (resourceTypeIn != 1) { throw std::runtime_error("Resource is not an icon"); } PRINT_DBG(" Icon resource header resource type: %d", resourceTypeIn); quint16 imagesCountIn = readUnsignedWord(file); PRINT_DBG(" Icon resource header images count: %d", imagesCountIn); QScopedArrayPointer<quint8> widths(new quint8[imagesCountIn]); QScopedArrayPointer<quint8> heights(new quint8[imagesCountIn]); QScopedArrayPointer<quint32> colorCounts(new quint32[imagesCountIn]); QScopedArrayPointer<quint16> colorPlanes(new quint16[imagesCountIn]); QScopedArrayPointer<quint16> bitsPerPixelCount(new quint16[imagesCountIn]); QScopedArrayPointer<qint64> bitmapSizes(new qint64[imagesCountIn]); QScopedArrayPointer<qint64> bitmapOffsets(new qint64[imagesCountIn]); for (int index = 0; index < imagesCountIn; index++) { widths[index] = readUnsignedByte(file); PRINT_DBG(" Icon image directory image header width: %d", widths[index]); heights[index] = readUnsignedByte(file); PRINT_DBG(" Icon image directory image header height: %d", heights[index]); colorCounts[index] = static_cast<quint32> (readUnsignedByte(file)); PRINT_DBG(" Icon image directory image header color count: %d", colorCounts[index]); quint8 reservedIn = readUnsignedByte(file); if (reservedIn != 0) { qDebug() << "Icon image directory image header reserved value is non-zero"; } PRINT_DBG(" Icon image directory image header reserved: %d", reservedIn); colorPlanes[index] = readUnsignedWord(file); PRINT_DBG(" Icon image directory image header color planes: %d", colorPlanes[index]); bitsPerPixelCount[index] = readUnsignedWord(file); PRINT_DBG( " Icon image directory image header bits per pixel count: %d", bitsPerPixelCount[index]); bitmapSizes[index] = static_cast<qint64> (readUnsignedDWord(file)); PRINT_DBG(" Icon image directory image header bitmap size: %lld", bitmapSizes[index]); bitmapOffsets[index] = static_cast<qint64> (readUnsignedDWord(file)); PRINT_DBG( " Icon image directory image header bitmap offset: %lld", bitmapOffsets[index]); } for (int index = 0; index < imagesCountIn; index++) { seekFile(file, off + bitmapOffsets[index]); quint32 headerSizeIn = readUnsignedDWord(file); PRINT_DBG(" Icon image header size: %d", headerSizeIn); if (headerSizeIn == 40) { qint32 widthIn = readSignedDWord(file); PRINT_DBG(" Icon image width: %d", widthIn); qint64 realWidth = static_cast<qint64> (widths[index]); if (realWidth == 0) { realWidth = static_cast<qint64> (widthIn); } qint32 heightIn = readSignedDWord(file); PRINT_DBG(" Icon image height: %d", heightIn); qint64 realHeight = static_cast<qint64> (heights[index]); if (realHeight == 0) { realHeight = (static_cast<qint64> (heightIn)) / (Q_INT64_C(2)); } quint16 colorPlanesIn = readUnsignedWord(file); PRINT_DBG(" Icon image color planes: %d", colorPlanesIn); quint16 bitsPerPixelCountIn = readUnsignedWord(file); PRINT_DBG(" Icon image bits per pixel count: %d", bitsPerPixelCountIn); if (colorCounts[index] == 0) { if (colorPlanesIn == 1) { if (bitsPerPixelCountIn == 1) { colorCounts[index] = 2; } else { if (bitsPerPixelCountIn == 4) { colorCounts[index] = 16; } else { if (bitsPerPixelCountIn == 8) { colorCounts[index] = 256; } else { if (bitsPerPixelCountIn != 32) { colorCounts[index] = 1 << bitsPerPixelCountIn; } } } } } else { colorCounts[index] = 1 << (bitsPerPixelCountIn * colorPlanesIn); } } quint32 compressionMethodIn = readUnsignedDWord(file); PRINT_DBG(" Icon image compression method: %d", compressionMethodIn); quint32 imageSizeIn = readUnsignedDWord(file); PRINT_DBG(" Icon image size: %d", imageSizeIn); qint32 horizontalResolutionIn = readSignedDWord(file); PRINT_DBG(" Icon image horizontal resolution: %d", horizontalResolutionIn); qint32 verticalResolutionIn = readSignedDWord(file); PRINT_DBG(" Icon image vertical resolution: %d", verticalResolutionIn); quint32 colorsInPaletteIn = readUnsignedDWord(file); PRINT_DBG(" Icon image colors in palette: %d", colorsInPaletteIn); quint32 importantColorsUsedIn = readUnsignedDWord(file); PRINT_DBG(" Icon image imporatnt colors used: %d", importantColorsUsedIn); if ((realWidth != 0) && (realHeight != 0) && ((colorCounts[index] == 0) || (colorCounts[index] == 2) || (colorCounts[index] == 16) || (colorCounts[index] == 256))) { QImage image(static_cast<int> (realWidth), static_cast<int> (realHeight), QImage::Format_ARGB32); if (colorCounts[index] == 2) { QScopedArrayPointer<QRgb> palette(new QRgb[2]); for (int i = 0; i < 2; i++) { palette[i] = readBGRDword(file); } qint64 scanlineBytes = ((realWidth + Q_INT64_C(31)) / (Q_INT64_C(32))) * Q_INT64_C(4); QScopedArrayPointer<quint8> xorImage( new quint8[scanlineBytes * realHeight]); QScopedArrayPointer<quint8> andImage( new quint8[scanlineBytes * realHeight]); if (file.read(reinterpret_cast<char *> (xorImage.data()), (scanlineBytes * realHeight)) != (scanlineBytes * realHeight)) { throw std::runtime_error("Unable to read icon image"); } if (file.read(reinterpret_cast<char *> (andImage.data()), (scanlineBytes * realHeight)) != (scanlineBytes * realHeight)) { throw std::runtime_error("Unable to read icon image"); } quint8 masks[] = { 128, 64, 32, 16, 8, 4, 2, 1 }; for (qint64 row = 0; row < realHeight; row++) { for (qint64 col = 0; col < realWidth; col++) { int colorIndex = 0; if ((xorImage[row * scanlineBytes + col / (Q_INT64_C(8))] & masks[col % (Q_INT64_C(8))]) != 0) { colorIndex = 1; } else { colorIndex = 0; } if ((andImage[row * scanlineBytes + col / (Q_INT64_C(8))] & masks[col % (Q_INT64_C(8))]) != 0) { image.setPixel(col, realHeight - Q_INT64_C(1) - row, qRgba(qRed(palette[colorIndex]), qGreen(palette[colorIndex]), qBlue( palette[colorIndex]), 0)); } else { image.setPixel(col, realHeight - Q_INT64_C(1) - row, qRgba(qRed(palette[colorIndex]), qGreen(palette[colorIndex]), qBlue( palette[colorIndex]), 0xFF)); } } } } else { if (colorCounts[index] == 16) { QScopedArrayPointer<QRgb> palette(new QRgb[16]); for (int i = 0; i < 16; i++) { palette[i] = readBGRDword(file); } qint64 scanlineBytesXor = ((realWidth * Q_INT64_C(4) + Q_INT64_C(31)) / (Q_INT64_C(32))) * Q_INT64_C(4); qint64 scanlineBytesAnd = ((realWidth + Q_INT64_C(31)) / (Q_INT64_C(32))) * Q_INT64_C(4); QScopedArrayPointer<quint8> xorImage( new quint8[scanlineBytesXor * realHeight]); QScopedArrayPointer<quint8> andImage( new quint8[scanlineBytesAnd * realHeight]); if (file.read( reinterpret_cast<char *> (xorImage.data()), (scanlineBytesXor * realHeight)) != (scanlineBytesXor * realHeight)) { throw std::runtime_error( "Unable to read icon image"); } if (file.read( reinterpret_cast<char *> (andImage.data()), (scanlineBytesAnd * realHeight)) != (scanlineBytesAnd * realHeight)) { throw std::runtime_error( "Unable to read icon image"); } quint8 masks[] = { 128, 64, 32, 16, 8, 4, 2, 1 }; for (qint64 row = 0; row < realHeight; row++) { for (qint64 col = 0; col < realWidth; col++) { quint8 colorIndex = 0; if ((col & Q_INT64_C(1)) == Q_INT64_C(0)) { colorIndex = xorImage[row * scanlineBytesXor + col / Q_INT64_C(2)]; colorIndex = colorIndex >> 4; } else { colorIndex = xorImage[row * scanlineBytesXor + col / Q_INT64_C(2)] & 15; } if ((andImage[row * scanlineBytesAnd + col / (Q_INT64_C(8))] & masks[col % (Q_INT64_C(8))]) != 0) { image.setPixel( col, realHeight - Q_INT64_C(1) - row, qRgba( qRed( palette[static_cast<int> ( colorIndex)]), qGreen( palette[static_cast<int> ( colorIndex)]), qBlue( palette[static_cast<int> ( colorIndex)]), 0)); } else { image.setPixel( col, realHeight - Q_INT64_C(1) - row, qRgba( qRed( palette[static_cast<int> ( colorIndex)]), qGreen( static_cast<int> (palette[ colorIndex])), qBlue( palette[static_cast<int> ( colorIndex)]), 0xFF)); } } } }
WinHelpPhrIndexFile::WinHelpPhrIndexFile(QFile &file, qint64 off) : phrasesOffset(), phrasesBits() { PRINT_DBG("Loading WinHelp PhrIndex file at %lld", off); seekFile(file, off); InternalDirectoryFileHeader hdr(file, off); seekFile(file, off + InternalDirectoryFileHeader::size); quint32 magic = readUnsignedDWord(file); PRINT_DBG(" Magic: %d", magic); if (magic != 1) { throw std::runtime_error("Not a PhrIndex file"); } quint32 nEntries = readUnsignedDWord(file); PRINT_DBG(" nEntries: %d", nEntries); quint32 compressedSize = readUnsignedDWord(file); PRINT_DBG(" Compressed size: %d", compressedSize); this->phrImageSize = static_cast<qint64> (readUnsignedDWord(file)); PRINT_DBG(" phrImage size: %lld", this->phrImageSize); this->phrImageCompressedSize = static_cast<qint64> (readUnsignedDWord(file)); PRINT_DBG(" phrImage compressed size: %lld", this->phrImageCompressedSize); quint32 alwaysZero = readUnsignedDWord(file); PRINT_DBG(" Always zero: %d", alwaysZero); if (alwaysZero != 0) { qDebug() << "Always zero phrIndex file field is non zero"; } quint8 bitfieldL = readUnsignedByte(file); PRINT_DBG(" Bitfield low byte: %d", bitfieldL); quint8 bitfieldH = readUnsignedByte(file); PRINT_DBG(" Bitfield high byte: %d", bitfieldH); quint8 bitCount = bitfieldL & 0x0F; PRINT_DBG(" Bitcount: %d", bitCount); quint16 unknownValue = readUnsignedWord(file); PRINT_DBG(" Unknown value: %d", unknownValue); this->phrasesOffset.resize(nEntries + 1); this->phrasesOffset[0] = 0; PRINT_DBG(" Phrase offset: %d", this->phrasesOffset[0]); IntAllignedCursor cur; cur.currentBitIndex = 0; cur.currentDwordByte0 = 0; cur.currentDwordByte1 = 0; cur.currentDwordByte2 = 0; cur.currentDwordByte3 = 0; for (quint32 i = 0; i < nEntries; i++) { uint n = 1; while (this->getNextBitIntAlligned(file, cur)) { n += static_cast<uint> (0x0001 << bitCount); } if (this->getNextBitIntAlligned(file, cur)) { n += 1; } if (bitCount > 1) { if (this->getNextBitIntAlligned(file, cur)) { n += 2; } } if (bitCount > 2) { if (this->getNextBitIntAlligned(file, cur)) { n += 4; } } if (bitCount > 3) { if (this->getNextBitIntAlligned(file, cur)) { n += 8; } } if (bitCount > 4) { if (this->getNextBitIntAlligned(file, cur)) { n += 16; } } this->phrasesOffset[i + 1] = this->phrasesOffset[i] + n; PRINT_DBG(" Phrase offset: %d", this->phrasesOffset[i + 1]); } this->phrasesBits.resize(nEntries); ByteAllignedCursor bCur; bCur.currentBitIndex = 0; bCur.currentByte = 0; for (quint32 index = 0; index < nEntries; index++) { if (this->getNextBitByteAlligned(file, bCur)) { this->phrasesBits[index] = true; PRINT_DBG(" Phrase bit is true"); } else { this->phrasesBits[index] = false; PRINT_DBG(" Phrase bit is false"); } } PRINT_DBG("WinHelp PhrIndex file loaded successfully"); }