/src/qpdf/libqpdf/Pl_ASCIIHexDecoder.cc
Line | Count | Source (jump to first uncovered line) |
1 | | #include <qpdf/Pl_ASCIIHexDecoder.hh> |
2 | | |
3 | | #include <qpdf/QTC.hh> |
4 | | #include <cctype> |
5 | | #include <stdexcept> |
6 | | |
7 | | using namespace std::literals; |
8 | | |
9 | | Pl_ASCIIHexDecoder::Pl_ASCIIHexDecoder(char const* identifier, Pipeline* next) : |
10 | 0 | Pipeline(identifier, next) |
11 | 0 | { |
12 | 0 | if (!next) { |
13 | 0 | throw std::logic_error("Attempt to create Pl_ASCIIHexDecoder with nullptr as next"); |
14 | 0 | } |
15 | 0 | } |
16 | | |
17 | | void |
18 | | Pl_ASCIIHexDecoder::write(unsigned char const* buf, size_t len) |
19 | 0 | { |
20 | 0 | if (this->eod) { |
21 | 0 | return; |
22 | 0 | } |
23 | 0 | for (size_t i = 0; i < len; ++i) { |
24 | 0 | char ch = static_cast<char>(toupper(buf[i])); |
25 | 0 | switch (ch) { |
26 | 0 | case ' ': |
27 | 0 | case '\f': |
28 | 0 | case '\v': |
29 | 0 | case '\t': |
30 | 0 | case '\r': |
31 | 0 | case '\n': |
32 | 0 | QTC::TC("libtests", "Pl_ASCIIHexDecoder ignore space"); |
33 | | // ignore whitespace |
34 | 0 | break; |
35 | | |
36 | 0 | case '>': |
37 | 0 | this->eod = true; |
38 | 0 | flush(); |
39 | 0 | break; |
40 | | |
41 | 0 | default: |
42 | 0 | if (((ch >= '0') && (ch <= '9')) || ((ch >= 'A') && (ch <= 'F'))) { |
43 | 0 | this->inbuf[this->pos++] = ch; |
44 | 0 | if (this->pos == 2) { |
45 | 0 | flush(); |
46 | 0 | } |
47 | 0 | } else { |
48 | 0 | char t[2]; |
49 | 0 | t[0] = ch; |
50 | 0 | t[1] = 0; |
51 | 0 | throw std::runtime_error("character out of range during base Hex decode: "s + t); |
52 | 0 | } |
53 | 0 | break; |
54 | 0 | } |
55 | 0 | if (this->eod) { |
56 | 0 | break; |
57 | 0 | } |
58 | 0 | } |
59 | 0 | } |
60 | | |
61 | | void |
62 | | Pl_ASCIIHexDecoder::flush() |
63 | 0 | { |
64 | 0 | if (this->pos == 0) { |
65 | 0 | QTC::TC("libtests", "Pl_ASCIIHexDecoder no-op flush"); |
66 | 0 | return; |
67 | 0 | } |
68 | 0 | int b[2]; |
69 | 0 | for (int i = 0; i < 2; ++i) { |
70 | 0 | if (this->inbuf[i] >= 'A') { |
71 | 0 | b[i] = this->inbuf[i] - 'A' + 10; |
72 | 0 | } else { |
73 | 0 | b[i] = this->inbuf[i] - '0'; |
74 | 0 | } |
75 | 0 | } |
76 | 0 | auto ch = static_cast<unsigned char>((b[0] << 4) + b[1]); |
77 | |
|
78 | 0 | QTC::TC("libtests", "Pl_ASCIIHexDecoder partial flush", (this->pos == 2) ? 0 : 1); |
79 | | // Reset before calling getNext()->write in case that throws an exception. |
80 | 0 | this->pos = 0; |
81 | 0 | this->inbuf[0] = '0'; |
82 | 0 | this->inbuf[1] = '0'; |
83 | 0 | this->inbuf[2] = '\0'; |
84 | |
|
85 | 0 | next()->write(&ch, 1); |
86 | 0 | } |
87 | | |
88 | | void |
89 | | Pl_ASCIIHexDecoder::finish() |
90 | 0 | { |
91 | 0 | flush(); |
92 | 0 | next()->finish(); |
93 | 0 | } |