/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 | 138 | Pipeline(identifier, next) |
14 | 138 | { |
15 | 138 | util::assertion(next, "Attempt to create Pl_ASCIIHexDecoder with nullptr as next"); |
16 | 138 | } |
17 | | |
18 | | void |
19 | | Pl_ASCIIHexDecoder::write(unsigned char const* buf, size_t len) |
20 | 138 | { |
21 | 138 | if (eod) { |
22 | 0 | return; |
23 | 0 | } |
24 | 72.2k | for (size_t i = 0; i < len; ++i) { |
25 | 72.1k | char ch = static_cast<char>(toupper(buf[i])); |
26 | 72.1k | switch (ch) { |
27 | 194 | case ' ': |
28 | 484 | case '\f': |
29 | 816 | case '\v': |
30 | 1.02k | case '\t': |
31 | 1.22k | case '\r': |
32 | 1.47k | case '\n': |
33 | 1.47k | QTC::TC("libtests", "Pl_ASCIIHexDecoder ignore space"); |
34 | | // ignore whitespace |
35 | 1.47k | break; |
36 | | |
37 | 7 | case '>': |
38 | 7 | eod = true; |
39 | 7 | flush(); |
40 | 7 | break; |
41 | | |
42 | 70.6k | default: |
43 | 70.6k | if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F')) { |
44 | 70.6k | inbuf[pos++] = ch; |
45 | 70.6k | if (pos == 2) { |
46 | 35.3k | flush(); |
47 | 35.3k | } |
48 | 70.6k | } else { |
49 | 42 | char t[2]; |
50 | 42 | t[0] = ch; |
51 | 42 | t[1] = 0; |
52 | 42 | throw std::runtime_error("character out of range during base Hex decode: "s + t); |
53 | 42 | } |
54 | 70.6k | break; |
55 | 72.1k | } |
56 | 72.1k | if (eod) { |
57 | 7 | break; |
58 | 7 | } |
59 | 72.1k | } |
60 | 138 | } |
61 | | |
62 | | void |
63 | | Pl_ASCIIHexDecoder::flush() |
64 | 35.4k | { |
65 | 35.4k | if (pos == 0) { |
66 | 80 | QTC::TC("libtests", "Pl_ASCIIHexDecoder no-op flush"); |
67 | 80 | return; |
68 | 80 | } |
69 | 35.3k | int b[2]; |
70 | 105k | for (int i = 0; i < 2; ++i) { |
71 | 70.6k | if (inbuf[i] >= 'A') { |
72 | 70.1k | b[i] = inbuf[i] - 'A' + 10; |
73 | 70.1k | } else { |
74 | 556 | b[i] = inbuf[i] - '0'; |
75 | 556 | } |
76 | 70.6k | } |
77 | 35.3k | auto ch = static_cast<unsigned char>((b[0] << 4) + b[1]); |
78 | | |
79 | 35.3k | QTC::TC("libtests", "Pl_ASCIIHexDecoder partial flush", (pos == 2) ? 0 : 1); |
80 | | // Reset before calling getNext()->write in case that throws an exception. |
81 | 35.3k | pos = 0; |
82 | 35.3k | inbuf[0] = '0'; |
83 | 35.3k | inbuf[1] = '0'; |
84 | 35.3k | inbuf[2] = '\0'; |
85 | | |
86 | 35.3k | next()->write(&ch, 1); |
87 | 35.3k | } |
88 | | |
89 | | void |
90 | | Pl_ASCIIHexDecoder::finish() |
91 | 96 | { |
92 | 96 | flush(); |
93 | 96 | next()->finish(); |
94 | 96 | } |