/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include #include namespace vcl::pdf { void COSWriter::appendLiteralString(const char* pStr, sal_Int32 nLength) { while (nLength) { switch (*pStr) { case '\n': mrBuffer.append("\\n"); break; case '\r': mrBuffer.append("\\r"); break; case '\t': mrBuffer.append("\\t"); break; case '\b': mrBuffer.append("\\b"); break; case '\f': mrBuffer.append("\\f"); break; case '(': case ')': case '\\': mrBuffer.append("\\"); mrBuffer.append(static_cast(*pStr)); break; default: mrBuffer.append(static_cast(*pStr)); break; } pStr++; nLength--; } } void COSWriter::writeUnicode(OUString const& rString) { mrBuffer.append("<"); COSWriter::appendUnicodeTextString(rString, mrBuffer); mrBuffer.append(">"); } void COSWriter::writeUnicodeEncrypt(OUString const& rString, sal_Int32 nObject) { if (maParams.mbCanEncrypt && mpPDFEncryptor) { mrBuffer.append("<"); const sal_Unicode* pString = rString.getStr(); size_t nLength = rString.getLength(); //prepare a unicode string, encrypt it mpPDFEncryptor->setupEncryption(maParams.maKey, nObject); sal_Int32 nChars = 2 + (nLength * 2); std::vector aEncryptionBuffer(nChars); sal_uInt8* pCopy = aEncryptionBuffer.data(); *pCopy++ = 0xFE; *pCopy++ = 0xFF; // we need to prepare a byte stream from the unicode string buffer for (size_t i = 0; i < nLength; i++) { sal_Unicode aUnicodeChar = pString[i]; *pCopy++ = sal_uInt8(aUnicodeChar >> 8); *pCopy++ = sal_uInt8(aUnicodeChar & 255); } std::vector aNewBuffer(nChars); mpPDFEncryptor->encrypt(aEncryptionBuffer.data(), nChars, aNewBuffer, nChars); //now append, hexadecimal (appendHex), the encrypted result COSWriter::appendHexArray(aNewBuffer.data(), aNewBuffer.size(), mrBuffer); mrBuffer.append(">"); } else { writeUnicode(rString); } } void COSWriter::writeLiteralEncrypt(std::u16string_view value, sal_Int32 nObject, rtl_TextEncoding nEncoding) { OString aBufferString(OUStringToOString(value, nEncoding)); sal_Int32 nLength = aBufferString.getLength(); OStringBuffer aBuffer(nLength); const char* pT = aBufferString.getStr(); for (sal_Int32 i = 0; i < nLength; i++, pT++) { if ((*pT & 0x80) == 0) aBuffer.append(*pT); else { aBuffer.append('<'); appendHex(*pT, aBuffer); aBuffer.append('>'); } } writeLiteralEncrypt(aBuffer.makeStringAndClear(), nObject); } void COSWriter::writeLiteralEncrypt(std::string_view value, sal_Int32 nObject) { if (maParams.mbCanEncrypt && mpPDFEncryptor) { mrBuffer.append("("); size_t nChars = value.size(); std::vector aEncryptionBuffer(nChars); mpPDFEncryptor->setupEncryption(maParams.maKey, nObject); mpPDFEncryptor->encrypt(value.data(), nChars, aEncryptionBuffer, nChars); appendLiteralString(reinterpret_cast(aEncryptionBuffer.data()), aEncryptionBuffer.size()); mrBuffer.append(")"); } else { writeLiteral(value); } } void COSWriter::appendUnicodeTextString(const OUString& rString, OStringBuffer& rBuffer) { rBuffer.append("FEFF"); const sal_Unicode* pString = rString.getStr(); size_t nLength = rString.getLength(); for (size_t i = 0; i < nLength; i++) { sal_Unicode aChar = pString[i]; COSWriter::appendHex(sal_Int8(aChar >> 8), rBuffer); COSWriter::appendHex(sal_Int8(aChar & 255), rBuffer); } } void COSWriter::appendName(std::u16string_view rStr, OStringBuffer& rBuffer) { // FIXME i59651 add a check for max length of 127 chars? Per PDF spec 1.4, appendix C.1 // I guess than when reading the #xx sequence it will count for a single character. OString aStr(OUStringToOString(rStr, RTL_TEXTENCODING_UTF8)); int nLen = aStr.getLength(); for (int i = 0; i < nLen; i++) { /* #i16920# PDF recommendation: output UTF8, any byte * outside the interval [33(=ASCII'!');126(=ASCII'~')] * should be escaped hexadecimal * for the sake of ghostscript which also reads PDF * but has a narrower acceptance rate we only pass * alphanumerics and '-' literally. */ if ((aStr[i] >= 'A' && aStr[i] <= 'Z') || (aStr[i] >= 'a' && aStr[i] <= 'z') || (aStr[i] >= '0' && aStr[i] <= '9') || aStr[i] == '-') { rBuffer.append(aStr[i]); } else { rBuffer.append('#'); appendHex(static_cast(aStr[i]), rBuffer); } } } void COSWriter::appendName(const char* pStr, OStringBuffer& rBuffer) { // FIXME i59651 see above while (pStr && *pStr) { if ((*pStr >= 'A' && *pStr <= 'Z') || (*pStr >= 'a' && *pStr <= 'z') || (*pStr >= '0' && *pStr <= '9') || *pStr == '-') { rBuffer.append(*pStr); } else { rBuffer.append('#'); appendHex(static_cast(*pStr), rBuffer); } pStr++; } } } //end vcl::pdf /* vim:set shiftwidth=4 softtabstop=4 expandtab: */