//Read a structure private static void ReadValueStruct(char c, Parser parser) { //Ignore whitespace if (char.IsWhiteSpace(c)) { return; } //Catch comments if (c == '/') { parser.StateStack.Push(State.COMMENT); parser.CurrentString.Clear(); parser.CurrentString.Append(c); return; } //Check for the end of the structure if (c == '}') { KVObject value = parser.ObjStack.Pop(); parser.ObjStack.Peek().AddProperty(value.Key, new KVValue(KVType.OBJECT, value)); parser.StateStack.Pop(); return; } //Start looking for the next property name parser.StateStack.Push(State.PROP_NAME); parser.CurrentString.Clear(); parser.CurrentString.Append(c); }
public KV3File( KVObject root, string encoding = "text:version{e21c7f3c-8a33-41c5-9977-a76d3a32aa0d}", string format = "generic:version{7412167c-06e9-4698-aff2-e63eb59037e7}") { Root = root; Encoding = encoding; Format = format; }
public Parser() { //Initialise datastructures ObjStack = new Stack<KVObject>(); StateStack = new Stack<State>(); StateStack.Push(State.HEADER); Root = new KVObject("root"); ObjStack.Push(Root); PreviousChar = '\0'; CharBuffer = new Queue<char>(); CurrentString = new StringBuilder(); }
public Parser() { //Initialise datastructures ObjStack = new Stack <KVObject>(); StateStack = new Stack <State>(); StateStack.Push(State.HEADER); Root = new KVObject("root"); ObjStack.Push(Root); PreviousChar = '\0'; CharBuffer = new Queue <char>(); CurrentString = new StringBuilder(); }
//Seeking value state private static void SeekValue(char c, Parser parser) { //Ignore whitespace if (char.IsWhiteSpace(c) || c == '=') { return; } //Check struct opening if (c == '{') { parser.StateStack.Pop(); parser.StateStack.Push(State.VALUE_STRUCT); parser.ObjStack.Push(new KVObject(parser.CurrentString.ToString())); } //Check for array opening else if (c == '[') { parser.StateStack.Pop(); parser.StateStack.Push(State.VALUE_ARRAY); parser.StateStack.Push(State.SEEK_VALUE); parser.ObjStack.Push(new KVObject(parser.CurrentString.ToString(), true)); } //Check for array closing else if (c == ']') { parser.StateStack.Pop(); parser.StateStack.Pop(); KVObject value = parser.ObjStack.Pop(); parser.ObjStack.Peek().AddProperty(value.Key, new KVValue(KVType.ARRAY, value)); } //String opening else if (c == '"') { //Check if a multistring or single string was found string next = PeekString(parser, 4); if (next.Contains("\"\"\n") || next == "\"\"\r\n") { //Skip the next two "'s SkipChars(parser, 2); parser.StateStack.Pop(); parser.StateStack.Push(State.VALUE_STRING_MULTI); parser.CurrentString.Clear(); } else { parser.StateStack.Pop(); parser.StateStack.Push(State.VALUE_STRING); parser.CurrentString.Clear(); } } //Boolean false else if (ReadAheadMatches(parser, c, "false")) { parser.StateStack.Pop(); //Can directly be added parser.ObjStack.Peek().AddProperty(parser.CurrentName, new KVValue(KVType.BOOLEAN, false)); //Skip next characters SkipChars(parser, "false".Length - 1); } //Boolean true else if (ReadAheadMatches(parser, c, "true")) { parser.StateStack.Pop(); //Can directly be added parser.ObjStack.Peek().AddProperty(parser.CurrentName, new KVValue(KVType.BOOLEAN, true)); //Skip next characters SkipChars(parser, "true".Length - 1); } //Null else if (ReadAheadMatches(parser, c, "null")) { parser.StateStack.Pop(); //Can directly be added parser.ObjStack.Peek().AddProperty(parser.CurrentName, new KVValue(KVType.NULL, null)); //Skip next characters SkipChars(parser, "null".Length - 1); } // Number else if (char.IsDigit(c)) { parser.StateStack.Pop(); parser.StateStack.Push(State.VALUE_NUMBER); parser.CurrentString.Clear(); parser.CurrentString.Append(c); } //Flagged resource else { parser.StateStack.Pop(); parser.StateStack.Push(State.VALUE_FLAGGED); parser.CurrentString.Clear(); parser.CurrentString.Append(c); } }
public override void Read(BinaryReader reader, Resource resource) { reader.BaseStream.Position = Offset; var outStream = new MemoryStream(); BinaryWriter outWrite = new BinaryWriter(outStream); BinaryReader outRead = new BinaryReader(outStream); // Why why why why why why why var sig = reader.ReadBytes(4); if (Encoding.ASCII.GetString(sig) != Encoding.ASCII.GetString(SIG)) { throw new InvalidDataException("Invalid KV Signature"); } // outWrite.Write(sig); var encoding = reader.ReadBytes(16); if (Encoding.ASCII.GetString(encoding) != Encoding.ASCII.GetString(ENCODING)) { throw new InvalidDataException("Unrecognized KV3 Encoding"); } // outWrite.Write(encoding); var format = reader.ReadBytes(16); if (Encoding.ASCII.GetString(format) != Encoding.ASCII.GetString(FORMAT)) { throw new InvalidDataException("Unrecognised KV3 Format"); } // outWrite.Write(format); // Ok we are 100% sure its now KV, good // It is flags, right? var flags = reader.ReadUInt32(); // TODO: Figure out what this is // outWrite.Write(flags); if ((flags & 0x80000000) > 0) { outWrite.Write(reader.ReadBytes((int)(reader.BaseStream.Length - reader.BaseStream.Position))); } else { while (reader.BaseStream.Position != reader.BaseStream.Length) { try { var blockMask = reader.ReadUInt16(); for (int i = 0; i < 16; i++) { // is the ith bit 1 if ((blockMask & (1 << i)) > 0) { var offsetSize = reader.ReadUInt16(); var offset = ((offsetSize & 0xFFF0) >> 4) + 1; var size = (offsetSize & 0x000F) + 3; var lookupSize = (offset < size) ? offset : size; // If the offset is larger or equal to the size, use the size instead. // Kill me now var p = outRead.BaseStream.Position; outRead.BaseStream.Position = p - offset; var data = outRead.ReadBytes(lookupSize); outWrite.BaseStream.Position = p; while (size > 0) { outWrite.Write(data, 0, (lookupSize < size) ? lookupSize : size); size -= lookupSize; } } else { var data = reader.ReadByte(); outWrite.Write(data); } } } catch (EndOfStreamException e) { break; } } } outRead.BaseStream.Position = 0; var stringCount = outRead.ReadUInt32(); //Assuming UInt stringArray = new string[stringCount]; for (var i = 0; i < stringCount; i++) { stringArray[i] = outRead.ReadNullTermString(Encoding.UTF8); } Data = ParseBinaryKV3(outRead, null, true); }
private KVObject ParseBinaryKV3(BinaryReader reader, KVObject parent, bool inArray = false) { string name = null; if (!inArray) { var stringID = reader.ReadInt32(); name = (stringID == -1) ? string.Empty : stringArray[stringID]; } var datatype = reader.ReadByte(); KVFlag flagInfo = KVFlag.None; if ((datatype & 0x80) > 0) { datatype &= 0x7F; //Remove the flag bit. flagInfo = (KVFlag)reader.ReadByte(); } switch (datatype) { case (byte)KVType.NULL: parent.AddProperty(name, MakeValue(datatype, null, flagInfo)); break; case (byte)KVType.BOOLEAN: parent.AddProperty(name, MakeValue(datatype, reader.ReadBoolean(), flagInfo)); break; case (byte)KVType.INTEGER: parent.AddProperty(name, MakeValue(datatype, reader.ReadInt64(), flagInfo)); break; case (byte)KVType.DOUBLE: parent.AddProperty(name, MakeValue(datatype, reader.ReadDouble(), flagInfo)); break; case (byte)KVType.STRING: var id = reader.ReadInt32(); parent.AddProperty(name, MakeValue(datatype, id == -1 ? string.Empty : stringArray[id], flagInfo)); break; case (byte)KVType.ARRAY: var arrayLength = reader.ReadInt32(); //UInt or Int? var array = new KVObject(name, true); for (var i = 0; i < arrayLength; i++) { ParseBinaryKV3(reader, array, true); } parent.AddProperty(name, MakeValue(datatype, array, flagInfo)); break; case (byte)KVType.OBJECT: var objectLength = reader.ReadInt32(); //UInt or Int? var newObject = new KVObject(name, false); for (var i = 0; i < objectLength; i++) { ParseBinaryKV3(reader, newObject, false); } if (parent == null) { parent = newObject; } else { parent.AddProperty(name, MakeValue(datatype, newObject, flagInfo)); } break; default: throw new InvalidDataException(string.Format("Unknown KVType {0}", datatype)); } return parent; }