public VDFNode GetNodeAt(string[] args, bool create, int index) { if (index >= args.Length) { return(this); } if (NodeType != ValueType.Array) { return(null); } if (!(NodeData is Dictionary <string, VDFNode> arrayData)) { throw new InvalidCastException("NodeData is not a Dictionary<string, VDFNode>"); } if (ContainsKey(args[index])) { return(arrayData[args[index]].GetNodeAt(args, create, index + 1)); } if (!create) { return(null); } VDFNode newNode = new VDFNode(); arrayData.Add(args[index], newNode); return(newNode.GetNodeAt(args, true, index + 1)); }
public static VDFNode LoadFromText(StreamReader stream, bool useFirstAsRoot) { VDFNode thisLevel = useFirstAsRoot ? null : new VDFNode(); ReadText_SkipWhitespace(stream); while (!stream.EndOfStream) { ReadText_SkipWhitespace(stream); // Get key char nextChar = (char)stream.Read(); if (stream.EndOfStream || nextChar == '}') { break; } if (nextChar != '"') { throw new InvalidDataException(string.Format(CultureInfo.InvariantCulture, "Unexpected Character Key '{0}'", nextChar)); } string key = ReadText_GetStringToken(stream); ReadText_SkipWhitespace(stream); // Get value nextChar = (char)stream.Read(); VDFNode newNode; if (nextChar == '"') { newNode = new VDFNode(ReadText_GetStringToken(stream)); } else if (nextChar == '{') { newNode = LoadFromText(stream); } else { throw new InvalidDataException(string.Format(CultureInfo.InvariantCulture, "Unexpected Character Value '{0}'", nextChar)); } if (useFirstAsRoot) { return(newNode); } thisLevel[key] = newNode; } return(thisLevel); }
public static PackageInfo FromNode(VDFNode node) { VDFNode idNode = node.GetNodeAt(new[] { "packageId" }, false); if ((idNode == null) || (idNode.NodeType != ValueType.Int)) { return(null); } int id = idNode.NodeInt; string name = null; VDFNode nameNode = node.GetNodeAt(new[] { "name" }, false); if ((nameNode != null) && (nameNode.NodeType == ValueType.String)) { name = nameNode.NodeString; } PackageInfo packageInfo = new PackageInfo(id, name); VDFNode billingTypeNode = node["billingtype"]; if ((billingTypeNode != null) && ((billingTypeNode.NodeType == ValueType.String) || (billingTypeNode.NodeType == ValueType.Int))) { int bType = billingTypeNode.NodeInt; packageInfo.BillingType = (PackageBillingType)bType; } VDFNode appsNode = node["appids"]; if ((appsNode == null) || (appsNode.NodeType != ValueType.Array)) { return(packageInfo); } foreach (VDFNode appNode in appsNode.NodeArray.Values) { if (appNode.NodeType == ValueType.Int) { packageInfo.AppIds.Add(appNode.NodeInt); } } return(packageInfo); }
public static Dictionary <int, PackageInfo> LoadPackages(string path) { /* * packageinfo.vdf entry example format, sometimes has extra values. Line breaks are only for readability and not part of format. * we only care about *packageid*, *billingtype*, *appids* * *undeciphered*(24 bytes i haven't deciphered) *changenumber*(4 bytes, little endian) * 00 *packageid*(variable size, big endian, ascii) 00 * 02 packageid 00 *packageid*(4 bytes, little endian) * 02 billingtype 00 *billingtype*(4 bytes, little endian) * 02 licensetype 00 *licensetype*(4 bytes, little endian) * 02 status 00 00 00 00 00 00 extended 00 * 08 00 appids 00 02 *entrynumber*(variable size, number stored as string(ascii), starts at 0, random example: 31 38 39=189) 00 *appid*(4 bytes, little endian) * 08 00 depotids 00 02 *entrynumber* 00 *depotid*(4 bytes, little endian) 02 *entrynumber* 00 *depotid* 02 *entrynumber* 00 *depotid* * 08 00 appitems 00 08 08 08 */ Dictionary <int, PackageInfo> packageInfos = new Dictionary <int, PackageInfo>(); using (BinaryReader binaryReader = new BinaryReader(new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read), Encoding.ASCII)) { long streamLength = binaryReader.BaseStream.Length; VDFNode.ReadBin_SeekTo(binaryReader, PackageidBytes, streamLength); while (binaryReader.BaseStream.Position < streamLength) { int id = binaryReader.ReadInt32(); PackageInfo package = new PackageInfo(id); VDFNode.ReadBin_SeekTo(binaryReader, BillingtypeBytes, streamLength); package.BillingType = (PackageBillingType)binaryReader.ReadInt32(); VDFNode.ReadBin_SeekTo(binaryReader, AppidsBytes, streamLength); while (binaryReader.ReadByte() == 0x02) { while (binaryReader.ReadByte() != 0x00) { } package.AppIds.Add(binaryReader.ReadInt32()); } packageInfos.Add(package.Id, package); VDFNode.ReadBin_SeekTo(binaryReader, PackageidBytes, streamLength); } } return(packageInfos); }
/// <summary> /// Loads a VDFNode from a stream. /// </summary> /// <param name="stream">Stream to read from.</param> /// <param name="streamLength">Length of stream in bytes.</param> /// <returns>VDFNode representing the content of the given stream.</returns> public static VDFNode LoadFromBinary(BinaryReader stream, long streamLength) { if (stream.BaseStream.Position == streamLength) { return(null); } VDFNode thisLevel = new VDFNode(); bool endOfStream = false; while (true) { byte nextByte; try { nextByte = stream.ReadByte(); } catch (EndOfStreamException) { endOfStream = true; nextByte = 8; } if (endOfStream || nextByte == 8 || stream.BaseStream.Position == streamLength) { break; } string key; switch (nextByte) { case 0: { key = ReadBin_GetStringToken(stream); VDFNode newNode = LoadFromBinary(stream, streamLength); thisLevel[key] = newNode; break; } case 1: key = ReadBin_GetStringToken(stream); thisLevel[key] = new VDFNode(ReadBin_GetStringToken(stream)); break; case 2: { key = ReadBin_GetStringToken(stream); int val = stream.ReadInt32(); thisLevel[key] = new VDFNode(val); break; } case 7: { key = ReadBin_GetStringToken(stream); ulong val = stream.ReadUInt64(); thisLevel[key] = new VDFNode(val); break; } case 0xFF: return(null); default: throw new InvalidDataException(string.Format(CultureInfo.InvariantCulture, "Unexpected Character Key '{0}'", nextByte)); } } return(thisLevel); }
/// <summary> /// Loads Apps from packageinfo.vdf. /// </summary> /// <param name="path">Path of packageinfo.vdf</param> public static Dictionary <int, PackageInfo> LoadPackages(string path) { Dictionary <int, PackageInfo> result = new Dictionary <int, PackageInfo>(); /* packageinfo.vdf entry example format, sometimes has extra values. Line breaks are only for readability and not part of format. * we only care about *packageid*, *billingtype*, *appids* * *undeciphered*(24 bytes i haven't deciphered) *changenumber*(4 bytes, little endian) * 00 *packageid*(variable size, big endian, ascii) 00 * 02 packageid 00 *packageid*(4 bytes, little endian) * 02 billingtype 00 *billingtype*(4 bytes, little endian) * 02 licensetype 00 *licensetype*(4 bytes, little endian) * 02 status 00 00 00 00 00 00 extended 00 * 08 00 appids 00 02 *entrynumber*(variable size, number stored as string(ascii), starts at 0, random example: 31 38 39=189) 00 *appid*(4 bytes, little endian) * 08 00 depotids 00 02 *entrynumber* 00 *depotid*(4 bytes, little endian) 02 *entrynumber* 00 *depotid* 02 *entrynumber* 00 *depotid* * 08 00 appitems 00 08 08 08 */ BinaryReader bReader = new BinaryReader(new FileStream(path, FileMode.Open), Encoding.ASCII); long fileLength = bReader.BaseStream.Length; // seek to packageid: start of a new entry byte[] packageidBytes = { 0x00, 0x02, 0x70, 0x61, 0x63, 0x6B, 0x61, 0x67, 0x65, 0x69, 0x64, 0x00 }; // 0x00 0x02 p a c k a g e i d 0x00 byte[] billingtypeBytes = { 0x02, 0x62, 0x69, 0x6C, 0x6C, 0x69, 0x6E, 0x67, 0x74, 0x79, 0x70, 0x65, 0x00 }; // 0x02 b i l l i n g t y p e 0x00 byte[] appidsBytes = { 0x08, 0x00, 0x61, 0x70, 0x70, 0x69, 0x64, 0x73, 0x00 }; // 0x08 0x00 appids 0x00 VDFNode.ReadBin_SeekTo(bReader, packageidBytes, fileLength); while (bReader.BaseStream.Position < fileLength) { int id = bReader.ReadInt32(); PackageInfo package = new PackageInfo(id); VDFNode.ReadBin_SeekTo(bReader, billingtypeBytes, fileLength); package.BillingType = (PackageBillingType)bReader.ReadInt32(); VDFNode.ReadBin_SeekTo(bReader, appidsBytes, fileLength); while (bReader.ReadByte() == 0x02) { while (bReader.ReadByte() != 0x00) { } package.AppIds.Add(bReader.ReadInt32()); } result.Add(package.Id, package); VDFNode.ReadBin_SeekTo(bReader, packageidBytes, fileLength); } return(result); }