switch TransactionalBuffer from char to uint8_t + partial parser of tags and lengths v_0
authorFrantišek Kučera <franta-hg@frantovo.cz>
Sun, 20 Jun 2021 20:16:46 +0200
branchv_0
changeset 13 d5e2cb9e31f1
parent 12 243ef6c91dbb
child 14 02725d301010
switch TransactionalBuffer from char to uint8_t + partial parser of tags and lengths
src/XMLDocumentConstructor.h
src/lib/AbstractParser.cpp
src/lib/AbstractParser.h
src/lib/BasicASN1Reader.h
src/lib/TransactionalBuffer.h
--- 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();