/// <summary> /// reads in all the indexes from the specified input stream. /// </summary> /// <param name="input"></param> public void ReadIndexes(Stream input) { // reads all the index data from the filestream while (input.Position < input.Length) { // get the starting position of the index block. long indexStartPosition = input.Position; int indexLength = 0; // read in the raw index descriptor: RawIndex raw = ReadNextIndexBlock(input, out indexLength); // add a new index to the list: _fileIndex.Add(new ArchiveFileIndex() { // keep the length, name, start index, and index block position/length FileLength = raw.L, FileName = raw.N, FileStartIndex = input.Position, IndexBlockPositionStart = indexStartPosition, IndexBlockLength = indexLength }); // skip the appropriate amount of the file: input.Position += raw.L; } }
/// <summary> /// writes the index data and the raw file blocks to the destination stream. /// </summary> /// <param name="destStream"></param> /// <param name="idx"></param> /// <param name="dataArray"></param> /// <param name="updIndex"></param> public static void AddRawData(Stream destStream, RawIndex idx, byte[] dataArray, IndexHandler updIndex) { // serialize and compress the index data: byte[] indexData = RawIndex.ToByteArray(idx); // generate the header bytes: byte[] header = BitConverter.GetBytes((ushort)indexData.Length); // move to the end of the stream: destStream.Position = destStream.Length; // write the header data: destStream.Write(header, 0, header.Length); // write the index data: destStream.Write(indexData, 0, indexData.Length); // add the index record to the handler: updIndex.ArchiveIndex.Add(new ArchiveFileIndex() { FileLength = idx.L, FileName = idx.N, FileStartIndex = destStream.Position }); // write the data to the stream destStream.Write(dataArray, 0, dataArray.Length); }
/// <summary> /// adds a list of files to an archive. /// </summary> /// <param name="data"></param> /// <param name="destStream"></param> /// <param name="updIndex"></param> public static void AddData(List <ArchiveFile> data, Stream destStream, IndexHandler updIndex) { if (!destStream.CanWrite) { throw new ArgumentException("Cannot Write to Stream"); } if (!destStream.CanSeek) { throw new ArgumentException("Cannot Seek!"); } // enumerate the archive files: generate the index and the data. foreach (var file in data) { // serialize and compress the archive file byte[] serialData = file.ToByteArray(); // generate a new index: RawIndex idx = new RawIndex() { N = file.ToString(), L = serialData.Length }; AddRawData(destStream, idx, serialData, updIndex); } }
/// <summary> /// read in the next index descriptor, and pass out the length. /// this assumes that the position of the filestream is at the start of an index. /// </summary> /// <param name="fs"></param> /// <returns></returns> public static RawIndex ReadNextIndexBlock(Stream fs, out int length) { // read in the length of the index data length = readNextIndexDataLength(fs); // read in the block of index data: byte[] idxBlock = ReadBuffer(fs, length); // deserialize it: return(RawIndex.FromByteArray(idxBlock)); }
/// <summary> /// remove a list of files from the archive by the archive file index. /// this works by duplicating the archive file into a temp location, skipping the files due to be deleted /// and then copying the duplicate back over the original. /// not the most inspired solution but better than nothing. /// </summary> /// <param name="filesToRemove"></param> public void RemoveFiles(List <ArchiveFileIndex> filesToRemove) { // create a temporary file: String tempFileName = Path.GetTempFileName(); // create a temporary archive: StreamingArchiveFile tempArc = new StreamingArchiveFile(tempFileName); // extract each file from this archive, add it to the other archive, // except the files to be deleted. using (Stream input = GetStream()) { using (Stream output = tempArc.GetStream()) { // enumerate the indexes: foreach (ArchiveFileIndex idx in _index.ArchiveIndex) { if (!filesToRemove.Contains(idx)) { // process this... read in the raw data block: input.Seek(idx.FileStartIndex, SeekOrigin.Begin); // read the compressed file data: byte[] data = IndexHandler.ReadBuffer(input, idx.FileLength); // now generate the raw index: RawIndex rawIndex = new RawIndex() { N = idx.FileName, L = idx.FileLength }; // add to the destination: AddRawData(output, rawIndex, data, tempArc._index); } } } } // now copy the temp file back over the archive: File.Delete(_fileName); File.Move(tempFileName, _fileName); // now re-read the indexes: OpenArchive(_fileName); }
/// <summary> /// compresses an array of RawIndex objects to a byte-array. /// </summary> /// <param name="indexData"></param> /// <returns></returns> public static byte[] ToByteArray(RawIndex indexData) { return TinySerializer.Serialize(indexData, true); }
/// <summary> /// adds a list of files to an archive. /// </summary> /// <param name="data"></param> /// <param name="destStream"></param> /// <param name="updIndex"></param> public static void AddData(List<ArchiveFile> data, Stream destStream, IndexHandler updIndex) { if (!destStream.CanWrite) throw new ArgumentException("Cannot Write to Stream"); if (!destStream.CanSeek) throw new ArgumentException("Cannot Seek!"); // enumerate the archive files: generate the index and the data. foreach (var file in data) { // serialize and compress the archive file byte[] serialData = file.ToByteArray(); // generate a new index: RawIndex idx = new RawIndex() { N = file.ToString(), L = serialData.Length }; AddRawData(destStream, idx, serialData, updIndex); } }
/// <summary> /// remove a list of files from the archive by the archive file index. /// this works by duplicating the archive file into a temp location, skipping the files due to be deleted /// and then copying the duplicate back over the original. /// not the most inspired solution but better than nothing. /// </summary> /// <param name="filesToRemove"></param> public void RemoveFiles(List<ArchiveFileIndex> filesToRemove) { // create a temporary file: String tempFileName = Path.GetTempFileName(); // create a temporary archive: StreamingArchiveFile tempArc = new StreamingArchiveFile(tempFileName); // extract each file from this archive, add it to the other archive, // except the files to be deleted. using (Stream input = GetStream()) { using (Stream output = tempArc.GetStream()) { // enumerate the indexes: foreach (ArchiveFileIndex idx in _index.ArchiveIndex) { if (!filesToRemove.Contains(idx)) { // process this... read in the raw data block: input.Seek(idx.FileStartIndex, SeekOrigin.Begin); // read the compressed file data: byte[] data = IndexHandler.ReadBuffer(input, idx.FileLength); // now generate the raw index: RawIndex rawIndex = new RawIndex() { N = idx.FileName, L = idx.FileLength }; // add to the destination: AddRawData(output, rawIndex, data, tempArc._index); } } } } // now copy the temp file back over the archive: File.Delete(_fileName); File.Move(tempFileName, _fileName); // now re-read the indexes: OpenArchive(_fileName); }
/// <summary> /// compresses an array of RawIndex objects to a byte-array. /// </summary> /// <param name="indexData"></param> /// <returns></returns> public static byte[] ToByteArray(RawIndex indexData) { return(TinySerializer.Serialize(indexData, true)); }