2
1
mirror of https://github.com/qpdf/qpdf.git synced 2024-12-22 10:58:58 +00:00

Security: replace operator[] with at

For std::string and std::vector, replace operator[] with at.  This was
done using an automated process.  See README.hardening for details.
This commit is contained in:
Jay Berkenbilt 2013-10-05 19:42:39 -04:00
parent 4229457068
commit ac9c1f0d56
23 changed files with 254 additions and 153 deletions

View File

@ -1,5 +1,10 @@
2013-10-05 Jay Berkenbilt <ejb@ql.org>
* Replace operator[] in std::string and std::vector with "at" in
order to get bounds checking. This reduces the chances that
incorrect code will result in data exposure or buffer overruns.
See README.hardening for additional notes.
* Use cryptographically secure random number generation when
available. See additional notes in README.

93
README.hardening Normal file
View File

@ -0,0 +1,93 @@
Avoiding operator[]
===================
During a security review by Red Hat security team (specifically
Florian Weimer), it was discovered that qpdf used std::string and
std::vector's operator[], which has no bounds checking by design.
Instead, using those objects' at() method is preferable since it does
bounds checking. Florian has a tool that can detect all uses of these
methods and report them. I have a short perl script that
automatically corrects any such uses. The perl script is not intended
to be general, but it could be reasonably general. The only known
shortcut is that it might not work very well with some cases of nested
[]'s like a[b[c]] or with cases where there are line breaks inside the
brackets. For qpdf's coding style, it worked on all cases reported.
To use this, obtain htcondor-analyzer, run it, and respond to the
report. Here's what I did.
sudo aptitude install libclang-dev llvm llvm-dev clang
cd /tmp
git clone https://github.com/fweimer/htcondor-analyzer
# HEAD = 5fa06fc68a9b0677e9de162279185d58ba1e8477 at this writing
cd htcondor-analyzer
make
in qpdf
./autogen.sh
/tmp/htcondor-analyzer/create-db
CC=/tmp/htcondor-analyzer/cc CXX=/tmp/htcondor-analyzer/cxx ./configure --disable-shared --disable-werror
# to remove conftest.c
\rm htcondor-analyzer.sqlite
/tmp/htcondor-analyzer/create-db
Repeat until no more errors:
/tmp/fix-at.pl is shown below.
make
/tmp/htcondor-analyzer/report | grep std:: | grep qpdf >| /tmp/r
perl /tmp/fix-at.pl /tmp/r
# move all *.new over the original file. patmv is my script. Can
# also use a for loop.
patmv -f s/.new// **/*.new
---------- /tmp/fix-at.pl ----------
#!/usr/bin/env perl
require 5.008;
use warnings;
use strict;
use File::Basename;
my $whoami = basename($0);
my %to_fix = ();
while (<>)
{
chomp;
die unless m/^([^:]+):(\d+):(\d+):\s*(.*)$/;
my ($file, $line, $col, $message) = ($1, $2, $3, $4);
if ($message !~ m/operator\[\]/)
{
warn "skipping $_\n";
next;
}
push(@{$to_fix{$file}}, [$line, $col, $message]);
}
foreach my $file (sort keys %to_fix)
{
open(F, "<$file") or die;
my @lines = (<F>);
close(F);
my $last = "";
my @data = reverse sort { ($a->[0] <=> $b->[0]) || ($a->[1] <=> $b->[1]) } @{$to_fix{$file}};
foreach my $d (@data)
{
my ($line, $col) = @$d;
next if $last eq "$line:$col";
$last = "$line:$col";
die if $line-- < 1;
die if $col-- < 1;
print $lines[$line];
$lines[$line] =~ s/^(.{$col})([^\[]+)\[([^\]]+)\]/$1$2.at($3)/ or die "$file:$last\n";
print $lines[$line];
}
open(F, ">$file.new") or die;
foreach my $line (@lines)
{
print F $line;
}
close(F) or die;
}
--------------------

View File

@ -43,6 +43,9 @@ Release Reminders
casting policy in the manual, and ensure that integer types are
properly handled.
* Remember to avoid using operator[] with std::string or
std::vector. See README.hardening for details.
* Increment shared library version information as needed
(libqpdf/build.mk)

View File

@ -31,7 +31,7 @@ void print_lines(std::vector<int>& numbers)
{
for (unsigned int i = 0; i < numbers.size() - 1; ++i)
{
if (numbers[i])
if (numbers.at(i))
{
std::cout << "| ";
}

View File

@ -128,7 +128,7 @@ int main(int argc, char* argv[])
{
QTC::TC("examples", "pdf-mod-info -key");
cur_key = argv[i];
if (! ((cur_key.length() > 0) && (cur_key[0] == '/')))
if (! ((cur_key.length() > 0) && (cur_key.at(0) == '/')))
{
cur_key = "/" + cur_key;
}

View File

@ -74,7 +74,7 @@ int main(int argc, char* argv[])
usage();
}
QPDFObjectHandle page = pages[pageno-1];
QPDFObjectHandle page = pages.at(pageno-1);
QPDFObjectHandle contents = page.getKey("/Contents");
ParserCallbacks cb;
QPDFObjectHandle::parseContentStream(contents, &cb);

View File

@ -109,7 +109,7 @@ Pl_LZWDecoder::getFirstChar(int code)
throw std::logic_error(
"Pl_LZWDecoder::getFirstChar: table overflow");
}
Buffer& b = table[idx];
Buffer& b = table.at(idx);
result = b.getBuffer()[0];
}
else
@ -142,7 +142,7 @@ Pl_LZWDecoder::addToTable(unsigned char next)
throw std::logic_error(
"Pl_LZWDecoder::addToTable: table overflow");
}
Buffer& b = table[idx];
Buffer& b = table.at(idx);
last_data = b.getBuffer();
last_size = b.getSize();
}
@ -238,7 +238,7 @@ Pl_LZWDecoder::handleCode(int code)
}
else
{
Buffer& b = table[code - 258];
Buffer& b = table.at(code - 258);
getNext()->write(b.getBuffer(), b.getSize());
}
}

