/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 | 711 | Pipeline(identifier, next) |
11 | 711 | { |
12 | 711 | if (!next) { |
13 | 0 | throw std::logic_error("Attempt to create Pl_ASCIIHexDecoder with nullptr as next"); |
14 | 0 | } |
15 | 711 | } |
16 | | |
17 | | void |
18 | | Pl_ASCIIHexDecoder::write(unsigned char const* buf, size_t len) |
19 | 593 | { |
20 | 593 | if (eod) { |
21 | 215 | return; |
22 | 215 | } |
23 | 8.38k | for (size_t i = 0; i < len; ++i) { |
24 | 8.24k | char ch = static_cast<char>(toupper(buf[i])); |
25 | 8.24k | switch (ch) { |
26 | 266 | case ' ': |
27 | 495 | case '\f': |
28 | 715 | case '\v': |
29 | 1.05k | case '\t': |
30 | 1.29k | case '\r': |
31 | 1.73k | case '\n': |
32 | 1.73k | QTC::TC("libtests", "Pl_ASCIIHexDecoder ignore space"); |
33 | | // ignore whitespace |
34 | 1.73k | break; |
35 | | |
36 | 44 | case '>': |
37 | 44 | eod = true; |
38 | 44 | flush(); |
39 | 44 | break; |
40 | | |
41 | 6.47k | default: |
42 | 6.47k | if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F')) { |
43 | 6.29k | inbuf[pos++] = ch; |
44 | 6.29k | if (pos == 2) { |
45 | 3.07k | flush(); |
46 | 3.07k | } |
47 | 6.29k | } else { |
48 | 181 | char t[2]; |
49 | 181 | t[0] = ch; |
50 | 181 | t[1] = 0; |
51 | 181 | throw std::runtime_error("character out of range during base Hex decode: "s + t); |
52 | 181 | } |
53 | 6.29k | break; |
54 | 8.24k | } |
55 | 8.05k | if (eod) { |
56 | 43 | break; |
57 | 43 | } |
58 | 8.05k | } |
59 | 378 | } |
60 | | |
61 | | void |
62 | | Pl_ASCIIHexDecoder::flush() |
63 | 3.49k | { |
64 | 3.49k | if (pos == 0) { |
65 | 299 | QTC::TC("libtests", "Pl_ASCIIHexDecoder no-op flush"); |
66 | 299 | return; |
67 | 299 | } |
68 | 3.19k | int b[2]; |
69 | 9.59k | for (int i = 0; i < 2; ++i) { |
70 | 6.39k | if (inbuf[i] >= 'A') { |
71 | 1.00k | b[i] = inbuf[i] - 'A' + 10; |
72 | 5.39k | } else { |
73 | 5.39k | b[i] = inbuf[i] - '0'; |
74 | 5.39k | } |
75 | 6.39k | } |
76 | 3.19k | auto ch = static_cast<unsigned char>((b[0] << 4) + b[1]); |
77 | | |
78 | 3.19k | QTC::TC("libtests", "Pl_ASCIIHexDecoder partial flush", (pos == 2) ? 0 : 1); |
79 | | // Reset before calling getNext()->write in case that throws an exception. |
80 | 3.19k | pos = 0; |
81 | 3.19k | inbuf[0] = '0'; |
82 | 3.19k | inbuf[1] = '0'; |
83 | 3.19k | inbuf[2] = '\0'; |
84 | | |
85 | 3.19k | next()->write(&ch, 1); |
86 | 3.19k | } |
87 | | |
88 | | void |
89 | | Pl_ASCIIHexDecoder::finish() |
90 | 379 | { |
91 | 379 | flush(); |
92 | 379 | next()->finish(); |
93 | 379 | } |