diff options
Diffstat (limited to 'libqpdf/Pl_ASCIIHexDecoder.cc')
-rw-r--r-- | libqpdf/Pl_ASCIIHexDecoder.cc | 109 |
1 files changed, 109 insertions, 0 deletions
diff --git a/libqpdf/Pl_ASCIIHexDecoder.cc b/libqpdf/Pl_ASCIIHexDecoder.cc new file mode 100644 index 0000000..ca153e8 --- /dev/null +++ b/libqpdf/Pl_ASCIIHexDecoder.cc @@ -0,0 +1,109 @@ +#include <qpdf/Pl_ASCIIHexDecoder.hh> +#include <qpdf/QTC.hh> +#include <stdexcept> +#include <string.h> +#include <ctype.h> + +Pl_ASCIIHexDecoder::Pl_ASCIIHexDecoder(char const* identifier, Pipeline* next) : + Pipeline(identifier, next), + pos(0), + eod(false) +{ + strcpy(this->inbuf, "00"); +} + +Pl_ASCIIHexDecoder::~Pl_ASCIIHexDecoder() +{ +} + +void +Pl_ASCIIHexDecoder::write(unsigned char* buf, size_t len) +{ + if (this->eod) + { + return; + } + for (size_t i = 0; i < len; ++i) + { + char ch = toupper(buf[i]); + switch (ch) + { + case ' ': + case '\f': + case '\v': + case '\t': + case '\r': + case '\n': + QTC::TC("libtests", "Pl_ASCIIHexDecoder ignore space"); + // ignore whitespace + break; + + case '>': + this->eod = true; + flush(); + break; + + default: + if (((ch >= '0') && (ch <= '9')) || + ((ch >= 'A') && (ch <= 'F'))) + { + this->inbuf[this->pos++] = ch; + if (this->pos == 2) + { + flush(); + } + } + else + { + char t[2]; + t[0] = ch; + t[1] = 0; + throw std::runtime_error( + std::string("character out of range" + " during base Hex decode: ") + t); + } + break; + } + if (this->eod) + { + break; + } + } +} + +void +Pl_ASCIIHexDecoder::flush() +{ + if (this->pos == 0) + { + QTC::TC("libtests", "Pl_ASCIIHexDecoder no-op flush"); + return; + } + int b[2]; + for (int i = 0; i < 2; ++i) + { + if (this->inbuf[i] >= 'A') + { + b[i] = this->inbuf[i] - 'A' + 10; + } + else + { + b[i] = this->inbuf[i] - '0'; + } + } + unsigned char ch = (unsigned char)((b[0] << 4) + b[1]); + + QTC::TC("libtests", "Pl_ASCIIHexDecoder partial flush", + (this->pos == 2) ? 0 : 1); + getNext()->write(&ch, 1); + + this->pos = 0; + strcpy(this->inbuf, "00"); +} + +void +Pl_ASCIIHexDecoder::finish() +{ + flush(); + getNext()->finish(); +} |