mirror of https://github.com/qpdf/qpdf.git
Remove /Crypt from stream filters unconditionally
When writing a new stream, always remove /Crypt even if we are not otherwise able to filter the stream.
This commit is contained in:
parent
4237a29c94
commit
9a23c3dcb6
|
@ -1297,12 +1297,53 @@ QPDFWriter::unparseObject(QPDFObjectHandle object, int level,
|
|||
// Suppress /Length since we will write it manually
|
||||
object.removeKey("/Length");
|
||||
|
||||
// XXX BUG: /Crypt filters should always be removed.
|
||||
if (flags & f_filtered)
|
||||
{
|
||||
// We will supply our own filter and decode
|
||||
// parameters.
|
||||
object.removeKey("/Filter");
|
||||
object.removeKey("/DecodeParms");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Make sure, no matter what else we have, that we
|
||||
// don't have /Crypt in the output filters.
|
||||
QPDFObjectHandle filter = object.getKey("/Filter");
|
||||
QPDFObjectHandle decode_parms = object.getKey("/DecodeParms");
|
||||
if (filter.isOrHasName("/Crypt"))
|
||||
{
|
||||
if (filter.isName())
|
||||
{
|
||||
object.removeKey("/Filter");
|
||||
object.removeKey("/DecodeParms");
|
||||
}
|
||||
else
|
||||
{
|
||||
int idx = -1;
|
||||
for (int i = 0; i < filter.getArrayNItems(); ++i)
|
||||
{
|
||||
QPDFObjectHandle item = filter.getArrayItem(i);
|
||||
if (item.isName() && item.getName() == "/Crypt")
|
||||
{
|
||||
idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (idx >= 0)
|
||||
{
|
||||
// If filter is an array, then the code in
|
||||
// QPDF_Stream has already verified that
|
||||
// DecodeParms and Filters are arrays of
|
||||
// the same length, but if they weren't
|
||||
// for some reason, eraseItem does type
|
||||
// and bounds checking.
|
||||
QTC::TC("qpdf", "QPDFWriter remove Crypt");
|
||||
filter.eraseItem(idx);
|
||||
decode_parms.eraseItem(idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
writeString("<<");
|
||||
|
|
|
@ -255,3 +255,4 @@ QPDFWriter preserve ADBE 0
|
|||
QPDF_encryption skip 0x28 0
|
||||
QPDF_encrypt crypt array 0
|
||||
QPDF_encryption CFM AESV3 0
|
||||
QPDFWriter remove Crypt 0
|
||||
|
|
|
@ -1701,12 +1701,12 @@ my @attachments = (
|
|||
'enc-XI-attachments-base.pdf',
|
||||
'enc-XI-R6,V5,U=attachment,encrypted-attachments.pdf',
|
||||
'enc-XI-R6,V5,U=view,attachments,cleartext-metadata.pdf');
|
||||
$n_tests += 4 * @attachments;
|
||||
$n_tests += 4 * @attachments + 3;
|
||||
foreach my $f (@attachments)
|
||||
{
|
||||
my $pass = '';
|
||||
my $tpass = '';
|
||||
if ($f =~ m/U=([^,]+)/)
|
||||
if ($f =~ m/U=([^,\.]+)/)
|
||||
{
|
||||
$pass = "--password=$1";
|
||||
$tpass = $1;
|
||||
|
@ -1726,6 +1726,23 @@ foreach my $f (@attachments)
|
|||
{$td->FILE => "attachments.out", $td->EXIT_STATUS => 0},
|
||||
$td->NORMALIZE_NEWLINES);
|
||||
}
|
||||
$td->runtest("unfilterable with crypt",
|
||||
{$td->COMMAND =>
|
||||
"test_driver 36 unfilterable-with-crypt.pdf attachment"},
|
||||
{$td->FILE => "unfilterable-with-crypt-before.out",
|
||||
$td->EXIT_STATUS => 0},
|
||||
$td->NORMALIZE_NEWLINES);
|
||||
unlink "a.pdf";
|
||||
$td->runtest("decrypt file",
|
||||
{$td->COMMAND => "qpdf -decrypt --password=attachment" .
|
||||
" unfilterable-with-crypt.pdf a.pdf"},
|
||||
{$td->STRING => "", $td->EXIT_STATUS => 0});
|
||||
$td->runtest("copy of unfilterable with crypt",
|
||||
{$td->COMMAND =>
|
||||
"test_driver 36 a.pdf attachment"},
|
||||
{$td->FILE => "unfilterable-with-crypt-after.out",
|
||||
$td->EXIT_STATUS => 0},
|
||||
$td->NORMALIZE_NEWLINES);
|
||||
|
||||
show_ntests();
|
||||
# ----------
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
<< /DL 30 /DecodeParms [ null ] /Filter [ /ZlateDecode ] /Length 39 /Params << /CheckSum <c4f73a3ba2b5fef86a4085d6f006eacd> /CreationDate (D:20121229172641-05'00') /ModDate (D:20121229172600) /Size 30 >> /Subtype /text#2fplain >>attachment1.txt:
|
||||
This is the first attachment.
|
||||
--END--
|
||||
test 36 done
|
|
@ -0,0 +1,4 @@
|
|||
<< /DL 30 /DecodeParms [ << /Name /StdCF >> null ] /Filter [ /Crypt /ZlateDecode ] /Length 64 /Params << /CheckSum <c4f73a3ba2b5fef86a4085d6f006eacd> /CreationDate (D:20121229172641-05'00') /ModDate (D:20121229172600) /Size 30 >> /Subtype /text#2fplain >>attachment1.txt:
|
||||
This is the first attachment.
|
||||
--END--
|
||||
test 36 done
|
Binary file not shown.
|
@ -112,7 +112,7 @@ void runtest(int n, char const* filename1, char const* arg2)
|
|||
{
|
||||
pdf.setAttemptRecovery(false);
|
||||
}
|
||||
if ((n == 35) && (arg2 != 0))
|
||||
if (((n == 35) || (n == 36)) && (arg2 != 0))
|
||||
{
|
||||
// arg2 is password
|
||||
pdf.processFile(filename1, arg2);
|
||||
|
@ -1214,6 +1214,37 @@ void runtest(int n, char const* filename1, char const* arg2)
|
|||
std::cout << filename << ":\n" << data << "--END--\n";
|
||||
}
|
||||
}
|
||||
else if (n == 36)
|
||||
{
|
||||
// Extract raw unfilterable attachment
|
||||
|
||||
QPDFObjectHandle root = pdf.getRoot();
|
||||
QPDFObjectHandle names = root.getKey("/Names");
|
||||
QPDFObjectHandle embeddedFiles = names.getKey("/EmbeddedFiles");
|
||||
names = embeddedFiles.getKey("/Names");
|
||||
for (int i = 0; i < names.getArrayNItems(); ++i)
|
||||
{
|
||||
QPDFObjectHandle item = names.getArrayItem(i);
|
||||
if (item.isDictionary() &&
|
||||
item.getKey("/Type").isName() &&
|
||||
(item.getKey("/Type").getName() == "/Filespec") &&
|
||||
item.getKey("/EF").isDictionary() &&
|
||||
item.getKey("/EF").getKey("/F").isStream() &&
|
||||
(item.getKey("/F").getStringValue() == "attachment1.txt"))
|
||||
{
|
||||
std::string filename = item.getKey("/F").getStringValue();
|
||||
QPDFObjectHandle stream = item.getKey("/EF").getKey("/F");
|
||||
Pl_Buffer p1("buffer");
|
||||
Pl_Flate p2("compress", &p1, Pl_Flate::a_inflate);
|
||||
stream.pipeStreamData(&p2, false, false, false);
|
||||
PointerHolder<Buffer> buf = p1.getBuffer();
|
||||
std::string data = std::string(
|
||||
(char const*)buf->getBuffer(), buf->getSize());
|
||||
std::cout << stream.getDict().unparse()
|
||||
<< filename << ":\n" << data << "--END--\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::runtime_error(std::string("invalid test ") +
|
||||
|
|
Loading…
Reference in New Issue