/src/qpdf/libqpdf/Pl_ASCII85Decoder.cc
Line | Count | Source (jump to first uncovered line) |
1 | | #include <qpdf/Pl_ASCII85Decoder.hh> |
2 | | |
3 | | #include <qpdf/QTC.hh> |
4 | | #include <cstring> |
5 | | #include <stdexcept> |
6 | | |
7 | | Pl_ASCII85Decoder::Pl_ASCII85Decoder(char const* identifier, Pipeline* next) : |
8 | 3.55k | Pipeline(identifier, next) |
9 | 3.55k | { |
10 | 3.55k | if (!next) { |
11 | 0 | throw std::logic_error("Attempt to create Pl_ASCII85Decoder with nullptr as next"); |
12 | 0 | } |
13 | 3.55k | } |
14 | | |
15 | | void |
16 | | Pl_ASCII85Decoder::write(unsigned char const* buf, size_t len) |
17 | 3.24k | { |
18 | 3.24k | if (eod > 1) { |
19 | 0 | return; |
20 | 0 | } |
21 | 1.37M | for (size_t i = 0; i < len; ++i) { |
22 | 1.37M | switch (buf[i]) { |
23 | 9.37k | case ' ': |
24 | 25.4k | case '\f': |
25 | 28.0k | case '\v': |
26 | 28.3k | case '\t': |
27 | 33.9k | case '\r': |
28 | 44.3k | case '\n': |
29 | 44.3k | QTC::TC("libtests", "Pl_ASCII85Decoder ignore space"); |
30 | | // ignore whitespace |
31 | 44.3k | continue; |
32 | 1.37M | } |
33 | 1.33M | if (eod > 1) { |
34 | 137 | break; |
35 | 1.33M | } else if (eod == 1) { |
36 | 1.99k | if (buf[i] == '>') { |
37 | 1.96k | flush(); |
38 | 1.96k | eod = 2; |
39 | 1.96k | } else { |
40 | 24 | throw std::runtime_error("broken end-of-data sequence in base 85 data"); |
41 | 24 | } |
42 | 1.32M | } else { |
43 | 1.32M | switch (buf[i]) { |
44 | 2.00k | case '~': |
45 | 2.00k | eod = 1; |
46 | 2.00k | break; |
47 | | |
48 | 1.62k | case 'z': |
49 | 1.62k | if (pos != 0) { |
50 | 32 | throw std::runtime_error("unexpected z during base 85 decode"); |
51 | 1.58k | } else { |
52 | 1.58k | QTC::TC("libtests", "Pl_ASCII85Decoder read z"); |
53 | 1.58k | unsigned char zeroes[4]; |
54 | 1.58k | memset(zeroes, '\0', 4); |
55 | 1.58k | next()->write(zeroes, 4); |
56 | 1.58k | } |
57 | 1.58k | break; |
58 | | |
59 | 1.32M | default: |
60 | 1.32M | if (buf[i] < 33 || buf[i] > 117) { |
61 | 657 | error = true; |
62 | 657 | throw std::runtime_error("character out of range during base 85 decode"); |
63 | 1.32M | } else { |
64 | 1.32M | this->inbuf[this->pos++] = buf[i]; |
65 | 1.32M | if (pos == 5) { |
66 | 263k | flush(); |
67 | 263k | } |
68 | 1.32M | } |
69 | 1.32M | break; |
70 | 1.32M | } |
71 | 1.32M | } |
72 | 1.33M | } |
73 | 3.24k | } |
74 | | |
75 | | void |
76 | | Pl_ASCII85Decoder::flush() |
77 | 268k | { |
78 | 268k | if (this->pos == 0) { |
79 | 2.78k | QTC::TC("libtests", "Pl_ASCII85Decoder no-op flush"); |
80 | 2.78k | return; |
81 | 2.78k | } |
82 | 265k | unsigned long lval = 0; |
83 | 1.59M | for (int i = 0; i < 5; ++i) { |
84 | 1.32M | lval *= 85; |
85 | 1.32M | lval += (this->inbuf[i] - 33U); |
86 | 1.32M | } |
87 | | |
88 | 265k | unsigned char outbuf[4]; |
89 | 265k | memset(outbuf, 0, 4); |
90 | 1.32M | for (int i = 3; i >= 0; --i) { |
91 | 1.06M | outbuf[i] = lval & 0xff; |
92 | 1.06M | lval >>= 8; |
93 | 1.06M | } |
94 | | |
95 | 265k | QTC::TC("libtests", "Pl_ASCII85Decoder partial flush", (this->pos == 5) ? 0 : 1); |
96 | | // Reset before calling getNext()->write in case that throws an exception. |
97 | 265k | auto t = this->pos - 1; |
98 | 265k | this->pos = 0; |
99 | 265k | memset(this->inbuf, 117, 5); |
100 | | |
101 | 265k | next()->write(outbuf, t); |
102 | 265k | } |
103 | | |
104 | | void |
105 | | Pl_ASCII85Decoder::finish() |
106 | 3.23k | { |
107 | 3.23k | if (error) { |
108 | 500 | return; |
109 | 500 | } |
110 | 2.73k | flush(); |
111 | 2.73k | next()->finish(); |
112 | 2.73k | } |