/src/qpdf/libqpdf/Pl_ASCII85Decoder.cc
Line | Count | Source |
1 | | #include <qpdf/Pl_ASCII85Decoder.hh> |
2 | | |
3 | | #include <qpdf/QTC.hh> |
4 | | #include <qpdf/Util.hh> |
5 | | |
6 | | #include <cstring> |
7 | | #include <stdexcept> |
8 | | |
9 | | using namespace qpdf; |
10 | | |
11 | | Pl_ASCII85Decoder::Pl_ASCII85Decoder(char const* identifier, Pipeline* next) : |
12 | 36.3k | Pipeline(identifier, next) |
13 | 36.3k | { |
14 | 36.3k | util::assertion(next, "Attempt to create Pl_ASCII85Decoder with nullptr as next"); |
15 | 36.3k | } |
16 | | |
17 | | void |
18 | | Pl_ASCII85Decoder::write(unsigned char const* buf, size_t len) |
19 | 44.0k | { |
20 | 44.0k | if (eod > 1) { |
21 | 4.74k | return; |
22 | 4.74k | } |
23 | 8.60M | for (size_t i = 0; i < len; ++i) { |
24 | 8.58M | switch (buf[i]) { |
25 | 61.6k | case ' ': |
26 | 66.3k | case '\f': |
27 | 71.3k | case '\v': |
28 | 75.7k | case '\t': |
29 | 94.0k | case '\r': |
30 | 163k | case '\n': |
31 | 163k | QTC::TC("libtests", "Pl_ASCII85Decoder ignore space"); |
32 | | // ignore whitespace |
33 | 163k | continue; |
34 | 8.58M | } |
35 | 8.42M | if (eod > 1) { |
36 | 2.51k | break; |
37 | 8.41M | } else if (eod == 1) { |
38 | 11.8k | util::no_ci_rt_error_if(buf[i] != '>', "broken end-of-data sequence in base 85 data"); |
39 | 11.8k | flush(); |
40 | 11.8k | eod = 2; |
41 | 8.40M | } else { |
42 | 8.40M | switch (buf[i]) { |
43 | 12.8k | case '~': |
44 | 12.8k | eod = 1; |
45 | 12.8k | break; |
46 | | |
47 | 20.6k | case 'z': |
48 | 20.6k | if (pos != 0) { |
49 | 525 | throw std::runtime_error("unexpected z during base 85 decode"); |
50 | 525 | } |
51 | 20.0k | unsigned char zeroes[4]; |
52 | 20.0k | memset(zeroes, '\0', 4); |
53 | 20.0k | next()->write(zeroes, 4); |
54 | 20.0k | break; |
55 | | |
56 | 8.37M | default: |
57 | 8.37M | if (buf[i] < 33 || buf[i] > 117) { |
58 | 11.4k | error = true; |
59 | 11.4k | throw std::runtime_error("character out of range during base 85 decode"); |
60 | 8.36M | } else { |
61 | 8.36M | this->inbuf[this->pos++] = buf[i]; |
62 | 8.36M | if (pos == 5) { |
63 | 1.66M | flush(); |
64 | 1.66M | } |
65 | 8.36M | } |
66 | 8.36M | break; |
67 | 8.40M | } |
68 | 8.40M | } |
69 | 8.42M | } |
70 | 39.2k | } |
71 | | |
72 | | void |
73 | | Pl_ASCII85Decoder::flush() |
74 | 1.69M | { |
75 | 1.69M | if (this->pos == 0) { |
76 | 20.3k | return; |
77 | 20.3k | } |
78 | 1.67M | unsigned long lval = 0; |
79 | 10.0M | for (int i = 0; i < 5; ++i) { |
80 | 8.38M | lval *= 85; |
81 | 8.38M | lval += (this->inbuf[i] - 33U); |
82 | 8.38M | } |
83 | | |
84 | 1.67M | unsigned char outbuf[4]; |
85 | 1.67M | memset(outbuf, 0, 4); |
86 | 8.38M | for (int i = 3; i >= 0; --i) { |
87 | 6.71M | outbuf[i] = lval & 0xff; |
88 | 6.71M | lval >>= 8; |
89 | 6.71M | } |
90 | | |
91 | 1.67M | QTC::TC("libtests", "Pl_ASCII85Decoder partial flush", (this->pos == 5) ? 0 : 1); |
92 | | // Reset before calling getNext()->write in case that throws an exception. |
93 | 1.67M | auto t = this->pos - 1; |
94 | 1.67M | this->pos = 0; |
95 | 1.67M | memset(this->inbuf, 117, 5); |
96 | | |
97 | 1.67M | next()->write(outbuf, t); |
98 | 1.67M | } |
99 | | |
100 | | void |
101 | | Pl_ASCII85Decoder::finish() |
102 | 34.0k | { |
103 | 34.0k | if (error) { |
104 | 7.77k | return; |
105 | 7.77k | } |
106 | 26.3k | flush(); |
107 | 26.3k | next()->finish(); |
108 | 26.3k | } |