View File

@ -531,7 +531,7 @@ QPDF::read_xrefTable(qpdf_offset_t xref_offset)
// For xref_table, these will always be small enough to be ints
qpdf_offset_t f1 = QUtil::string_to_ll(m2.getMatch(1).c_str());
int f2 = atoi(m2.getMatch(2).c_str());
char type = m2.getMatch(3)[0];
char type = m2.getMatch(3).at(0);
if (type == 'f')
{
// Save deleted items until after we've checked the
@ -758,17 +758,17 @@ QPDF::processXRefStream(qpdf_offset_t xref_offset, QPDFObjectHandle& xref_obj)
long long num_entries = 0;
for (unsigned int i = 1; i < indx.size(); i += 2)
{
if (indx[i] > max_num_entries - num_entries)
if (indx.at(i) > max_num_entries - num_entries)
{
throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(),
"xref stream", xref_offset,
"Cross-reference stream claims to contain"
" too many entries: " +
QUtil::int_to_string(indx[i]) + " " +
QUtil::int_to_string(indx.at(i)) + " " +
QUtil::int_to_string(max_num_entries) + " " +
QUtil::int_to_string(num_entries));
}
num_entries += indx[i];
num_entries += indx.at(i);
}
// entry_size and num_entries have both been validated to ensure
@ -829,9 +829,9 @@ QPDF::processXRefStream(qpdf_offset_t xref_offset, QPDFObjectHandle& xref_obj)
// based on /Index. The generation number is 0 unless this is
// an uncompressed object record, in which case the generation
// number appears as the third field.
int obj = indx[cur_chunk] + chunk_count;
int obj = indx.at(cur_chunk) + chunk_count;
++chunk_count;
if (chunk_count >= indx[cur_chunk + 1])
if (chunk_count >= indx.at(cur_chunk + 1))
{
cur_chunk += 2;
chunk_count = 0;

View File

@ -712,7 +712,7 @@ QPDFObjectHandle::parse(std::string const& object_str,
size_t offset = input->tell();
while (offset < object_str.length())
{
if (! isspace(object_str[offset]))
if (! isspace(object_str.at(offset)))
{
QTC::TC("qpdf", "QPDFObjectHandle trailing data in parse");
throw QPDFExc(qpdf_e_damaged_pdf, input->getName(),
@ -966,8 +966,8 @@ QPDFObjectHandle::parseInternal(PointerHolder<InputSource> input,
std::string const& value = token.getValue();
if ((value == "R") && (in_array || in_dictionary) &&
(olist.size() >= 2) &&
(olist[olist.size() - 1].isInteger()) &&
(olist[olist.size() - 2].isInteger()))
(olist.at(olist.size() - 1).isInteger()) &&
(olist.at(olist.size() - 2).isInteger()))
{
if (context == 0)
{
@ -979,8 +979,8 @@ QPDFObjectHandle::parseInternal(PointerHolder<InputSource> input,
// Try to resolve indirect objects
object = newIndirect(
context,
olist[olist.size() - 2].getIntValue(),
olist[olist.size() - 1].getIntValue());
olist.at(olist.size() - 2).getIntValue(),
olist.at(olist.size() - 1).getIntValue());
olist.pop_back();
olist.pop_back();
}
@ -1067,8 +1067,8 @@ QPDFObjectHandle::parseInternal(PointerHolder<InputSource> input,
}
for (unsigned int i = 0; i < olist.size(); i += 2)
{
QPDFObjectHandle key_obj = olist[i];
QPDFObjectHandle val = olist[i + 1];
QPDFObjectHandle key_obj = olist.at(i);
QPDFObjectHandle val = olist.at(i + 1);
if (! key_obj.isName())
{
throw QPDFExc(

View File

@ -61,7 +61,7 @@ QPDFTokenizer::resolveLiteral()
{
PCRE num_re("^[\\+\\-]?(?:\\.\\d+|\\d+(?:\\.\\d+)?)$");
if ((val.length() > 0) && (val[0] == '/'))
if ((val.length() > 0) && (val.at(0) == '/'))
{
type = tt_name;
// Deal with # in name token. Note: '/' by itself is a
@ -397,8 +397,8 @@ QPDFTokenizer::presentCharacter(char ch)
std::string nval;
for (unsigned int i = 0; i < val.length(); i += 2)
{
num[0] = val[i];
num[1] = val[i+1];
num[0] = val.at(i);
num[1] = val.at(i+1);
char nch = static_cast<char>(strtol(num, 0, 16));
nval += nch;
}

View File

@ -1569,7 +1569,7 @@ QPDFWriter::writeObjectStreamOffsets(std::vector<qpdf_offset_t>& offsets,
}
writeString(QUtil::int_to_string(i + first_obj));
writeString(" ");
writeString(QUtil::int_to_string(offsets[i]));
writeString(QUtil::int_to_string(offsets.at(i)));
}
writeString("\n");
}
@ -1603,7 +1603,7 @@ QPDFWriter::writeObjectStream(QPDFObjectHandle object)
{
// Adjust offsets to skip over comment before first object
first = offsets[0];
first = offsets.at(0);
for (std::vector<qpdf_offset_t>::iterator iter = offsets.begin();
iter != offsets.end(); ++iter)
{
@ -2745,7 +2745,7 @@ QPDFWriter::writeLinearized()
if (pass == 2)
{
std::vector<QPDFObjectHandle> const& pages = pdf.getAllPages();
int first_page_object = obj_renumber[pages[0].getObjGen()];
int first_page_object = obj_renumber[pages.at(0).getObjGen()];
int npages = pages.size();
writeString(" /Linearized 1 /L ");

View File

@ -60,7 +60,7 @@ QPDF_Array::getItem(int n) const
throw std::logic_error(
"INTERNAL ERROR: bounds error accessing QPDF_Array element");
}
return this->items[n];
return this->items.at(n);
}
std::vector<QPDFObjectHandle> const&
@ -74,7 +74,7 @@ QPDF_Array::setItem(int n, QPDFObjectHandle const& oh)
{
// Call getItem for bounds checking
(void) getItem(n);
this->items[n] = oh;
this->items.at(n) = oh;
}
void

View File

@ -21,10 +21,10 @@ QPDF_Name::normalizeName(std::string const& name)
return name;
}
std::string result;
result += name[0];
result += name.at(0);
for (unsigned int i = 1; i < name.length(); ++i)
{
char ch = name[i];
char ch = name.at(i);
// Don't use locale/ctype here; follow PDF spec guidelines.
if (strchr("#()<>[]{}/%", ch) || (ch < 33) || (ch > 126))
{

View File

@ -310,7 +310,7 @@ QPDF_Stream::filterable(std::vector<std::string>& filters,
for (unsigned int i = 0; i < filters.size(); ++i)
{
QPDFObjectHandle decode_item = decode_parms[i];
QPDFObjectHandle decode_item = decode_parms.at(i);
if (decode_item.isNull())
{
// okay
@ -318,7 +318,7 @@ QPDF_Stream::filterable(std::vector<std::string>& filters,
else if (decode_item.isDictionary())
{
if (! understandDecodeParams(
filters[i], decode_item,
filters.at(i), decode_item,
predictor, columns, early_code_change))
{
filterable = false;

View File

@ -55,7 +55,7 @@ QPDF_String::unparse(bool force_binary)
int consecutive_printable = 0;
for (unsigned int i = 0; i < this->val.length(); ++i)
{
char ch = this->val[i];
char ch = this->val.at(i);
// Note: do not use locale to determine printability. The
// PDF specification accepts arbitrary binary data. Some
// locales imply multibyte characters. We'll consider
@ -97,7 +97,7 @@ QPDF_String::unparse(bool force_binary)
result += "(";
for (unsigned int i = 0; i < this->val.length(); ++i)
{
char ch = this->val[i];
char ch = this->val.at(i);
switch (ch)
{
case '\n':
@ -135,7 +135,7 @@ QPDF_String::unparse(bool force_binary)
default:
if (is_iso_latin1_printable(ch))
{
result += this->val[i];
result += this->val.at(i);
}
else
{
@ -164,7 +164,7 @@ QPDF_String::getUTF8Val() const
std::string result;
size_t len = this->val.length();
if ((len >= 2) && (len % 2 == 0) &&
(this->val[0] == '\xfe') && (this->val[1] == '\xff'))
(this->val.at(0) == '\xfe') && (this->val.at(1) == '\xff'))
{
// This is a Unicode string using big-endian UTF-16. This
// code uses unsigned long and unsigned short to hold
@ -181,8 +181,8 @@ QPDF_String::getUTF8Val() const
// discarded, and a low codepoint not preceded by a high
// codepoint will just get its low 10 bits output.
unsigned short bits =
(static_cast<unsigned char>(this->val[i]) << 8) +
static_cast<unsigned char>(this->val[i+1]);
(static_cast<unsigned char>(this->val.at(i)) << 8) +
static_cast<unsigned char>(this->val.at(i+1));
if ((bits & 0xFC00) == 0xD800)
{
codepoint = 0x10000 + ((bits & 0x3FF) << 10);
@ -209,7 +209,7 @@ QPDF_String::getUTF8Val() const
{
for (unsigned int i = 0; i < len; ++i)
{
result += QUtil::toUTF8(static_cast<unsigned char>(this->val[i]));
result += QUtil::toUTF8(static_cast<unsigned char>(this->val.at(i)));
}
}
return result;

View File

@ -312,7 +312,7 @@ hash_V5(std::string const& password,
int E_mod_3 = 0;
for (unsigned int i = 0; i < 16; ++i)
{
E_mod_3 += static_cast<unsigned char>(E[i]);
E_mod_3 += static_cast<unsigned char>(E.at(i));
}
E_mod_3 %= 3;
int next_hash = ((E_mod_3 == 0) ? 256 :

View File

@ -33,7 +33,7 @@ load_vector_int(BitStream& bit_stream, int nitems, std::vector<T>& vec,
{
vec.push_back(T());
}
vec[i].*field = bit_stream.getBits(bits_wanted);
vec.at(i).*field = bit_stream.getBits(bits_wanted);
}
if (static_cast<int>(vec.size()) != nitems)
{
@ -54,9 +54,9 @@ load_vector_vector(BitStream& bit_stream,
// into the vec2 vector field of the ith item of vec1.
for (int i1 = 0; i1 < nitems1; ++i1)
{
for (int i2 = 0; i2 < vec1[i1].*nitems2; ++i2)
for (int i2 = 0; i2 < vec1.at(i1).*nitems2; ++i2)
{
(vec1[i1].*vec2).push_back(bit_stream.getBits(bits_wanted));
(vec1.at(i1).*vec2).push_back(bit_stream.getBits(bits_wanted));
}
}
bit_stream.skipToNextByte();
@ -237,8 +237,8 @@ QPDF::readLinearizationData()
}
// H: hint table offset/length for primary and overflow hint tables
int H0_offset = H_items[0];
int H0_length = H_items[1];
int H0_offset = H_items.at(0);
int H0_length = H_items.at(1);
int H1_offset = 0;
int H1_length = 0;
if (H_items.size() == 4)
@ -246,8 +246,8 @@ QPDF::readLinearizationData()
// Acrobat doesn't read or write these (as PDF 1.4), so we
// don't have a way to generate a test case.
// QTC::TC("qpdf", "QPDF overflow hint table");
H1_offset = H_items[2];
H1_length = H_items[3];
H1_offset = H_items.at(2);
H1_length = H_items.at(3);
}
// P: first page number
@ -470,7 +470,7 @@ QPDF::readHSharedObject(BitStream h)
1, &HSharedObjectEntry::signature_present);
for (int i = 0; i < nitems; ++i)
{
if (entries[i].signature_present)
if (entries.at(i).signature_present)
{
// Skip 128-bit MD5 hash. These are not supported by
// acrobat, so they should probably never be there. We
@ -512,7 +512,7 @@ QPDF::checkLinearizationInternal()
// O: object number of first page
std::vector<QPDFObjectHandle> const& pages = getAllPages();
if (p.first_page_object != pages[0].getObjectID())
if (p.first_page_object != pages.at(0).getObjectID())
{
QTC::TC("qpdf", "QPDF err /O mismatch");
errors.push_back("first page object (/O) mismatch");
@ -528,7 +528,7 @@ QPDF::checkLinearizationInternal()
for (int i = 0; i < npages; ++i)
{
QPDFObjectHandle const& page = pages[i];
QPDFObjectHandle const& page = pages.at(i);
QPDFObjGen og(page.getObjGen());
if (this->xref_table[og].getType() == 2)
{
@ -776,7 +776,7 @@ QPDF::checkHPageOffset(std::list<std::string>& errors,
unsigned int npages = pages.size();
int table_offset = adjusted_offset(
this->page_offset_hints.first_page_offset);
QPDFObjGen first_page_og(pages[0].getObjGen());
QPDFObjGen first_page_og(pages.at(0).getObjGen());
assert(this->xref_table.count(first_page_og) > 0);
int offset = getLinearizationOffset(first_page_og);
if (table_offset != offset)
@ -786,13 +786,13 @@ QPDF::checkHPageOffset(std::list<std::string>& errors,
for (unsigned int pageno = 0; pageno < npages; ++pageno)
{
QPDFObjGen page_og(pages[pageno].getObjGen());
QPDFObjGen page_og(pages.at(pageno).getObjGen());
int first_object = page_og.getObj();
assert(this->xref_table.count(page_og) > 0);
offset = getLinearizationOffset(page_og);
HPageOffsetEntry& he = this->page_offset_hints.entries[pageno];
CHPageOffsetEntry& ce = this->c_page_offset_data.entries[pageno];
HPageOffsetEntry& he = this->page_offset_hints.entries.at(pageno);
CHPageOffsetEntry& ce = this->c_page_offset_data.entries.at(pageno);
int h_nobjects = he.delta_nobjects +
this->page_offset_hints.min_nobjects;
if (h_nobjects != ce.nobjects)
@ -837,7 +837,7 @@ QPDF::checkHPageOffset(std::list<std::string>& errors,
for (int i = 0; i < he.nshared_objects; ++i)
{
int idx = he.shared_identifiers[i];
int idx = he.shared_identifiers.at(i);
if (shared_idx_to_obj.count(idx) == 0)
{
throw std::logic_error(
@ -849,13 +849,13 @@ QPDF::checkHPageOffset(std::list<std::string>& errors,
for (int i = 0; i < ce.nshared_objects; ++i)
{
int idx = ce.shared_identifiers[i];
int idx = ce.shared_identifiers.at(i);
if (idx >= this->c_shared_object_data.nshared_total)
{
throw std::logic_error(
"index out of bounds for shared object hint table");
}
int obj = this->c_shared_object_data.entries[idx].object;
int obj = this->c_shared_object_data.entries.at(idx).object;
computed_shared.insert(obj);
}
@ -923,7 +923,7 @@ QPDF::checkHSharedObject(std::list<std::string>& errors,
// The first nshared_first_page objects are consecutive
// objects starting with the first page object. The rest are
// consecutive starting from the first_shared_obj object.
int cur_object = pages[0].getObjectID();
int cur_object = pages.at(0).getObjectID();
for (int i = 0; i < so.nshared_total; ++i)
{
if (i == so.nshared_first_page)
@ -937,7 +937,7 @@ QPDF::checkHSharedObject(std::list<std::string>& errors,
}
else
{
int obj = this->part8[0].getObjectID();
int obj = this->part8.at(0).getObjectID();
if (obj != so.first_shared_obj)
{
errors.push_back(
@ -965,7 +965,7 @@ QPDF::checkHSharedObject(std::list<std::string>& errors,
}
idx_to_obj[i] = cur_object;
HSharedObjectEntry& se = so.entries[i];
HSharedObjectEntry& se = so.entries.at(i);
int nobjects = se.nobjects_minus_one + 1;
int length = lengthNextN(cur_object, nobjects, errors);
int h_length = so.min_group_length + se.delta_group_length;
@ -1146,7 +1146,7 @@ QPDF::dumpHPageOffset()
for (int i1 = 0; i1 < this->linp.npages; ++i1)
{
HPageOffsetEntry& pe = t.entries[i1];
HPageOffsetEntry& pe = t.entries.at(i1);
*out_stream
<< "Page " << i1 << ":" << std::endl
<< " nobjects: " << pe.delta_nobjects + t.min_nobjects
@ -1162,9 +1162,9 @@ QPDF::dumpHPageOffset()
for (int i2 = 0; i2 < pe.nshared_objects; ++i2)
{
*out_stream << " identifier " << i2 << ": "
<< pe.shared_identifiers[i2] << std::endl;
<< pe.shared_identifiers.at(i2) << std::endl;
*out_stream << " numerator " << i2 << ": "
<< pe.shared_numerators[i2] << std::endl;
<< pe.shared_numerators.at(i2) << std::endl;
}
}
}
@ -1191,7 +1191,7 @@ QPDF::dumpHSharedObject()
for (int i = 0; i < t.nshared_total; ++i)
{
HSharedObjectEntry& se = t.entries[i];
HSharedObjectEntry& se = t.entries.at(i);
*out_stream << "Shared Object " << i << ":" << std::endl;
*out_stream << " group length: "
<< se.delta_group_length + t.min_group_length << std::endl;
@ -1522,7 +1522,7 @@ QPDF::calculateLinearizationData(std::map<int, int> const& object_stream_data)
// will do the same.
// First, place the actual first page object itself.
QPDFObjGen first_page_og(pages[0].getObjGen());
QPDFObjGen first_page_og(pages.at(0).getObjGen());
if (! lc_first_page_private.count(first_page_og))
{
throw std::logic_error(
@ -1530,8 +1530,8 @@ QPDF::calculateLinearizationData(std::map<int, int> const& object_stream_data)
"object not in lc_first_page_private");
}
lc_first_page_private.erase(first_page_og);
this->c_linp.first_page_object = pages[0].getObjectID();
this->part6.push_back(pages[0]);
this->c_linp.first_page_object = pages.at(0).getObjectID();
this->part6.push_back(pages.at(0));
// The PDF spec "recommends" an order for the rest of the objects,
// but we are going to disregard it except to the extent that it
@ -1562,7 +1562,7 @@ QPDF::calculateLinearizationData(std::map<int, int> const& object_stream_data)
// in garbage values for all the shared object identifiers on the
// first page.
this->c_page_offset_data.entries[0].nobjects = this->part6.size();
this->c_page_offset_data.entries.at(0).nobjects = this->part6.size();
// Part 7: other pages' private objects
@ -1571,7 +1571,7 @@ QPDF::calculateLinearizationData(std::map<int, int> const& object_stream_data)
{
// Place this page's page object
QPDFObjGen page_og(pages[i].getObjGen());
QPDFObjGen page_og(pages.at(i).getObjGen());
if (! lc_other_page_private.count(page_og))
{
throw std::logic_error(
@ -1580,12 +1580,12 @@ QPDF::calculateLinearizationData(std::map<int, int> const& object_stream_data)
QUtil::int_to_string(i) + " not in lc_other_page_private");
}
lc_other_page_private.erase(page_og);
this->part7.push_back(pages[i]);
this->part7.push_back(pages.at(i));
// Place all non-shared objects referenced by this page,
// updating the page object count for the hint table.
this->c_page_offset_data.entries[i].nobjects = 1;
this->c_page_offset_data.entries.at(i).nobjects = 1;
ObjUser ou(ObjUser::ou_page, i);
assert(this->obj_user_to_objects.count(ou) > 0);
@ -1598,7 +1598,7 @@ QPDF::calculateLinearizationData(std::map<int, int> const& object_stream_data)
{
lc_other_page_private.erase(og);
this->part7.push_back(objGenToIndirect(og));
++this->c_page_offset_data.entries[i].nobjects;
++this->c_page_offset_data.entries.at(i).nobjects;
}
}
}
@ -1649,7 +1649,7 @@ QPDF::calculateLinearizationData(std::map<int, int> const& object_stream_data)
// thumbnail hint tables.
for (unsigned int i = 0; i < npages; ++i)
{
QPDFObjectHandle thumb = pages[i].getKey("/Thumb");
QPDFObjectHandle thumb = pages.at(i).getKey("/Thumb");
thumb = getUncompressedObject(thumb, object_stream_data);
if (! thumb.isNull())
{
@ -1758,7 +1758,7 @@ QPDF::calculateLinearizationData(std::map<int, int> const& object_stream_data)
if (! this->part8.empty())
{
this->c_shared_object_data.first_shared_obj =
this->part8[0].getObjectID();
this->part8.at(0).getObjectID();
for (std::vector<QPDFObjectHandle>::iterator iter =
this->part8.begin();
iter != this->part8.end(); ++iter)
@ -1781,7 +1781,7 @@ QPDF::calculateLinearizationData(std::map<int, int> const& object_stream_data)
for (unsigned int i = 1; i < npages; ++i)
{
CHPageOffsetEntry& pe = this->c_page_offset_data.entries[i];
CHPageOffsetEntry& pe = this->c_page_offset_data.entries.at(i);
ObjUser ou(ObjUser::ou_page, i);
assert(this->obj_user_to_objects.count(ou) > 0);
std::set<QPDFObjGen> const& ogs = this->obj_user_to_objects[ou];
@ -1892,12 +1892,12 @@ QPDF::calculateHPageOffset(
// Calculate minimum and maximum values for number of objects per
// page and page length.
int min_nobjects = cphe[0].nobjects;
int min_nobjects = cphe.at(0).nobjects;
int max_nobjects = min_nobjects;
int min_length = outputLengthNextN(
pages[0].getObjectID(), min_nobjects, lengths, obj_renumber);
pages.at(0).getObjectID(), min_nobjects, lengths, obj_renumber);
int max_length = min_length;
int max_shared = cphe[0].nshared_objects;
int max_shared = cphe.at(0).nshared_objects;
HPageOffset& ph = this->page_offset_hints;
std::vector<HPageOffsetEntry>& phe = ph.entries;
@ -1912,10 +1912,10 @@ QPDF::calculateHPageOffset(
// Repeat calculations for page 0 so we can assign to phe[i]
// without duplicating those assignments.
int nobjects = cphe[i].nobjects;
int nobjects = cphe.at(i).nobjects;
int length = outputLengthNextN(
pages[i].getObjectID(), nobjects, lengths, obj_renumber);
int nshared = cphe[i].nshared_objects;
pages.at(i).getObjectID(), nobjects, lengths, obj_renumber);
int nshared = cphe.at(i).nshared_objects;
min_nobjects = std::min(min_nobjects, nobjects);
max_nobjects = std::max(max_nobjects, nobjects);
@ -1923,13 +1923,13 @@ QPDF::calculateHPageOffset(
max_length = std::max(max_length, length);
max_shared = std::max(max_shared, nshared);
phe[i].delta_nobjects = nobjects;
phe[i].delta_page_length = length;
phe[i].nshared_objects = nshared;
phe.at(i).delta_nobjects = nobjects;
phe.at(i).delta_page_length = length;
phe.at(i).nshared_objects = nshared;
}
ph.min_nobjects = min_nobjects;
int in_page0_id = pages[0].getObjectID();
int in_page0_id = pages.at(0).getObjectID();
int out_page0_id = (*(obj_renumber.find(in_page0_id))).second;
ph.first_page_offset = (*(xref.find(out_page0_id))).second.getOffset();
ph.nbits_delta_nobjects = nbits(max_nobjects - min_nobjects);
@ -1951,17 +1951,17 @@ QPDF::calculateHPageOffset(
for (unsigned int i = 0; i < npages; ++i)
{
// Adjust delta entries
assert(phe[i].delta_nobjects >= min_nobjects);
assert(phe[i].delta_page_length >= min_length);
phe[i].delta_nobjects -= min_nobjects;
phe[i].delta_page_length -= min_length;
phe[i].delta_content_length = phe[i].delta_page_length;
assert(phe.at(i).delta_nobjects >= min_nobjects);
assert(phe.at(i).delta_page_length >= min_length);
phe.at(i).delta_nobjects -= min_nobjects;
phe.at(i).delta_page_length -= min_length;
phe.at(i).delta_content_length = phe.at(i).delta_page_length;
for (int j = 0; j < cphe[i].nshared_objects; ++j)
for (int j = 0; j < cphe.at(i).nshared_objects; ++j)
{
phe[i].shared_identifiers.push_back(
cphe[i].shared_identifiers[j]);
phe[i].shared_numerators.push_back(0);
phe.at(i).shared_identifiers.push_back(
cphe.at(i).shared_identifiers.at(j));
phe.at(i).shared_numerators.push_back(0);
}
}
}
@ -1979,18 +1979,18 @@ QPDF::calculateHSharedObject(
soe.clear();
int min_length = outputLengthNextN(
csoe[0].object, 1, lengths, obj_renumber);
csoe.at(0).object, 1, lengths, obj_renumber);
int max_length = min_length;
for (int i = 0; i < cso.nshared_total; ++i)
{
// Assign absolute numbers to deltas; adjust later
int length = outputLengthNextN(
csoe[i].object, 1, lengths, obj_renumber);
csoe.at(i).object, 1, lengths, obj_renumber);
min_length = std::min(min_length, length);
max_length = std::max(max_length, length);
soe.push_back(HSharedObjectEntry());
soe[i].delta_group_length = length;
soe.at(i).delta_group_length = length;
}
if (soe.size() != static_cast<size_t>(cso.nshared_total))
{
@ -2012,8 +2012,8 @@ QPDF::calculateHSharedObject(
for (int i = 0; i < cso.nshared_total; ++i)
{
// Adjust deltas
assert(soe[i].delta_group_length >= min_length);
soe[i].delta_group_length -= min_length;
assert(soe.at(i).delta_group_length >= min_length);
soe.at(i).delta_group_length -= min_length;
}
}
@ -2051,7 +2051,7 @@ write_vector_int(BitWriter& w, int nitems, std::vector<T>& vec,
for (int i = 0; i < nitems; ++i)
{
w.writeBits(vec[i].*field, bits);
w.writeBits(vec.at(i).*field, bits);
}
// The PDF spec says that each hint table starts at a byte
// boundary. Each "row" actually must start on a byte boundary.
@ -2068,9 +2068,9 @@ write_vector_vector(BitWriter& w,
// from the vec2 vector field of the ith item of vec1.
for (int i1 = 0; i1 < nitems1; ++i1)
{
for (int i2 = 0; i2 < vec1[i1].*nitems2; ++i2)
for (int i2 = 0; i2 < vec1.at(i1).*nitems2; ++i2)
{
w.writeBits((vec1[i1].*vec2)[i2], bits);
w.writeBits((vec1.at(i1).*vec2).at(i2), bits);
}
}
w.flush();
@ -2151,7 +2151,7 @@ QPDF::writeHSharedObject(BitWriter& w)
for (int i = 0; i < nitems; ++i)
{
// If signature were present, we'd have to write a 128-bit hash.
assert(entries[i].signature_present == 0);
assert(entries.at(i).signature_present == 0);
}
write_vector_int(w, nitems, entries,
t.nbits_nobjects,

View File

@ -91,7 +91,7 @@ QPDF::optimize(std::map<int, int> const& object_stream_data,
for (int pageno = 0; pageno < n; ++pageno)
{
updateObjectMaps(ObjUser(ObjUser::ou_page, pageno),
this->all_pages[pageno]);
this->all_pages.at(pageno));
}
// Traverse document-level items

View File

@ -114,8 +114,8 @@ QPDF::flattenPagesTree()
for (int pos = 0; pos < len; ++pos)
{
// populate pageobj_to_pages_pos and fix parent pointer
insertPageobjToPage(this->all_pages[pos], pos, true);
this->all_pages[pos].replaceKey("/Parent", pages);
insertPageobjToPage(this->all_pages.at(pos), pos, true);
this->all_pages.at(pos).replaceKey("/Parent", pages);
}
pages.replaceKey("/Kids", QPDFObjectHandle::newArray(this->all_pages));
@ -194,7 +194,7 @@ QPDF::insertPage(QPDFObjectHandle newpage, int pos)
assert(this->all_pages.size() == static_cast<size_t>(npages));
for (int i = pos + 1; i < npages; ++i)
{
insertPageobjToPage(this->all_pages[i], i, false);
insertPageobjToPage(this->all_pages.at(i), i, false);
}
insertPageobjToPage(newpage, pos, true);
assert(this->pageobj_to_pages_pos.size() == static_cast<size_t>(npages));
@ -221,7 +221,7 @@ QPDF::removePage(QPDFObjectHandle page)
assert(this->pageobj_to_pages_pos.size() == static_cast<size_t>(npages));
for (int i = pos; i < npages; ++i)
{
insertPageobjToPage(this->all_pages[i], i, false);
insertPageobjToPage(this->all_pages.at(i), i, false);
}
}

View File

@ -201,7 +201,7 @@ QUtil::hex_encode(std::string const& input)
for (unsigned int i = 0; i < input.length(); ++i)
{
result += QUtil::int_to_string_base(
static_cast<int>(static_cast<unsigned char>(input[i])), 16, 2);
static_cast<int>(static_cast<unsigned char>(input.at(i))), 16, 2);
}
return result;
}

View File

@ -441,7 +441,7 @@ static std::vector<int> parse_numrange(char const* range, int max,
p = 0;
for (size_t i = 0; i < work.size(); i += 2)
{
int num = work[i];
int num = work.at(i);
// max == 0 means we don't know the max and are just
// testing for valid syntax.
if ((max > 0) && ((num < 1) || (num > max)))
@ -451,11 +451,11 @@ static std::vector<int> parse_numrange(char const* range, int max,
}
if (i == 0)
{
result.push_back(work[i]);
result.push_back(work.at(i));
}
else
{
int separator = work[i-1];
int separator = work.at(i-1);
if (separator == comma)
{
result.push_back(num);
@ -1664,7 +1664,7 @@ int main(int argc, char* argv[])
// Pages are specified from 1 but numbered
// from 0 in the vector
int pageno = *pageno_iter - 1;
pdf.addPage(page_data.orig_pages[pageno], false);
pdf.addPage(page_data.orig_pages.at(pageno), false);
if (page_data.qpdf == &pdf)
{
// This is a page from the original file.
@ -1683,7 +1683,7 @@ int main(int argc, char* argv[])
{
if (selected_from_orig.count(pageno) == 0)
{
pdf.replaceObject(orig_pages[pageno].getObjGen(),
pdf.replaceObject(orig_pages.at(pageno).getObjGen(),
QPDFObjectHandle::newNull());
}
}

View File

@ -603,10 +603,10 @@ void runtest(int n, char const* filename1, char const* arg2)
else if (n == 10)
{
std::vector<QPDFObjectHandle> pages = pdf.getAllPages();
pages[0].addPageContents(
pages.at(0).addPageContents(
QPDFObjectHandle::newStream(
&pdf, "BT /F1 12 Tf 72 620 Td (Baked) Tj ET\n"), true);
pages[0].addPageContents(
pages.at(0).addPageContents(
QPDFObjectHandle::newStream(
&pdf, "BT /F1 18 Tf 72 520 Td (Mashed) Tj ET\n"), false);
@ -659,7 +659,7 @@ void runtest(int n, char const* filename1, char const* arg2)
" not called 4-page file");
}
// Swap pages 2 and 3
pdf.swapObjects(pages[1].getObjGen(), pages[2].getObjGen());
pdf.swapObjects(pages.at(1).getObjGen(), pages.at(2).getObjGen());
// Replace object and swap objects
QPDFObjectHandle trailer = pdf.getTrailer();
QPDFObjectHandle qdict = trailer.getKey("/QDict");
@ -700,7 +700,7 @@ void runtest(int n, char const* filename1, char const* arg2)
std::map<std::string, QPDFObjectHandle> dict_items =
qarray.getDictAsMap();
if ((array_elements.size() == 1) &&
(array_elements[0].getName() == "/Array") &&
(array_elements.at(0).getName() == "/Array") &&
(dict_items.size() == 1) &&
(dict_items["/NewDict"].getIntValue() == 2))
{
@ -738,12 +738,12 @@ void runtest(int n, char const* filename1, char const* arg2)
assert(pages.size() == 9);
pdf.removePage(*pages.begin()); // original page 0
assert(pages.size() == 8);
checkPageContents(pages[4], "Original page 5");
pdf.removePage(pages[4]); // original page 5
checkPageContents(pages.at(4), "Original page 5");
pdf.removePage(pages.at(4)); // original page 5
assert(pages.size() == 7);
checkPageContents(pages[4], "Original page 6");
checkPageContents(pages[0], "Original page 1");
checkPageContents(pages[6], "Original page 8");
checkPageContents(pages.at(4), "Original page 6");
checkPageContents(pages.at(0), "Original page 1");
checkPageContents(pages.at(6), "Original page 8");
// Insert pages
@ -760,7 +760,7 @@ void runtest(int n, char const* filename1, char const* arg2)
// dictionary and modify it. Using the results of
// getDictAsMap to create a new dictionary effectively creates
// a shallow copy.
QPDFObjectHandle page_template = pages[0];
QPDFObjectHandle page_template = pages.at(0);
std::vector<QPDFObjectHandle> new_pages;
for (std::vector<QPDFObjectHandle>::iterator iter = contents.begin();
iter != contents.end(); ++iter)
@ -781,25 +781,25 @@ void runtest(int n, char const* filename1, char const* arg2)
}
// Now insert the pages
pdf.addPage(new_pages[0], true);
checkPageContents(pages[0], "New page 1");
pdf.addPageAt(new_pages[1], true, pages[0]);
assert(pages[0].getObjGen() == new_pages[1].getObjGen());
pdf.addPageAt(new_pages[2], true, pages[5]);
assert(pages[5].getObjGen() == new_pages[2].getObjGen());
pdf.addPageAt(new_pages[3], false, pages[5]);
assert(pages[6].getObjGen() == new_pages[3].getObjGen());
pdf.addPage(new_pages.at(0), true);
checkPageContents(pages.at(0), "New page 1");
pdf.addPageAt(new_pages.at(1), true, pages.at(0));
assert(pages.at(0).getObjGen() == new_pages.at(1).getObjGen());
pdf.addPageAt(new_pages.at(2), true, pages.at(5));
assert(pages.at(5).getObjGen() == new_pages.at(2).getObjGen());
pdf.addPageAt(new_pages.at(3), false, pages.at(5));
assert(pages.at(6).getObjGen() == new_pages.at(3).getObjGen());
assert(pages.size() == 11);
pdf.addPage(new_pages[4], false);
assert(pages[11].getObjGen() == new_pages[4].getObjGen());
pdf.addPageAt(new_pages[5], false, pages.back());
pdf.addPage(new_pages.at(4), false);
assert(pages.at(11).getObjGen() == new_pages.at(4).getObjGen());
pdf.addPageAt(new_pages.at(5), false, pages.back());
assert(pages.size() == 13);
checkPageContents(pages[0], "New page 0");
checkPageContents(pages[1], "New page 1");
checkPageContents(pages[5], "New page 5");
checkPageContents(pages[6], "New page 6");
checkPageContents(pages[11], "New page 11");
checkPageContents(pages[12], "New page 12");
checkPageContents(pages.at(0), "New page 0");
checkPageContents(pages.at(1), "New page 1");
checkPageContents(pages.at(5), "New page 5");
checkPageContents(pages.at(6), "New page 6");
checkPageContents(pages.at(11), "New page 11");
checkPageContents(pages.at(12), "New page 12");
// Exercise writing to FILE*
FILE* out = QUtil::safe_fopen("a.pdf", "wb");
@ -816,7 +816,7 @@ void runtest(int n, char const* filename1, char const* arg2)
QPDFObjectHandle contents = createPageContents(pdf, "New page 10");
QPDFObjectHandle page =
pdf.makeIndirectObject(
QPDFObjectHandle(all_pages[0]).shallowCopy());
QPDFObjectHandle(all_pages.at(0)).shallowCopy());
page.replaceKey("/Contents", contents);
// Insert the page manually.
@ -843,7 +843,7 @@ void runtest(int n, char const* filename1, char const* arg2)
// The input file to this test case is broken to exercise an
// error condition.
std::vector<QPDFObjectHandle> const& pages = pdf.getAllPages();
pdf.removePage(pages[0]);
pdf.removePage(pages.at(0));
std::cout << "you can't see this" << std::endl;
}
else if (n == 18)
@ -854,7 +854,7 @@ void runtest(int n, char const* filename1, char const* arg2)
// Remove pages from various places, checking to make sure
// that our pages reference is getting updated.
assert(pages.size() == 10);
QPDFObjectHandle page5 = pages[5];
QPDFObjectHandle page5 = pages.at(5);
pdf.removePage(page5);
pdf.addPage(page5, false);
assert(pages.size() == 10);
@ -871,7 +871,7 @@ void runtest(int n, char const* filename1, char const* arg2)
std::vector<QPDFObjectHandle> const& pages = pdf.getAllPages();
// Try to insert a page that's already there.
pdf.addPage(pages[5], false);
pdf.addPage(pages.at(5), false);
std::cout << "you can't see this" << std::endl;
}
else if (n == 20)
@ -893,7 +893,7 @@ void runtest(int n, char const* filename1, char const* arg2)
{
// Try to shallow copy a stream
std::vector<QPDFObjectHandle> const& pages = pdf.getAllPages();
QPDFObjectHandle page = pages[0];
QPDFObjectHandle page = pages.at(0);
QPDFObjectHandle contents = page.getKey("/Contents");
contents.shallowCopy();
std::cout << "you can't see this" << std::endl;
@ -902,7 +902,7 @@ void runtest(int n, char const* filename1, char const* arg2)
{
// Try to remove a page we don't have
std::vector<QPDFObjectHandle> const& pages = pdf.getAllPages();
QPDFObjectHandle page = pages[0];
QPDFObjectHandle page = pages.at(0);
pdf.removePage(page);
pdf.removePage(page);
std::cout << "you can't see this" << std::endl;
@ -1109,9 +1109,9 @@ void runtest(int n, char const* filename1, char const* arg2)
QPDF final;
final.processFile("b.pdf", "user");
std::vector<QPDFObjectHandle> pages = pdf.getAllPages();
std::string orig_contents = getPageContents(pages[0]);
std::string orig_contents = getPageContents(pages.at(0));
pages = final.getAllPages();
std::string new_contents = getPageContents(pages[0]);
std::string new_contents = getPageContents(pages.at(0));
if (orig_contents != new_contents)
{
std::cout << "oops -- page contents don't match" << std::endl
@ -1226,7 +1226,7 @@ void runtest(int n, char const* filename1, char const* arg2)
bool is_binary = false;
for (size_t i = 0; i < data.size(); ++i)
{
if ((data[i] < 0) || (data[i] > 126))
if ((data.at(i) < 0) || (data.at(i) > 126))
{
is_binary = true;
break;
@ -1239,9 +1239,9 @@ void runtest(int n, char const* filename1, char const* arg2)
i < std::min(data.size(), static_cast<size_t>(20));
++i)
{
if ((data[i] >= 32) && (data[i] <= 126))
if ((data.at(i) >= 32) && (data.at(i) <= 126))
{
t += data[i];
t += data.at(i);
}
else
{

View File

@ -286,8 +286,8 @@ static void check_pdf(char const* filename)
{
int pageno = i + 1;
std::cout << "page " << pageno << " of " << npages << std::endl;
check_page_contents(pageno, pages[i]);
check_image(pageno, pages[i]);
check_page_contents(pageno, pages.at(i));
check_image(pageno, pages.at(i));
}
}