switch TransactionalBuffer from char to uint8_t + partial parser of tags and lengths
--- a/src/XMLDocumentConstructor.h Sun Jun 20 10:23:50 2021 +0200
+++ b/src/XMLDocumentConstructor.h Sun Jun 20 20:16:46 2021 +0200
@@ -17,6 +17,7 @@
#pragma once
#include <memory>
+#include <stdexcept>
#include <libxml++-2.6/libxml++/libxml++.h>
@@ -53,7 +54,7 @@
try {
// TODO: buffering? (reader itself also buffers)
- for (char ch = input->get(); input->good(); ch = input->get()) reader.write(&ch, 1);
+ for (uint8_t b = input->get(); input->good(); b = input->get()) reader.write(&b, 1);
} catch (const relpipe::in::asn1::lib::TransactionalBuffer::WriteBufferOverflowException& e) {
// TODO: avoid leaky abstraction and use different exception
throw relpipe::writer::RelpipeWriterException(L"Transactional buffer for ASN.1 input is too small");
--- a/src/lib/AbstractParser.cpp Sun Jun 20 10:23:50 2021 +0200
+++ b/src/lib/AbstractParser.cpp Sun Jun 20 20:16:46 2021 +0200
@@ -45,7 +45,7 @@
delete implementation;
}
-void AbstractParser::write(const char* buffer, const size_t length) {
+void AbstractParser::write(const uint8_t* buffer, const size_t length) {
try {
// TODO: do not write to the buffer, just append in read()/peek() and write just the part that was not read during this cycle
implementation->buffer.write(buffer, length);
@@ -74,11 +74,11 @@
implementation->buffer.commitRead();
}
-void AbstractParser::read(char* buffer, const size_t length) {
+void AbstractParser::read(uint8_t* buffer, const size_t length) {
implementation->buffer.read(buffer, length);
}
-void AbstractParser::peek(char* buffer, const size_t length) {
+void AbstractParser::peek(uint8_t* buffer, const size_t length) {
implementation->buffer.read(buffer, length);
}
--- a/src/lib/AbstractParser.h Sun Jun 20 10:23:50 2021 +0200
+++ b/src/lib/AbstractParser.h Sun Jun 20 20:16:46 2021 +0200
@@ -17,6 +17,7 @@
#pragma once
#include <cstring>
+#include <cstdint>
namespace relpipe {
namespace in {
@@ -51,7 +52,7 @@
* @param buffer readable memory
* @param length size of the buffer
*/
- void write(const char* buffer, const size_t length);
+ void write(const uint8_t* buffer, const size_t length);
/**
* Finalize the parsing process.
@@ -94,7 +95,7 @@
* @param buffer writable memory
* @param length size of the buffer
*/
- void read(char* buffer, const size_t length);
+ void read(uint8_t* buffer, const size_t length);
/**
* Like read(), but does not update the marks (buffer positions), so it can be called again and again with same result.
@@ -102,7 +103,7 @@
* @param buffer writable memory
* @param length size of the buffer
*/
- void peek(char* buffer, const size_t length);
+ void peek(uint8_t* buffer, const size_t length);
/**
* Reads input from buffers using read(), parses data and usually emits the result (e.g. to a handler/listener).
--- a/src/lib/BasicASN1Reader.h Sun Jun 20 10:23:50 2021 +0200
+++ b/src/lib/BasicASN1Reader.h Sun Jun 20 20:16:46 2021 +0200
@@ -33,19 +33,65 @@
class BasicASN1Reader : public ASN1Reader {
private:
- enum class State {
- A,
- B,
- C
+ bool started = false;
+
+ enum class TagClass : uint8_t {
+ Universal = 0,
+ Application = 1,
+ ContextSpecific = 2,
+ Private = 3
+ };
+
+ enum class PC : uint8_t {
+ Primitive = 0,
+ Constructed = 1
+ };
+
+ class Header {
+ public:
+ TagClass tagClass;
+ PC pc;
+ uint64_t tag;
+ bool definiteLength;
+ size_t length;
};
- State state = State::A;
+ Header readHeader() {
+ Header h;
+
+ memset(&h, 0, sizeof (h)); // TODO: remove, not needed
+
+ uint8_t tagByte;
+ read(&tagByte, 1);
+
+ h.tagClass = (TagClass) (tagByte >> 6);
+ h.pc = (PC) ((tagByte >> 5) & 1);
+ h.tag = tagByte & (0xFF >> 3);
+ if (h.tag > 30) throw relpipe::writer::RelpipeWriterException(L"not yet implemented, ASN.1 tag > 30"); // FIXME: higher tag values → read more bytes
+
+ uint8_t lengthByte;
+ read(&lengthByte, 1);
- bool started = false;
+ std::wcerr << L"lengthByte = " << lengthByte << std::endl;
+
+ if (lengthByte >> 7 == 0) {
+ h.definiteLength = true;
+ h.length = lengthByte;
+ } else if (lengthByte == 0b10000000) {
+ h.definiteLength = false;
+ h.length = 0;
+ } else if (lengthByte == 0xFF) {
+ throw relpipe::writer::RelpipeWriterException(L"ASN.1 lengthByte == 0xFF (reserved value)"); // TODO: better exception
+ } else {
+ // FIXME: longer values
+ throw relpipe::writer::RelpipeWriterException(L"not yet implemented, ASN.1 lengthBytes: longer value"); // TODO: better exception
+ }
+
+ return h;
+ }
void readNext() {
- std::array<char, 2> typeAndLength;
- read(typeAndLength.data(), typeAndLength.size());
+ Header typeHeader = readHeader();
commit();
if (!started) {
@@ -56,18 +102,20 @@
handlers.writeCollectionStart(ASN1ContentHandler::CollectionType::Sequence);
handlers.writeNull();
handlers.writeBoolean(true);
- handlers.writeInteger(typeAndLength[0]);
- handlers.writeInteger(typeAndLength[1]);
+
+ handlers.writeString(ASN1ContentHandler::StringType::UTF8String, "tagClass:");
+ handlers.writeInteger((int64_t) typeHeader.tagClass);
+ handlers.writeString(ASN1ContentHandler::StringType::UTF8String, "pc:");
+ handlers.writeInteger((int64_t) typeHeader.pc);
+ handlers.writeString(ASN1ContentHandler::StringType::UTF8String, "tag:");
+ handlers.writeInteger((int64_t) typeHeader.tag);
+ handlers.writeString(ASN1ContentHandler::StringType::UTF8String, "definiteLength:");
+ handlers.writeBoolean(typeHeader.definiteLength);
+ handlers.writeString(ASN1ContentHandler::StringType::UTF8String, "length:");
+ handlers.writeInteger((int64_t) typeHeader.length);
+
handlers.writeString(ASN1ContentHandler::StringType::UTF8String, "relational pipes");
handlers.writeCollectionEnd();
-
- if (state == State::A) {
-
- } else if (state == State::B) {
-
- } else if (state == State::C) {
-
- }
}
protected:
--- a/src/lib/TransactionalBuffer.h Sun Jun 20 10:23:50 2021 +0200
+++ b/src/lib/TransactionalBuffer.h Sun Jun 20 20:16:46 2021 +0200
@@ -29,7 +29,7 @@
class TransactionalBuffer {
private:
- char* buffer;
+ uint8_t* buffer;
size_t bufferSize;
bool hasData = false;
size_t writePosition = 0;
@@ -53,7 +53,7 @@
public:
- /**
+ /**
* Is thrown from read() and peak() methods if there are not enough data.
* Interrupts current update() cycle and causes rollback.
*/
@@ -70,14 +70,14 @@
TransactionalBuffer(size_t initialSize = 4096) : bufferSize(initialSize) {
// TODO: initial size + resize + hard upper limit
- buffer = (char*) malloc(bufferSize);
+ buffer = (uint8_t*) malloc(bufferSize);
}
virtual ~TransactionalBuffer() {
free(buffer);
}
- void write(const char* inputBuffer, const size_t length) {
+ void write(const uint8_t* inputBuffer, const size_t length) {
if (length == 0) return;
if (length > availableForWriting()) throw WriteBufferOverflowException(); // TODO: optional resize
@@ -93,7 +93,7 @@
writePosition = (writePosition + length) % bufferSize;
}
- void read(char* outputBuffer, const size_t length) {
+ void read(uint8_t* outputBuffer, const size_t length) {
if (length == 0) return;
peek(outputBuffer, length);
@@ -101,7 +101,7 @@
hasData = readPosition != writePosition;
}
- void peek(char* outputBuffer, const size_t length) {
+ void peek(uint8_t* outputBuffer, const size_t length) {
if (length == 0) return;
if (length > availableForReading()) throw ReadBufferUnderflowException();