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