/src/qpdf/libqpdf/Pl_ASCIIHexDecoder.cc
Line | Count | Source (jump to first uncovered line) |
1 | | #include <qpdf/Pl_ASCIIHexDecoder.hh> |
2 | | |
3 | | #include <qpdf/QTC.hh> |
4 | | #include <cctype> |
5 | | #include <stdexcept> |
6 | | |
7 | | Pl_ASCIIHexDecoder::Pl_ASCIIHexDecoder(char const* identifier, Pipeline* next) : |
8 | | Pipeline(identifier, next), |
9 | | pos(0), |
10 | | eod(false) |
11 | 135 | { |
12 | 135 | this->inbuf[0] = '0'; |
13 | 135 | this->inbuf[1] = '0'; |
14 | 135 | this->inbuf[2] = '\0'; |
15 | 135 | } |
16 | | |
17 | | void |
18 | | Pl_ASCIIHexDecoder::write(unsigned char const* buf, size_t len) |
19 | 135 | { |
20 | 135 | if (this->eod) { |
21 | 0 | return; |
22 | 0 | } |
23 | 3.56k | for (size_t i = 0; i < len; ++i) { |
24 | 3.46k | char ch = static_cast<char>(toupper(buf[i])); |
25 | 3.46k | switch (ch) { |
26 | 226 | case ' ': |
27 | 420 | case '\f': |
28 | 614 | case '\v': |
29 | 890 | case '\t': |
30 | 1.08k | case '\r': |
31 | 1.30k | case '\n': |
32 | 1.30k | QTC::TC("libtests", "Pl_ASCIIHexDecoder ignore space"); |
33 | | // ignore whitespace |
34 | 1.30k | break; |
35 | | |
36 | 9 | case '>': |
37 | 9 | this->eod = true; |
38 | 9 | flush(); |
39 | 9 | break; |
40 | | |
41 | 2.16k | default: |
42 | 2.16k | if (((ch >= '0') && (ch <= '9')) || ((ch >= 'A') && (ch <= 'F'))) { |
43 | 2.12k | this->inbuf[this->pos++] = ch; |
44 | 2.12k | if (this->pos == 2) { |
45 | 1.04k | flush(); |
46 | 1.04k | } |
47 | 2.12k | } else { |
48 | 34 | char t[2]; |
49 | 34 | t[0] = ch; |
50 | 34 | t[1] = 0; |
51 | 34 | throw std::runtime_error( |
52 | 34 | std::string("character out of range" |
53 | 34 | " during base Hex decode: ") + |
54 | 34 | t); |
55 | 34 | } |
56 | 2.12k | break; |
57 | 3.46k | } |
58 | 3.43k | if (this->eod) { |
59 | 9 | break; |
60 | 9 | } |
61 | 3.43k | } |
62 | 135 | } |
63 | | |
64 | | void |
65 | | Pl_ASCIIHexDecoder::flush() |
66 | 1.15k | { |
67 | 1.15k | if (this->pos == 0) { |
68 | 82 | QTC::TC("libtests", "Pl_ASCIIHexDecoder no-op flush"); |
69 | 82 | return; |
70 | 82 | } |
71 | 1.07k | int b[2]; |
72 | 3.22k | for (int i = 0; i < 2; ++i) { |
73 | 2.15k | if (this->inbuf[i] >= 'A') { |
74 | 1.17k | b[i] = this->inbuf[i] - 'A' + 10; |
75 | 1.17k | } else { |
76 | 973 | b[i] = this->inbuf[i] - '0'; |
77 | 973 | } |
78 | 2.15k | } |
79 | 1.07k | auto ch = static_cast<unsigned char>((b[0] << 4) + b[1]); |
80 | | |
81 | 1.07k | QTC::TC("libtests", "Pl_ASCIIHexDecoder partial flush", (this->pos == 2) ? 0 : 1); |
82 | | // Reset before calling getNext()->write in case that throws an exception. |
83 | 1.07k | this->pos = 0; |
84 | 1.07k | this->inbuf[0] = '0'; |
85 | 1.07k | this->inbuf[1] = '0'; |
86 | 1.07k | this->inbuf[2] = '\0'; |
87 | | |
88 | 1.07k | getNext()->write(&ch, 1); |
89 | 1.07k | } |
90 | | |
91 | | void |
92 | | Pl_ASCIIHexDecoder::finish() |
93 | 101 | { |
94 | 101 | flush(); |
95 | 101 | getNext()->finish(); |
96 | 101 | } |