/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 | 148 | Pipeline(identifier, next) |
14 | 148 | { |
15 | 148 | util::assertion(next, "Attempt to create Pl_ASCIIHexDecoder with nullptr as next"); |
16 | 148 | } |
17 | | |
18 | | void |
19 | | Pl_ASCIIHexDecoder::write(unsigned char const* buf, size_t len) |
20 | 148 | { |
21 | 148 | if (eod) { |
22 | 0 | return; |
23 | 0 | } |
24 | 5.33k | for (size_t i = 0; i < len; ++i) { |
25 | 5.24k | char ch = static_cast<char>(toupper(buf[i])); |
26 | 5.24k | switch (ch) { |
27 | 197 | case ' ': |
28 | 391 | case '\f': |
29 | 597 | case '\v': |
30 | 797 | case '\t': |
31 | 1.00k | case '\r': |
32 | 1.24k | case '\n': |
33 | 1.24k | QTC::TC("libtests", "Pl_ASCIIHexDecoder ignore space"); |
34 | | // ignore whitespace |
35 | 1.24k | break; |
36 | | |
37 | 9 | case '>': |
38 | 9 | eod = true; |
39 | 9 | flush(); |
40 | 9 | break; |
41 | | |
42 | 3.99k | default: |
43 | 3.99k | if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F')) { |
44 | 3.95k | inbuf[pos++] = ch; |
45 | 3.95k | if (pos == 2) { |
46 | 1.96k | flush(); |
47 | 1.96k | } |
48 | 3.95k | } else { |
49 | 47 | char t[2]; |
50 | 47 | t[0] = ch; |
51 | 47 | t[1] = 0; |
52 | 47 | throw std::runtime_error("character out of range during base Hex decode: "s + t); |
53 | 47 | } |
54 | 3.95k | break; |
55 | 5.24k | } |
56 | 5.20k | if (eod) { |
57 | 9 | break; |
58 | 9 | } |
59 | 5.20k | } |
60 | 148 | } |
61 | | |
62 | | void |
63 | | Pl_ASCIIHexDecoder::flush() |
64 | 2.07k | { |
65 | 2.07k | if (pos == 0) { |
66 | 84 | QTC::TC("libtests", "Pl_ASCIIHexDecoder no-op flush"); |
67 | 84 | return; |
68 | 84 | } |
69 | 1.98k | int b[2]; |
70 | 5.96k | for (int i = 0; i < 2; ++i) { |
71 | 3.97k | if (inbuf[i] >= 'A') { |
72 | 3.67k | b[i] = inbuf[i] - 'A' + 10; |
73 | 3.67k | } else { |
74 | 304 | b[i] = inbuf[i] - '0'; |
75 | 304 | } |
76 | 3.97k | } |
77 | 1.98k | auto ch = static_cast<unsigned char>((b[0] << 4) + b[1]); |
78 | | |
79 | 1.98k | 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.98k | pos = 0; |
82 | 1.98k | inbuf[0] = '0'; |
83 | 1.98k | inbuf[1] = '0'; |
84 | 1.98k | inbuf[2] = '\0'; |
85 | | |
86 | 1.98k | next()->write(&ch, 1); |
87 | 1.98k | } |
88 | | |
89 | | void |
90 | | Pl_ASCIIHexDecoder::finish() |
91 | 101 | { |
92 | 101 | flush(); |
93 | 101 | next()->finish(); |
94 | 101 | } |