/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 | 29.7k | Pipeline(identifier, next) |
9 | 29.7k | { |
10 | 29.7k | if (!next) { |
11 | 0 | throw std::logic_error("Attempt to create Pl_ASCII85Decoder with nullptr as next"); |
12 | 0 | } |
13 | 29.7k | } |
14 | | |
15 | | void |
16 | | Pl_ASCII85Decoder::write(unsigned char const* buf, size_t len) |
17 | 30.3k | { |
18 | 30.3k | if (eod > 1) { |
19 | 1.28k | return; |
20 | 1.28k | } |
21 | 12.6M | for (size_t i = 0; i < len; ++i) { |
22 | 12.6M | switch (buf[i]) { |
23 | 24.4k | case ' ': |
24 | 77.9k | case '\f': |
25 | 83.9k | case '\v': |
26 | 88.7k | case '\t': |
27 | 100k | case '\r': |
28 | 227k | case '\n': |
29 | 227k | QTC::TC("libtests", "Pl_ASCII85Decoder ignore space"); |
30 | | // ignore whitespace |
31 | 227k | continue; |
32 | 12.6M | } |
33 | 12.4M | if (eod > 1) { |
34 | 1.49k | break; |
35 | 12.4M | } else if (eod == 1) { |
36 | 11.4k | if (buf[i] == '>') { |
37 | 11.0k | flush(); |
38 | 11.0k | eod = 2; |
39 | 11.0k | } else { |
40 | 453 | throw std::runtime_error("broken end-of-data sequence in base 85 data"); |
41 | 453 | } |
42 | 12.4M | } else { |
43 | 12.4M | switch (buf[i]) { |
44 | 12.4k | case '~': |
45 | 12.4k | eod = 1; |
46 | 12.4k | break; |
47 | | |
48 | 15.9k | case 'z': |
49 | 15.9k | if (pos != 0) { |
50 | 382 | throw std::runtime_error("unexpected z during base 85 decode"); |
51 | 15.5k | } else { |
52 | 15.5k | QTC::TC("libtests", "Pl_ASCII85Decoder read z"); |
53 | 15.5k | unsigned char zeroes[4]; |
54 | 15.5k | memset(zeroes, '\0', 4); |
55 | 15.5k | next()->write(zeroes, 4); |
56 | 15.5k | } |
57 | 15.5k | break; |
58 | | |
59 | 12.4M | default: |
60 | 12.4M | if (buf[i] < 33 || buf[i] > 117) { |
61 | 8.17k | error = true; |
62 | 8.17k | throw std::runtime_error("character out of range during base 85 decode"); |
63 | 12.3M | } else { |
64 | 12.3M | this->inbuf[this->pos++] = buf[i]; |
65 | 12.3M | if (pos == 5) { |
66 | 2.46M | flush(); |
67 | 2.46M | } |
68 | 12.3M | } |
69 | 12.3M | break; |
70 | 12.4M | } |
71 | 12.4M | } |
72 | 12.4M | } |
73 | 29.0k | } |
74 | | |
75 | | void |
76 | | Pl_ASCII85Decoder::flush() |
77 | 2.50M | { |
78 | 2.50M | if (this->pos == 0) { |
79 | 18.4k | QTC::TC("libtests", "Pl_ASCII85Decoder no-op flush"); |
80 | 18.4k | return; |
81 | 18.4k | } |
82 | 2.48M | unsigned long lval = 0; |
83 | 14.8M | for (int i = 0; i < 5; ++i) { |
84 | 12.4M | lval *= 85; |
85 | 12.4M | lval += (this->inbuf[i] - 33U); |
86 | 12.4M | } |
87 | | |
88 | 2.48M | unsigned char outbuf[4]; |
89 | 2.48M | memset(outbuf, 0, 4); |
90 | 12.4M | for (int i = 3; i >= 0; --i) { |
91 | 9.92M | outbuf[i] = lval & 0xff; |
92 | 9.92M | lval >>= 8; |
93 | 9.92M | } |
94 | | |
95 | 2.48M | 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 | 2.48M | auto t = this->pos - 1; |
98 | 2.48M | this->pos = 0; |
99 | 2.48M | memset(this->inbuf, 117, 5); |
100 | | |
101 | 2.48M | next()->write(outbuf, t); |
102 | 2.48M | } |
103 | | |
104 | | void |
105 | | Pl_ASCII85Decoder::finish() |
106 | 26.8k | { |
107 | 26.8k | if (error) { |
108 | 6.08k | return; |
109 | 6.08k | } |
110 | 20.7k | flush(); |
111 | 20.7k | next()->finish(); |
112 | 20.7k | } |