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