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