/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 | 22.0k | Pipeline(identifier, next) |
11 | 22.0k | { |
12 | 22.0k | if (!next) { |
13 | 0 | throw std::logic_error("Attempt to create Pl_ASCIIHexDecoder with nullptr as next"); |
14 | 0 | } |
15 | 22.0k | } |
16 | | |
17 | | void |
18 | | Pl_ASCIIHexDecoder::write(unsigned char const* buf, size_t len) |
19 | 24.4k | { |
20 | 24.4k | if (this->eod) { |
21 | 2.96k | return; |
22 | 2.96k | } |
23 | 4.69M | for (size_t i = 0; i < len; ++i) { |
24 | 4.68M | char ch = static_cast<char>(toupper(buf[i])); |
25 | 4.68M | switch (ch) { |
26 | 122k | case ' ': |
27 | 126k | case '\f': |
28 | 131k | case '\v': |
29 | 137k | case '\t': |
30 | 142k | case '\r': |
31 | 150k | case '\n': |
32 | 150k | QTC::TC("libtests", "Pl_ASCIIHexDecoder ignore space"); |
33 | | // ignore whitespace |
34 | 150k | break; |
35 | | |
36 | 846 | case '>': |
37 | 846 | this->eod = true; |
38 | 846 | flush(); |
39 | 846 | break; |
40 | | |
41 | 4.53M | default: |
42 | 4.53M | if (((ch >= '0') && (ch <= '9')) || ((ch >= 'A') && (ch <= 'F'))) { |
43 | 4.52M | this->inbuf[this->pos++] = ch; |
44 | 4.52M | if (this->pos == 2) { |
45 | 2.25M | flush(); |
46 | 2.25M | } |
47 | 4.52M | } else { |
48 | 10.7k | char t[2]; |
49 | 10.7k | t[0] = ch; |
50 | 10.7k | t[1] = 0; |
51 | 10.7k | throw std::runtime_error("character out of range during base Hex decode: "s + t); |
52 | 10.7k | } |
53 | 4.52M | break; |
54 | 4.68M | } |
55 | 4.67M | if (this->eod) { |
56 | 843 | break; |
57 | 843 | } |
58 | 4.67M | } |
59 | 21.4k | } |
60 | | |
61 | | void |
62 | | Pl_ASCIIHexDecoder::flush() |
63 | 2.27M | { |
64 | 2.27M | if (this->pos == 0) { |
65 | 11.5k | QTC::TC("libtests", "Pl_ASCIIHexDecoder no-op flush"); |
66 | 11.5k | return; |
67 | 11.5k | } |
68 | 2.26M | int b[2]; |
69 | 6.80M | for (int i = 0; i < 2; ++i) { |
70 | 4.53M | if (this->inbuf[i] >= 'A') { |
71 | 1.34M | b[i] = this->inbuf[i] - 'A' + 10; |
72 | 3.19M | } else { |
73 | 3.19M | b[i] = this->inbuf[i] - '0'; |
74 | 3.19M | } |
75 | 4.53M | } |
76 | 2.26M | auto ch = static_cast<unsigned char>((b[0] << 4) + b[1]); |
77 | | |
78 | 2.26M | 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 | 2.26M | this->pos = 0; |
81 | 2.26M | this->inbuf[0] = '0'; |
82 | 2.26M | this->inbuf[1] = '0'; |
83 | 2.26M | this->inbuf[2] = '\0'; |
84 | | |
85 | 2.26M | next()->write(&ch, 1); |
86 | 2.26M | } |
87 | | |
88 | | void |
89 | | Pl_ASCIIHexDecoder::finish() |
90 | 18.3k | { |
91 | 18.3k | flush(); |
92 | 18.3k | next()->finish(); |
93 | 18.3k | } |