somehow parse nested SEQUENCEs and SETs + support definite long form of lengths (multiple length octets) v_0
authorFrantišek Kučera <franta-hg@frantovo.cz>
Sun, 20 Jun 2021 21:06:02 +0200
branchv_0
changeset 14 02725d301010
parent 13 d5e2cb9e31f1
child 15 95ca127ba816
somehow parse nested SEQUENCEs and SETs + support definite long form of lengths (multiple length octets)
src/lib/ASN1ContentHandler.h
src/lib/AbstractParser.cpp
src/lib/AbstractParser.h
src/lib/BasicASN1Reader.h
src/lib/TransactionalBuffer.h
--- a/src/lib/ASN1ContentHandler.h	Sun Jun 20 20:16:46 2021 +0200
+++ b/src/lib/ASN1ContentHandler.h	Sun Jun 20 21:06:02 2021 +0200
@@ -27,12 +27,12 @@
 class ASN1ContentHandler {
 public:
 
-	enum class CollectionType {
-		Sequence,
-		Set
+	enum class CollectionType : uint64_t {
+		Sequence = 16,
+		Set = 17
 	};
 
-	enum class StringType {
+	enum class StringType : uint64_t {
 		OctetString,
 		UTF8String,
 		NumericString,
--- a/src/lib/AbstractParser.cpp	Sun Jun 20 20:16:46 2021 +0200
+++ b/src/lib/AbstractParser.cpp	Sun Jun 20 21:06:02 2021 +0200
@@ -82,6 +82,10 @@
 	implementation->buffer.read(buffer, length);
 }
 
+size_t AbstractParser::getBytesRead() {
+	return implementation->buffer.getBytesRead();
+}
+
 }
 }
 }
--- a/src/lib/AbstractParser.h	Sun Jun 20 20:16:46 2021 +0200
+++ b/src/lib/AbstractParser.h	Sun Jun 20 21:06:02 2021 +0200
@@ -106,6 +106,11 @@
 	void peek(uint8_t* buffer, const size_t length);
 
 	/**
+	 * @return total number of bytes that were successfully read
+	 */
+	size_t getBytesRead();
+
+	/**
 	 * Reads input from buffers using read(), parses data and usually emits the result (e.g. to a handler/listener).
 	 * Is specific for particular format/parser.
 	 * 
--- a/src/lib/BasicASN1Reader.h	Sun Jun 20 20:16:46 2021 +0200
+++ b/src/lib/BasicASN1Reader.h	Sun Jun 20 21:06:02 2021 +0200
@@ -19,6 +19,7 @@
 #include <memory>
 #include <vector>
 #include <array>
+#include <sstream>
 
 #include "ASN1Reader.h"
 
@@ -56,6 +57,25 @@
 		size_t length;
 	};
 
+	class LevelMetadata {
+	public:
+		bool definiteLength;
+		size_t length;
+		size_t start;
+	};
+
+	std::vector<LevelMetadata> level;
+
+	void checkRemainingItems() {
+		if (level.size()) {
+			LevelMetadata& l = level.back();
+			if (l.definiteLength && l.length == getBytesRead() - l.start) {
+				level.pop_back();
+				handlers.writeCollectionEnd();
+			}
+		}
+	}
+
 	Header readHeader() {
 		Header h;
 
@@ -72,33 +92,76 @@
 		uint8_t lengthByte;
 		read(&lengthByte, 1);
 
-		std::wcerr << L"lengthByte = " << lengthByte << std::endl;
-
 		if (lengthByte >> 7 == 0) {
+			// definite short
 			h.definiteLength = true;
 			h.length = lengthByte;
 		} else if (lengthByte == 0b10000000) {
+			// indefinite
 			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
+			// definite long
+			h.definiteLength = true;
+			h.length = 0;
+			std::vector<uint8_t> lengthBytes(lengthByte & 0b01111111, 0);
+			read(lengthBytes.data(), lengthBytes.size());
+			for (uint8_t l : lengthBytes) h.length = (h.length << 8) + l;
 		}
-		
+
 		return h;
 	}
 
 	void readNext() {
+		checkRemainingItems();
 		Header typeHeader = readHeader();
-		commit();
+		// commit(); // TODO: commit here and recover later instead of rollback?
 
 		if (!started) {
 			handlers.writeStreamStart();
 			started = true;
 		}
+		
+		// TODO: check tagClass and pc
 
+		// TODO: constants, more types
+		if (typeHeader.tag == 0) handlers.writeCollectionEnd();
+		else if (typeHeader.tag == 16) {
+			level.push_back({typeHeader.definiteLength, typeHeader.length, getBytesRead()}); // TODO: transaction
+			handlers.writeCollectionStart(ASN1ContentHandler::CollectionType::Sequence);
+		} else if (typeHeader.tag == 17) {
+			level.push_back({typeHeader.definiteLength, typeHeader.length, getBytesRead()}); // TODO: transaction
+			handlers.writeCollectionStart(ASN1ContentHandler::CollectionType::Set);
+		} else if (typeHeader.tag == 5 && typeHeader.length == 0) {
+			handlers.writeNull();
+		} else if (typeHeader.tag == 1) {
+			bool value;
+			read((uint8_t*) & value, 1);
+			handlers.writeBoolean(value);
+		} else {
+			// TODO: do not skip, parse
+			std::vector<uint8_t> temp(typeHeader.length, 0);
+			read(temp.data(), typeHeader.length);
+			// TODO: recover transaction?
+
+			std::stringstream description;
+			description << "value:"
+					<< " tag = " << typeHeader.tag
+					<< " tagClass = " << (int) typeHeader.tagClass
+					<< " pc = " << (int) typeHeader.pc
+					<< " length = " << typeHeader.length
+					<< " definite = " << (typeHeader.definiteLength ? "true" : "false");
+
+			handlers.writeString(ASN1ContentHandler::StringType::UTF8String, description.str());
+		}
+
+		commit();
+
+
+		// TODO: remove debug/demo output:
+		return;
 		handlers.writeCollectionStart(ASN1ContentHandler::CollectionType::Sequence);
 		handlers.writeNull();
 		handlers.writeBoolean(true);
@@ -127,7 +190,8 @@
 public:
 
 	void close() override {
-		if (started) handlers.writeStreamEnd();
+		// TODO: check the bytes remaining in the buffer
+		//if (started) handlers.writeStreamEnd();
 	}
 
 };
--- a/src/lib/TransactionalBuffer.h	Sun Jun 20 20:16:46 2021 +0200
+++ b/src/lib/TransactionalBuffer.h	Sun Jun 20 21:06:02 2021 +0200
@@ -37,6 +37,9 @@
 	size_t readPosition = 0;
 	size_t readPositionCommited = 0;
 
+	size_t bytesRead = 0;
+	size_t bytesReadCommited = 0;
+
 	size_t availableForReading() {
 		if (readPosition < writePosition) return writePosition - readPosition;
 		else if (readPosition > writePosition) return bufferSize - readPosition + writePosition;
@@ -99,6 +102,7 @@
 		peek(outputBuffer, length);
 		readPosition = (readPosition + length) % bufferSize;
 		hasData = readPosition != writePosition;
+		bytesRead += length;
 	}
 
 	void peek(uint8_t* outputBuffer, const size_t length) {
@@ -114,11 +118,18 @@
 
 	void commitRead() {
 		readPositionCommited = readPosition;
+		bytesReadCommited = bytesRead;
 	}
 
 	void rollbackRead() {
 		readPosition = readPositionCommited;
+		bytesRead = bytesReadCommited;
 	}
+
+	size_t getBytesRead() {
+		return bytesRead;
+	}
+
 };