Created
November 19, 2015 13:21
-
-
Save VictorKoenders/5f0cdd2c334bcbf56624 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"use strict"; | |
var zlib = require('zlib'), | |
fs = require('fs'); | |
var str = "H4sIAAAAAAAA/6Va7W6bQBB8FSu/IfJynDGK/CyRZaMEycWV7VStLN69PkhTm72PYfKnkQqT3Z25m9tbsj8uDsfd9rB43Vyb7tJe2ua8uV677Y9m83S+nLbt2/slv/04PGU/j+fb82O3uf7e5JL9uf1j+z5Lv2yn7+4+Tr+ave/XFsOryz7bt6dmN/y3RUJ85mNm5GOAfFY6nXJGOgKEKN2ba7LgGuF07d4s7yMUUISBJnuPq3BcdY8z6SyXKsn/RLu383P71m2noOcx1rONAHfv27bzwmWErx7hko678gIhdmpFDiR3rbSQNKdSKFIxBSuHMyTO+pUPkpmbkU37yCZEi3CJSiTPGEzjsCx1mgLxWWggtnWlZoFaehBoWaCJABOmVtyjVlC4gRiZv7Q9GmL1aSWgtebBYfFYAWn9SEJjsifjEXyS+pEwsjpShJjmidOhmM0kuTA9+5w1zxnxZLbpRv0ohiO1Yx2XtfjomRL2W3F9auFHJdqsXIrxhJfHEx4zbNEGY+DI5Rh4GerwUgYV8LVUWPONevWyhXalhkG7SxUpaJF+amFpKp6icacFag3b3Xq6gCd6em8Iq0SayaU/XlGE6G2HE5lowu1UUmj9KBSUo0oRuDxJ6aMEq20wL7YfZtththtmm2EGR/LiyiNkINlUZGKdG6kBKQGrAAXjUFyKikZuh8Ox5h+5nNDcYiR3DLlBST8g7Yd0u5i5RhpDd41Y+1Hg6VgyfZKrsfJbVyps7YuKNYX1dGHjvShfqwpq0aDeSoFprBYVHm5WflJT7UCQlyAw/2zOJtPfGQdmTY6BArPt1AKo4ulCDTNTrM4Zv3jXETUjg/VvKFOosDNaPAZXhXEJ13v8MAReZ4cbFzOAtGR9ZooD52UKx+4sfE5KwCLqpZpDAsZyQsE4FJcixwezdTw7Bx47EhwqOkjvw6NJYJ4yK0u8qyRg3J4hDTbm5xF/ddMaCXy0TrYEIkxvJ1aph30W1Dh0HiWBj7PY+TotE/nY+m/6YqJtSGxuE0QmT3VhGrWaBVYs0LJAwwJZclhuWGpYZmhiOBwJI7MkSSE1ICVnlxi7ptlNxO5a1ia8vtRn7e7Yub+Da7t949ZTyJVvIcZXikzb/ddDk/ny+Hpc+h/3/cupuXycusXrS9Pt/wLX3F77qicAAA=="; | |
var buffer = new Buffer(str, 'base64'); | |
function percentage(total, value){ | |
var percentage = (1 - (value / total)) * 100; | |
return Math.round(percentage * 100) / 100; | |
} | |
zlib.gunzip(buffer, function(error, data){ | |
fs.writeFile('output.lua', data); | |
console.log("gzip changed size from " + data.length + " to " + str.length + " (" + percentage(data.length, str.length) + "% compression)") | |
// Do the actual parsing | |
var table = new LuaParser(data).parse(); | |
fs.writeFile('output.json', JSON.stringify(table)); | |
}); | |
class LuaParser { | |
// Creates the LUA parser and sets initial variables | |
constructor(buffer){ | |
this._buffer = buffer; | |
this._index = 0; | |
} | |
// Parses the LUA object | |
parse(){ | |
// parses the stack and store the result | |
var result = this.parseStack(); | |
// Our first (and only) entry will be something like: | |
// {"do local _": {<actual blueprint>}} | |
// we'll just strip this because we can | |
return result[Object.keys(result)[0]]; | |
} | |
// Convert a stack to an object | |
// This can be one of the following options: | |
// ["name=", "\"straight-rail\""] | |
// This needs to be converted into: | |
// { name: "straight-rail" } | |
// ["[3]=", "\"chemical-plant\""] | |
// Here we simply convert it to: | |
// [3: "chemical-plant"] | |
// [<inner stack>, <inner stack>] | |
// we can just leave this as it is | |
convertStackToObject(stack){ | |
var result = {}; | |
// parse all keys, even index (0, 2, 4, etc) | |
for(var i = 0; i < stack.length - 1; i+=2){ | |
if(typeof(stack[i]) !== "string") { | |
// This entry is not a key! This means we're dealing with an array of objects | |
// This means we can just return the original stack, as this is already an array | |
return stack; | |
} | |
// parse the key and value | |
var key = stack[i].substring(0, stack[i].length - 1); | |
var value = this.parseValue(stack[i + 1]); | |
result[key] = value; | |
} | |
// Now we have an object of key-value pairs | |
// There is one exception; if all keys are | |
// [0], [1], etc | |
// This means we're actually dealing with a LUA array | |
// NOT an object | |
// so we check for this | |
if(Object.keys(result).length){ | |
var keys = Object.keys(result); | |
// Check if every key is [0], [1], etc | |
var resultIsArray = keys.every(key => /^\[\d+\]$/.test(key)); | |
if(resultIsArray){ | |
// Okay, so we just return all the values | |
// NOTE: we could possibly change the index here | |
// This might be desired to keep in the future | |
var resultArray = []; | |
for(var i = 0; i < keys.length; i++){ | |
resultArray[i] = result[keys[i]]; | |
} | |
result = resultArray; | |
} | |
} | |
return result; | |
} | |
// Parses the value of a key. This is one of the following: | |
// <object>: return the object, don't change it | |
// "someText": return the value as text between quotes | |
// "-15.3": return the float value of the string | |
// TODO: Are there other possibilities? | |
parseValue(value){ | |
if(typeof(value) !== "string") return value; | |
if(value[0] == '"' && value[value.length - 1] == '"'){ | |
return value.substring(1, value.length - 1); | |
} | |
return parseFloat(value); | |
} | |
// Parse a single stack | |
// A stack is one of the following formats: | |
// LUA: {key="value"} | |
// JSON: { "key": "value" } | |
// LUA: {key={{x=-1},{x=-2}}} | |
// JSON: { "key": [ { "x": -1 }, { "x": -2 } ] } | |
parseStack(){ | |
var index = 0; | |
var result = []; | |
while(this._index < this._buffer.length){ | |
var char = this.takeChar(); | |
if(char == '}'){ | |
break; | |
} | |
if(char == '{'){ | |
result.push(this.parseStack()); | |
index++; | |
if(this.peekChar() == ','){ | |
this.takeChar(); | |
} | |
} else if(char == ','){ | |
index++; | |
} else { | |
result[index] = (result[index] || '') + char; | |
if(char == '='){ | |
index++; | |
} | |
} | |
} | |
return this.convertStackToObject(result); | |
} | |
// Return the next character, but leaves the character intact | |
peekChar(){ | |
return String.fromCharCode(this._buffer[this._index]); | |
} | |
// Returns the next character. After this call, the internal | |
// pointer will point to the character after this one | |
takeChar(){ | |
return String.fromCharCode(this._buffer[this._index++]); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment