Skip to content

Commit

Permalink
Adds VDF reader
Browse files Browse the repository at this point in the history
  • Loading branch information
JujuAdams committed Mar 25, 2023
1 parent 558e903 commit faaded4
Show file tree
Hide file tree
Showing 6 changed files with 322 additions and 1 deletion.
4 changes: 4 additions & 0 deletions objects/oTestVDF/Create_0.gml
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,8 @@ show_debug_message("------------------------------------------------------------
show_debug_message(SnapToVDF(struct, false, true));
show_debug_message("---------------------------------------------------------------------------------------");
show_debug_message(SnapToVDF(struct, true, true));
show_debug_message("---------------------------------------------------------------------------------------");
show_debug_message(SnapToJSON(SnapFromVDF("\"a\" { \"b\" \"c\" }"), true, true, true));
show_debug_message("---------------------------------------------------------------------------------------");
show_debug_message(SnapToJSON(SnapFromVDF(SnapToVDF(struct)), true, true, true));
show_debug_message("---------------------------------------------------------------------------------------");
279 changes: 279 additions & 0 deletions scripts/SnapBufferReadVDF/SnapBufferReadVDF.gml
Original file line number Diff line number Diff line change
@@ -0,0 +1,279 @@
/// @return Nested struct data that represents the contents of the VDF string
///
/// @param buffer Buffer to read data from
/// @param offset Offset in the buffer to read data from
///
/// @jujuadams 2023-03-25

function SnapBufferReadVDF(_buffer, _inOffset = undefined)
{
if (_inOffset != undefined)
{
var _oldOffset = buffer_tell(_buffer);
buffer_seek(_buffer, buffer_seek_start, _inOffset);
}

var _cacheBuffer = undefined;

var _readStart = undefined;
var _inString = false;
var _stringUsesCache = false;

var _inStructKey = true;
var _structKey = undefined;
var _inStructValue = false;

var _inComment = false;
var _inMultilineComment = false;
var _newComment = false;
var _newMultilineComment = false;

var _root = {};
var _stackTop = _root;
var _stack = [_stackTop];

var _bufferSize = buffer_get_size(_buffer);
while(buffer_tell(_buffer) < _bufferSize)
{
var _byte = buffer_read(_buffer, buffer_u8);
if (_byte == 0x00) break;

if (_inComment)
{
if ((_byte == ord("\n")) || (_byte == ord("\r")))
{
_inComment = false;
}
}
else if (_inMultilineComment)
{
if ((_byte == ord("*")) && (buffer_read(_buffer, buffer_u8) == ord("/")))
{
_inMultilineComment = false;
}
}
else if (_inString)
{
if (_byte == ord("\""))
{
if (_stringUsesCache)
{
_stringUsesCache = false;

var _size = buffer_tell(_buffer) - _readStart-1;
if (_size > 0)
{
buffer_copy(_buffer, _readStart, _size, _cacheBuffer, buffer_tell(_cacheBuffer));
buffer_seek(_cacheBuffer, buffer_seek_relative, _size);
}

buffer_write(_cacheBuffer, buffer_u8, 0x00);
buffer_seek(_cacheBuffer, buffer_seek_start, 0);
var _value = buffer_read(_cacheBuffer, buffer_string);
}
else
{
buffer_poke(_buffer, buffer_tell(_buffer)-1, buffer_u8, 0x00);
buffer_seek(_buffer, buffer_seek_start, _readStart);
var _value = buffer_read(_buffer, buffer_string);
}

//Reset string handling values
_inString = false;
_stringUsesCache = false;

if (_inStructKey)
{
_structKey = _value;

_inStructKey = false;
_inStructValue = true;
}
else if (_inStructValue)
{
_stackTop[$ _structKey] = _value;
_structKey = undefined;

_inStructKey = true;
_inStructValue = false;
}
}
else if (_byte == ord("\\"))
{
if (!_stringUsesCache)
{
_stringUsesCache = true;
if (_cacheBuffer == undefined)
{
_cacheBuffer = buffer_create(1024, buffer_grow, 1);
}
else
{
buffer_seek(_cacheBuffer, buffer_seek_start, 0);
}
}

var _size = buffer_tell(_buffer) - _readStart-1;
if (_size > 0)
{
buffer_copy(_buffer, _readStart, _size, _cacheBuffer, buffer_tell(_cacheBuffer));
buffer_seek(_cacheBuffer, buffer_seek_relative, _size);
}

var _next_byte = buffer_read(_buffer, buffer_u8);
switch(_next_byte)
{
case ord("n"): buffer_write(_cacheBuffer, buffer_u8, ord("\n")); break;
case ord("r"): buffer_write(_cacheBuffer, buffer_u8, ord("\r")); break;
case ord("t"): buffer_write(_cacheBuffer, buffer_u8, ord("\t")); break;

case ord("u"):
var _old_value = buffer_peek(_buffer, buffer_tell(_buffer)+4, buffer_u8);
buffer_poke(_buffer, buffer_tell(_buffer)+4, buffer_u8, 0x00);
var _hex = buffer_read(_buffer, buffer_string);
buffer_seek(_buffer, buffer_seek_relative, -1);
buffer_poke(_buffer, buffer_tell(_buffer), buffer_u8, _old_value);

var _value = int64(ptr(_hex));
if (_value <= 0x7F) //0xxxxxxx
{
buffer_write(_cacheBuffer, buffer_u8, _value);
}
else if (_value <= 0x07FF) //110xxxxx 10xxxxxx
{
buffer_write(_cacheBuffer, buffer_u8, 0xC0 | ((_value >> 6) & 0x1F));
buffer_write(_cacheBuffer, buffer_u8, 0x80 | ( _value & 0x3F));
}
else if (_value <= 0xFFFF) //1110xxxx 10xxxxxx 10xxxxxx
{
buffer_write(_cacheBuffer, buffer_u8, 0xC0 | ( _value & 0x0F));
buffer_write(_cacheBuffer, buffer_u8, 0x80 | ((_value >> 4) & 0x3F));
buffer_write(_cacheBuffer, buffer_u8, 0x80 | ((_value >> 10) & 0x3F));
}
else if (_value <= 0x10000) //11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
{
buffer_write(_cacheBuffer, buffer_u8, 0xC0 | ( _value & 0x07));
buffer_write(_cacheBuffer, buffer_u8, 0x80 | ((_value >> 3) & 0x3F));
buffer_write(_cacheBuffer, buffer_u8, 0x80 | ((_value >> 9) & 0x3F));
buffer_write(_cacheBuffer, buffer_u8, 0x80 | ((_value >> 15) & 0x3F));
}
break;

default:
if ((_next_byte & $E0) == $C0) //110xxxxx 10xxxxxx
{
buffer_copy(_buffer, buffer_tell(_buffer)+1, 1, _cacheBuffer, buffer_tell(_cacheBuffer));
buffer_seek(_buffer, buffer_seek_relative, 1);
buffer_seek(_cacheBuffer, buffer_seek_relative, 1);
}
else if ((_next_byte & $F0) == $E0) //1110xxxx 10xxxxxx 10xxxxxx
{
buffer_copy(_buffer, buffer_tell(_buffer)+1, 2, _cacheBuffer, buffer_tell(_cacheBuffer));
buffer_seek(_buffer, buffer_seek_relative, 2);
buffer_seek(_cacheBuffer, buffer_seek_relative, 2);
}
else if ((_next_byte & $F8) == $F0) //11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
{
buffer_copy(_buffer, buffer_tell(_buffer)+1, 3, _cacheBuffer, buffer_tell(_cacheBuffer));
buffer_seek(_buffer, buffer_seek_relative, 3);
buffer_seek(_cacheBuffer, buffer_seek_relative, 3);
}
else
{
buffer_write(_cacheBuffer, buffer_u8, _next_byte);
}
break;
}

_readStart = buffer_tell(_buffer);
}
}
else
{
//Searching for the start to a string or value
switch(_byte)
{
case ord("\""):
_readStart = buffer_tell(_buffer);
_inString = true;
break;

case ord("{"):
if (_inStructKey)
{
show_error("SNAP:\nCannot use a struct as a struct key\n ", true);
}
else
{
var _new_stack_top = {};

if (_inStructValue)
{
_stackTop[$ _structKey] = _new_stack_top;
}

array_push(_stack, _new_stack_top);
_stackTop = _new_stack_top;

_inStructKey = true;
_inStructValue = false;
}
break;

case ord("}"):
if (_inStructKey || _inStructValue)
{
array_pop(_stack);
_stackTop = (array_length(_stack) <= 0)? undefined : _stack[array_length(_stack)-1];

if (is_struct(_stackTop))
{
_inStructKey = true;
_inStructValue = false;
}
}
else
{
show_error("SNAP:\nFound unexpected }\n ", true);
}
break;

default:
if (_byte == ord("/"))
{
var _next_byte = buffer_peek(_buffer, buffer_tell(_buffer), buffer_u8);
if (_next_byte == ord("/"))
{
_inComment = true;
buffer_seek(_buffer, buffer_seek_relative, 1);
}
else if (_next_byte == ord("*"))
{
_inMultilineComment = true;
buffer_seek(_buffer, buffer_seek_relative, 1);
}
}
else if (_byte > 0x20)
{
show_error("SNAP:\nKeys and values must be strings\n ", true);
}
else if (_inStructValue && (_byte == ord("\n")) || (_byte == ord("\r")))
{
show_error("SNAP:\nWas expecting a value, found a newline instead\n ", true);
}
break;
}
}
}

if (_cacheBuffer != undefined) buffer_delete(_cacheBuffer);

if (array_length(_stack) > 1) show_error("SNAP:\nOne or more VDF objects not terminataed\n ", true);

if (_inOffset != undefined)
{
buffer_seek(_buffer, buffer_seek_start, _oldOffset);
}

return _root;
}
11 changes: 11 additions & 0 deletions scripts/SnapBufferReadVDF/SnapBufferReadVDF.yy
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"resourceType": "GMScript",
"resourceVersion": "1.0",
"name": "SnapBufferReadVDF",
"isDnD": false,
"isCompatibility": false,
"parent": {
"name": "VDF",
"path": "folders/SNAP/VDF.yy",
},
}
14 changes: 14 additions & 0 deletions scripts/SnapFromVDF/SnapFromVDF.gml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/// @return Nested struct data that represents the contents of the VDF string
///
/// @param string The VDF string to be decoded
///
/// @jujuadams 2023-03-25

