private void loadFromStream(Stream stream, string expectedContentType) { // TODO 流式读取尚未完成 // 增加参数,是否一次性读取 // 增加迭代器,用于流读取 // 如果是流读取,只有读取结束之时,才可以使用 Nodes 属性 var br = new BinaryReader(stream); if (!br.ReadBytes(5).SequenceEqual(mHeaderBytes)) // 文件头 throw new InvalidDataException("指定的流不是 CPK 数据,或流位置不正确。"); if ((this.FormatVersion = br.ReadUInt16()) > FORMAT_VERSION_CODE) // 版本号 throw new NotSupportedException("不支持读取此版本的 CPK 数据(CPK 格式版本过高)"); this.Flags = (CPKFlags)br.ReadUInt32(); // 标记位 this.ContentType = CPKNode.readStringWithLength(br); // 正文类型 if (expectedContentType != null && expectedContentType != this.ContentType) throw new InvalidDataException("输入数据的类型不是需要的类型。"); if ((this.Flags & CPKFlags.LZ4Compressed) == CPKFlags.LZ4Compressed) { stream = new Ceeji.Data.Codec.LZ4.LZ4Stream(stream, System.IO.Compression.CompressionMode.Decompress, false, 1024 * 1024 * 30); } if ((this.Flags & CPKFlags.LZ4HCCompressed) == CPKFlags.LZ4HCCompressed) { stream = new Ceeji.Data.Codec.LZ4.LZ4Stream(stream, System.IO.Compression.CompressionMode.Decompress, true, 1024 * 1024 * 30); } if ((this.Flags & CPKFlags.DeflateCompressed) == CPKFlags.DeflateCompressed) { stream = new DeflateStream(stream, System.IO.Compression.CompressionMode.Decompress, true); } long pos = -1, pos2 = -1; if (this.HashIncluded) { pos = stream.Position; } CPKNode hashNode = null; CPKNode node; while ((node = CPKNode.DeserializeFromStream(stream)) != null) { if (node.Name != "_!#hash#!_") { if (this.HashIncluded) { pos2 = stream.Position; } this.Nodes.Add(node.Name, node); if (node.Name == "_!#guid#!_") { this.PackageGuid = (Guid)node.Value.Value; } } else { hashNode = node; } } if (this.HashIncluded) { stream.Position = pos; var hash = HashHelper.ComputeRawHash(new PartialReadOnlyStream(stream, pos, pos2 - pos), HashHelper.MD5Algorithm); if (hashNode == null || !hashNode.Get<byte[]>().SequenceEqual(hash)) { throw new InvalidDataException("指定的输入数据的数据摘要不一致,可能已经被无意间修改"); } } }
/// <summary> /// 将包的内容写入指定的流。 /// </summary> /// <param name="stream"></param> public void WriteToStream(Stream stream) { if (stream == null) throw new ArgumentNullException("stream"); // 打开流进行写入 var bw = new BinaryWriter(stream); // 输出文件头 bw.Write(mHeaderBytes); bw.Write(FORMAT_VERSION_CODE); bw.Write((uint)this.Flags); bw.Write(CPKNode.getBinaryWithLength(Encoding.UTF8.GetBytes(ContentType))); // 输出正文 long pos = -1; if (this.HashIncluded) { pos = stream.Position; } if ((this.Flags & CPKFlags.LZ4Compressed) == CPKFlags.LZ4Compressed) { stream.Flush(); stream = new Ceeji.Data.Codec.LZ4.LZ4Stream(stream, System.IO.Compression.CompressionMode.Compress, false, 1024 * 1024 * 30); bw = new BinaryWriter(stream); } if ((this.Flags & CPKFlags.LZ4HCCompressed) == CPKFlags.LZ4HCCompressed) { stream.Flush(); stream = new Ceeji.Data.Codec.LZ4.LZ4Stream(stream, System.IO.Compression.CompressionMode.Compress, true, 1024 * 1024 * 30); bw = new BinaryWriter(stream); } if ((this.Flags & CPKFlags.DeflateCompressed) == CPKFlags.DeflateCompressed) { stream.Flush(); stream = new DeflateStream(stream, System.IO.Compression.CompressionMode.Compress, true); bw = new BinaryWriter(stream); } // var binNodes = mEmptyByteArr; foreach (var node in this.Nodes) { if (node.Key == "_!#hash#!_") continue; node.Value.SerializeToStream(stream); //binNodes = binNodes.Concat(data).ToArray(); } // bw.Write(binNodes); // 如果需要哈希,则计算哈希 if (this.HashIncluded) { long posn = stream.Position; stream.Position = pos; var hash = HashHelper.ComputeRawHash(stream, HashHelper.MD5Algorithm); stream.Position = posn; new CPKNode("_!#hash#!_", hash).SerializeToStream(stream); } // 输出结束符 bw.Write((byte)0); bw.Flush(); stream.Flush(); }