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