public static Base Read(Stream stream) { var b = (byte)stream.ReadByte(); bool f = (b & 0x80) == 0x80; if (!f) throw new UnknownValueFlagException(); var valueType = stream.ReadUtf8String(b & 0x7f); var tmp = new byte[4]; stream.FillInBuffer(tmp, 2); int valueLength = BitConverter.ToUInt16(tmp, 0); if (valueLength == 0xffff) valueLength = stream.ReadInt32() - 4; //todo: shouldn't it be 6??? else { stream.FillInBuffer(tmp, 2, tmp.Length - 2); valueLength = BitConverter.ToInt32(tmp, 0); } tmp = new byte[valueLength]; stream.FillInBuffer(tmp); switch (valueType) { case "Uint8": return new Uint8(tmp); case "Uint16": return new Uint16(tmp); case "Uint": return new Uint(tmp); case "Uint64": return new Uint64(tmp); case "Int8": return new Int8(tmp); case "Int16": return new Int16(tmp); case "Int": return new Int(tmp); case "Int64": return new Int64(tmp); case "String": return new String(tmp); case "CGUID": return new CGuid(tmp); case "Bool": return new Bool(tmp); case "SQuestLogPhaseStatus": return new SQuestLogPhaseStatus(tmp); default: return new UnknownValueType(tmp){valueTypeName = valueType}; } }
/// <summary> /// Decompresses the data using LibLZF algorithm /// </summary> /// <param name="input">Reference to the data to decompress</param> /// <param name="inputLength">Lenght of the data to decompress</param> /// <param name="output">Reference to a buffer which will contain the decompressed data</param> /// <param name="outputLength">The size of the decompressed archive in the output buffer</param> /// <returns>Returns decompressed size</returns> public static int Decompress(this Stream input, Stream output, long inputLength, long outputLength) { uint readBytes = 0; uint writtenBytes = 0; do { var ctrl = (uint)input.ReadByte(); readBytes++; if (ctrl < (1 << 5)) /* literal run */ { ctrl++; if (writtenBytes + ctrl > outputLength) throw new InvalidOperationException("LZF decompression error E2BIG."); var tmp = new byte[ctrl]; input.FillInBuffer(tmp); readBytes += ctrl; output.Write(tmp, 0, tmp.Length); writtenBytes += ctrl; } else /* back reference */ { uint len = ctrl >> 5; int reference = (int)(writtenBytes - ((ctrl & 0x1f) << 8) - 1); if (len == 7) { len += (uint)input.ReadByte(); readBytes++; } reference -= input.ReadByte(); readBytes++; if (writtenBytes + len + 2 > outputLength) throw new InvalidOperationException("LZF decompression error E2BIG."); if (reference < 0) throw new InvalidOperationException("LZF decompression error EINVAL."); var currentPosition = output.Position; output.Seek(reference, SeekOrigin.Begin); var patternLength = len + 2; /* * fun part is when pattern length is longer than we have * so, if we have 'abcdef' in output and have to write a pattern of length 7, starting from d, * we have to have 'abcdefdefdefd' in the end. */ var tmp = new byte[Math.Min(currentPosition - reference, patternLength)]; var read = output.FillInBuffer(tmp); if (read != tmp.Length) throw new InvalidOperationException(string.Format("Expected {0} bytes to be read, but was {1}", tmp.Length, read)); output.Seek(currentPosition, SeekOrigin.Begin); //making copies until we write a pattern of given length do { var blockSize = (int)Math.Min(tmp.Length, patternLength); output.Write(tmp, 0, blockSize); patternLength -= (uint)blockSize; } while (patternLength > 0); writtenBytes += len + 2; } } while (readBytes < inputLength); return (int)writtenBytes; }