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