function SnapFromVDF(_string)
{
var _buffer = buffer_create(string_byte_length(_string), buffer_fixed, 1);
buffer_write(_buffer, buffer_text, _string);
var _data = SnapBufferReadVDF(_buffer, 0);
buffer_delete(_buffer);
return _data;
}
11 changes: 11 additions & 0 deletions scripts/SnapFromVDF/SnapFromVDF.yy
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"resourceType": "GMScript",
"resourceVersion": "1.0",
"name": "SnapFromVDF",
"isDnD": false,
"isCompatibility": false,
"parent": {
"name": "VDF",
"path": "folders/SNAP/VDF.yy",
},
}
4 changes: 3 additions & 1 deletion snap.yyp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
{"id":{"name":"SnapDeepCopy","path":"scripts/SnapDeepCopy/SnapDeepCopy.yy",},"order":1,},
{"id":{"name":"SnapNumberToString","path":"scripts/SnapNumberToString/SnapNumberToString.yy",},"order":6,},
{"id":{"name":"SnapBufferWriteGrid","path":"scripts/SnapBufferWriteGrid/SnapBufferWriteGrid.yy",},"order":0,},
{"id":{"name":"SnapBufferReadVDF","path":"scripts/SnapBufferReadVDF/SnapBufferReadVDF.yy",},"order":3,},
{"id":{"name":"oTestCSV","path":"objects/oTestCSV/oTestCSV.yy",},"order":10,},
{"id":{"name":"SnapBufferReadNSV","path":"scripts/SnapBufferReadNSV/SnapBufferReadNSV.yy",},"order":3,},
{"id":{"name":"SnapFromQML","path":"scripts/SnapFromQML/SnapFromQML.yy",},"order":1,},
Expand All @@ -35,6 +36,7 @@
{"id":{"name":"SnapBufferWriteJSON","path":"scripts/SnapBufferWriteJSON/SnapBufferWriteJSON.yy",},"order":2,},
{"id":{"name":"SnapBufferWriteLooseJSON","path":"scripts/SnapBufferWriteLooseJSON/SnapBufferWriteLooseJSON.yy",},"order":2,},
{"id":{"name":"SnapStringFromFile","path":"scripts/SnapStringFromFile/SnapStringFromFile.yy",},"order":7,},
{"id":{"name":"SnapFromVDF","path":"scripts/SnapFromVDF/SnapFromVDF.yy",},"order":1,},
{"id":{"name":"oTestNSV","path":"objects/oTestNSV/oTestNSV.yy",},"order":11,},
{"id":{"name":"SnapBufferWriteXML","path":"scripts/SnapBufferWriteXML/SnapBufferWriteXML.yy",},"order":2,},
{"id":{"name":"oTestVDF","path":"objects/oTestVDF/oTestVDF.yy",},"order":20,},
Expand Down Expand Up @@ -67,7 +69,7 @@
{"id":{"name":"SnapBufferReadBOM","path":"scripts/SnapBufferReadBOM/SnapBufferReadBOM.yy",},"order":10,},
{"id":{"name":"SnapMD5","path":"scripts/SnapMD5/SnapMD5.yy",},"order":11,},
{"id":{"name":"ScratchBuffer","path":"scripts/ScratchBuffer/ScratchBuffer.yy",},"order":2,},
{"id":{"name":"SnapBufferWriteVDF","path":"scripts/SnapBufferWriteVDF/SnapBufferWriteVDF.yy",},"order":1,},
{"id":{"name":"SnapBufferWriteVDF","path":"scripts/SnapBufferWriteVDF/SnapBufferWriteVDF.yy",},"order":2,},
{"id":{"name":"SnapToXML","path":"scripts/SnapToXML/SnapToXML.yy",},"order":0,},
{"id":{"name":"SnapToVDF","path":"scripts/SnapToVDF/SnapToVDF.yy",},"order":0,},
{"id":{"name":"SnapBufferWriteYAML","path":"scripts/SnapBufferWriteYAML/SnapBufferWriteYAML.yy",},"order":2,},
Expand Down

0 comments on commit faaded4

Please sign in to comment.