/// @brief Adds entry to the file. /// /// Some entries may be ignored because of their namespace. Entries from Wiktionary /// namespace are ignored for now. /// /// The contents of the entry can be changed before saving. /// /// Prep modifies entry content: /// - <nowiki> sections are converted to HTML entities and the tags are removed. /// - <noinclude> blocks are removed with their content /// - HTML comments <!-- --> are removed with their content /// - <includeonly> tags are removed, but not the contents between them /// /// @param name /// Name of entry. Includes the optional namespace. /// @param contents /// Entry contents in wiki syntax. static void addPrepEntry(const QString &name, QString contents) { // Skip pages from Wikitonary namespace. if (name.contains("Wiktionary:")) return; // Apply errata if it exists. contents = errata.value(name, contents); // Remove comments from contents. contents = StringUtils::removeBlock(QRegExp("<!--"), QRegExp("-->"), contents); // Remove includeonly tags, but not the content between them. contents.remove(QRegExp("<includeonly\\s*>")) .remove(QRegExp("</includeonly\\s*>")); // Remove __TOC__ magic word, because we handle Table of Contents in // a separate window. contents.remove("__TOC__"); // Do not remove <nowiki/> tags. They are used as a separator between wikisyntax // that cannot be parsed together. // Substitute special wiki characters in <nowiki> sections with // html chars and removes the <nowiki> tags. contents = substituteSpecialCharactersNoWiki(contents); if (!temporaryFile.isOpen()) temporaryFile.open(); qint64 offset = temporaryFile.pos(); // Save data to the content file. FileUtils::writeString(temporaryFile, name); FileUtils::writeString(temporaryFile, contents); // Add an entry to the link list. links.push_back(Link(name, offset)); }
bool Packaging::ExtractTar(QTemporaryFile& tarFile, PackageData *packageData) { TarHeader tarHeader; if (!tarFile.open()) { Alerts::DisplayError(QString("Error opening temporary TAR archive:\n%1").arg(tarFile.fileName())); return (false); } bool previousEmpty = false; QProgressDialog progressDialog("Extracting files...", "Cancel", 0, tarFile.size()); progressDialog.setWindowModality(Qt::ApplicationModal); progressDialog.setWindowTitle("Heimdall Frontend"); while (!tarFile.atEnd()) { qint64 dataRead = tarFile.read(tarHeader.buffer, TarHeader::kBlockLength); if (dataRead != TarHeader::kBlockLength) { progressDialog.close(); Alerts::DisplayError("Package's TAR archive is malformed."); tarFile.close(); return (false); } progressDialog.setValue(tarFile.pos()); if (progressDialog.wasCanceled()) { tarFile.close(); progressDialog.close(); return (false); } //bool ustarFormat = strcmp(tarHeader.fields.magic, ustarMagic) == 0; bool empty = true; for (int i = 0; i < TarHeader::kBlockLength; i++) { if (tarHeader.buffer[i] != 0) { empty = false; break; } } if (empty) { if (previousEmpty) { // Two empty blocks in a row means we've reached the end of the archive. break; } } else { int checksum = 0; for (char *bufferIndex = tarHeader.buffer; bufferIndex < tarHeader.fields.checksum; bufferIndex++) checksum += static_cast<unsigned char>(*bufferIndex); checksum += 8 * ' '; checksum += static_cast<unsigned char>(tarHeader.fields.typeFlag); // Both the TAR and USTAR formats have terrible documentation, it's not clear if the following code is required. /*if (ustarFormat) { for (char *bufferIndex = tarHeader.fields.linkName; bufferIndex < tarHeader.fields.prefix + 155; bufferIndex++) checksum += static_cast<unsigned char>(*bufferIndex); }*/ bool parsed = false; // The size field is not always null terminated, so we must create a copy and null terminate it for parsing. char fileSizeString[13]; memcpy(fileSizeString, tarHeader.fields.size, 12); fileSizeString[12] = '\0'; qulonglong fileSize = QString(fileSizeString).toULongLong(&parsed, 8); if (!parsed) { progressDialog.close(); Alerts::DisplayError("Tar header contained an invalid file size."); tarFile.close(); return (false); } if (fileSize > 0 && tarHeader.fields.typeFlag == '0') { // We're working with a file. QString filename = QString::fromUtf8(tarHeader.fields.name); QTemporaryFile *outputFile = new QTemporaryFile("XXXXXX-" + filename); packageData->GetFiles().append(outputFile); if (!outputFile->open()) { progressDialog.close(); Alerts::DisplayError(QString("Failed to open output file: \n%1").arg(outputFile->fileName())); tarFile.close(); return (false); } qulonglong dataRemaining = fileSize; char readBuffer[TarHeader::kBlockReadCount * TarHeader::kBlockLength]; // Copy the file contents from tarFile to outputFile while (dataRemaining > 0) { qint64 fileDataToRead = (dataRemaining < TarHeader::kBlockReadCount * TarHeader::kBlockLength) ? dataRemaining : TarHeader::kBlockReadCount * TarHeader::kBlockLength; qint64 dataRead = tarFile.read(readBuffer, fileDataToRead + (TarHeader::kBlockLength - fileDataToRead % TarHeader::kBlockLength) % TarHeader::kBlockLength); if (dataRead < fileDataToRead || dataRead % TarHeader::kBlockLength != 0) { progressDialog.close(); Alerts::DisplayError("Unexpected read error whilst extracting package files."); tarFile.close(); outputFile->close(); remove(outputFile->fileName().toStdString().c_str()); return (false); } outputFile->write(readBuffer, fileDataToRead); dataRemaining -= fileDataToRead; progressDialog.setValue(tarFile.pos()); if (progressDialog.wasCanceled()) { tarFile.close(); outputFile->close(); remove(outputFile->fileName().toStdString().c_str()); progressDialog.close(); return (false); } } outputFile->close(); } else { progressDialog.close(); Alerts::DisplayError("Heimdall packages shouldn't contain links or directories."); tarFile.close(); return (false); } } previousEmpty = empty; } progressDialog.close(); tarFile.close(); return (true); }