From e9f9887cfb6f3eace17640cb951f847d2e4a8c53 Mon Sep 17 00:00:00 2001 From: Jakob Truelsen Date: Mon, 3 May 2010 21:08:10 +0200 Subject: Propperly escape title and creator in PDF documents The title and creator fields in the PDF information section were not propperly escaped leading to invalid pdf documents when the title contain ')','(','\' (or any of the bazilion utf16 characters where one of the bytes happen to be the same as the ascii code for one of these). Merge-request: 2375 Reviewed-by: Benjamin Poulain --- src/gui/painting/qprintengine_pdf.cpp | 46 ++++++++++++++++++++--------------- src/gui/painting/qprintengine_pdf_p.h | 1 + tests/auto/qprinter/tst_qprinter.cpp | 28 ++++++++++++++++++++- 3 files changed, 54 insertions(+), 21 deletions(-) diff --git a/src/gui/painting/qprintengine_pdf.cpp b/src/gui/painting/qprintengine_pdf.cpp index b8bf15e..0a747e7 100644 --- a/src/gui/painting/qprintengine_pdf.cpp +++ b/src/gui/painting/qprintengine_pdf.cpp @@ -931,29 +931,16 @@ void QPdfEnginePrivate::writeHeader() void QPdfEnginePrivate::writeInfo() { info = addXrefEntry(-1); - - // The 'text string' type in PDF is encoded either as PDFDocEncoding, or - // Unicode UTF-16 with a Unicode byte order mark as the first character - // (0xfeff), with the high-order byte first. - QByteArray array("<<\n/Title (\xfe\xff"); - const ushort *utf16Title = title.utf16(); - for (int i=0; i < title.size(); ++i) { - array.append((*(utf16Title + i)) >> 8); - array.append((*(utf16Title + i)) & 0xff); - } - array.append(")\n/Creator (\xfe\xff"); - const ushort *utf16Creator = creator.utf16(); - for (int i=0; i < creator.size(); ++i) { - array.append((*(utf16Creator + i)) >> 8); - array.append((*(utf16Creator + i)) & 0xff); - } - array.append(")\n/Producer (Qt " QT_VERSION_STR " (C) 2010 Nokia Corporation and/or its subsidiary(-ies))\n"); - write(array); - + xprintf("<<\n/Title "); + printString(title); + xprintf("\n/Creator "); + printString(creator); + xprintf("\n/Producer "); + printString(QString::fromLatin1("Qt " QT_VERSION_STR " (C) 2010 Nokia Corporation and/or its subsidiary(-ies)")); QDateTime now = QDateTime::currentDateTime().toUTC(); QTime t = now.time(); QDate d = now.date(); - xprintf("/CreationDate (D:%d%02d%02d%02d%02d%02d)\n", + xprintf("\n/CreationDate (D:%d%02d%02d%02d%02d%02d)\n", d.year(), d.month(), d.day(), @@ -1230,6 +1217,25 @@ int QPdfEnginePrivate::addXrefEntry(int object, bool printostr) return object; } +void QPdfEnginePrivate::printString(const QString &string) { + // The 'text string' type in PDF is encoded either as PDFDocEncoding, or + // Unicode UTF-16 with a Unicode byte order mark as the first character + // (0xfeff), with the high-order byte first. + QByteArray array("(\xfe\xff"); + const ushort *utf16 = string.utf16(); + + for (int i=0; i < string.size(); ++i) { + char part[2] = {(*(utf16 + i)) >> 8, (*(utf16 + i)) & 0xff}; + for(int j=0; j < 2; ++j) { + if (part[j] == '(' || part[j] == ')' || part[j] == '\\') + array.append('\\'); + array.append(part[j]); + } + } + array.append(")"); + write(array); +} + QT_END_NAMESPACE #endif // QT_NO_PRINTER diff --git a/src/gui/painting/qprintengine_pdf_p.h b/src/gui/painting/qprintengine_pdf_p.h index cb6c59d..e0ca56f 100644 --- a/src/gui/painting/qprintengine_pdf_p.h +++ b/src/gui/painting/qprintengine_pdf_p.h @@ -170,6 +170,7 @@ private: void writePage(); int addXrefEntry(int object, bool printostr = true); + void printString(const QString &string); void xprintf(const char* fmt, ...); inline void write(const QByteArray &data) { stream->writeRawData(data.constData(), data.size()); diff --git a/tests/auto/qprinter/tst_qprinter.cpp b/tests/auto/qprinter/tst_qprinter.cpp index 49bddb2..8b79533 100644 --- a/tests/auto/qprinter/tst_qprinter.cpp +++ b/tests/auto/qprinter/tst_qprinter.cpp @@ -110,6 +110,7 @@ private slots: void testCurrentPage(); void taskQTBUG4497_reusePrinterOnDifferentFiles(); + void testPdfTitle(); private: }; @@ -417,7 +418,7 @@ void tst_QPrinter::testMargins() printer.setFullPage(fullpage); printer.setPageSize((QPrinter::PageSize)pagesize); if (withPainter) - painter = new QPainter(&printer); + painter = new QPainter(&printer); #ifdef QT3_SUPPORT Q3PaintDeviceMetrics metrics(&printer); @@ -1028,5 +1029,30 @@ void tst_QPrinter::testCurrentPage() } +void tst_QPrinter::testPdfTitle() +{ + // Check the document name is represented correctly in produced pdf + { + QPainter painter; + QPrinter printer; + // This string is just the UTF-8 encoding of the string: \()f ø hiragana o + const char title[]={0x5c, 0x28, 0x29, 0x66, 0xc3, 0xb8, 0xe3, 0x81, 0x8a, 0x00}; + printer.setOutputFileName("file.pdf"); + printer.setDocName(QString::fromUtf8(title)); + painter.begin(&printer); + painter.end(); + } + QFile file("file.pdf"); + QVERIFY(file.open(QIODevice::ReadOnly)); + // The we expect the title to appear in the PDF as: + // ASCII('\title (') UTF16(\\\(\)f ø hiragana o) ASCII(')'). + // which has the following binary representation + const char expected[] = { + 0x2f, 0x54, 0x69, 0x74, 0x6c, 0x65, 0x20, 0x28, 0xfe, + 0xff, 0x00, 0x5c, 0x5c, 0x00, 0x5c, 0x28, 0x00, 0x5c, + 0x29, 0x00, 0x66, 0x00, 0xf8, 0x30, 0x4a, 0x29}; + QVERIFY(file.readAll().contains(QByteArray(expected, 26))); +} + QTEST_MAIN(tst_QPrinter) #include "tst_qprinter.moc" -- cgit v0.12