/src/qpdf/libqpdf/Pl_ASCII85Decoder.cc
Line | Count | Source |
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 | 25.0k | Pipeline(identifier, next) |
9 | 25.0k | { |
10 | 25.0k | if (!next) { |
11 | 0 | throw std::logic_error("Attempt to create Pl_ASCII85Decoder with nullptr as next"); |
12 | 0 | } |
13 | 25.0k | } |
14 | | |
15 | | void |
16 | | Pl_ASCII85Decoder::write(unsigned char const* buf, size_t len) |
17 | 25.6k | { |
18 | 25.6k | if (eod > 1) { |
19 | 802 | return; |
20 | 802 | } |
21 | 10.1M | for (size_t i = 0; i < len; ++i) { |
22 | 10.0M | switch (buf[i]) { |
23 | 26.7k | case ' ': |
24 | 87.2k | case '\f': |
25 | 92.4k | case '\v': |
26 | 97.5k | case '\t': |
27 | 117k | case '\r': |
28 | 220k | case '\n': |
29 | 220k | QTC::TC("libtests", "Pl_ASCII85Decoder ignore space"); |
30 | | // ignore whitespace |
31 | 220k | continue; |
32 | 10.0M | } |
33 | 9.86M | if (eod > 1) { |
34 | 1.37k | break; |
35 | 9.86M | } else if (eod == 1) { |
36 | 8.31k | if (buf[i] == '>') { |
37 | 7.86k | flush(); |
38 | 7.86k | eod = 2; |
39 | 7.86k | } else { |
40 | 458 | throw std::runtime_error("broken end-of-data sequence in base 85 data"); |
41 | 458 | } |
42 | 9.85M | } else { |
43 | 9.85M | switch (buf[i]) { |
44 | 9.19k | case '~': |
45 | 9.19k | eod = 1; |
46 | 9.19k | break; |
47 | | |
48 | 16.2k | case 'z': |
49 | 16.2k | if (pos != 0) { |
50 | 376 | throw std::runtime_error("unexpected z during base 85 decode"); |
51 | 15.9k | } else { |
52 | 15.9k | QTC::TC("libtests", "Pl_ASCII85Decoder read z"); |
53 | 15.9k | unsigned char zeroes[4]; |
54 | 15.9k | memset(zeroes, '\0', 4); |
55 | 15.9k | next()->write(zeroes, 4); |
56 | 15.9k | } |
57 | 15.9k | break; |
58 | | |
59 | 9.83M | default: |
60 | 9.83M | if (buf[i] < 33 || buf[i] > 117) { |
61 | 7.26k | error = true; |
62 | 7.26k | throw std::runtime_error("character out of range during base 85 decode"); |
63 | 9.82M | } else { |
64 | 9.82M | this->inbuf[this->pos++] = buf[i]; |
65 | 9.82M | if (pos == 5) { |
66 | 1.95M | flush(); |
67 | 1.95M | } |
68 | 9.82M | } |
69 | 9.82M | break; |
70 | 9.85M | } |
71 | 9.85M | } |
72 | 9.86M | } |
73 | 24.8k | } |
74 | | |
75 | | void |
76 | | Pl_ASCII85Decoder::flush() |
77 | 1.98M | { |
78 | 1.98M | if (this->pos == 0) { |
79 | 14.5k | QTC::TC("libtests", "Pl_ASCII85Decoder no-op flush"); |
80 | 14.5k | return; |
81 | 14.5k | } |
82 | 1.96M | unsigned long lval = 0; |
83 | 11.8M | for (int i = 0; i < 5; ++i) { |
84 | 9.84M | lval *= 85; |
85 | 9.84M | lval += (this->inbuf[i] - 33U); |
86 | 9.84M | } |
87 | | |
88 | 1.96M | unsigned char outbuf[4]; |
89 | 1.96M | memset(outbuf, 0, 4); |
90 | 9.84M | for (int i = 3; i >= 0; --i) { |
91 | 7.87M | outbuf[i] = lval & 0xff; |
92 | 7.87M | lval >>= 8; |
93 | 7.87M | } |
94 | | |
95 | 1.96M | 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 | 1.96M | auto t = this->pos - 1; |
98 | 1.96M | this->pos = 0; |
99 | 1.96M | memset(this->inbuf, 117, 5); |
100 | | |
101 | 1.96M | next()->write(outbuf, t); |
102 | 1.96M | } |
103 | | |
104 | | void |
105 | | Pl_ASCII85Decoder::finish() |
106 | 22.9k | { |
107 | 22.9k | if (error) { |
108 | 5.46k | return; |
109 | 5.46k | } |
110 | 17.4k | flush(); |
111 | 17.4k | next()->finish(); |
112 | 17.4k | } |