/// <summary> /// Writes a file contained in an archive to the cache. /// </summary> /// <param name="type"> The type of file. </param> /// <param name="file"> The id of the archive. </param> /// <param name="member"> The file within the archive. </param> /// <param name="data"> The data to write. </param> /// <exception cref="IOException"> if an I/O error occurs. </exception> public void Write(int type, int file, int member, ByteBuffer data) { /* grab the reference table */ var tableContainer = Container.Decode(store.Read(255, type)); var table = ReferenceTable.Decode(tableContainer.GetData()); /* create a new entry if necessary */ var entry = table.GetEntry(file); var oldArchiveSize = -1; if (entry == null) { entry = new ReferenceTable.Entry(); table.PutEntry(file, entry); } else { oldArchiveSize = entry.Capacity(); } /* add a child entry if one does not exist */ var child = entry.GetEntry(member); if (child == null) { child = new ReferenceTable.ChildEntry(); entry.PutEntry(member, child); } /* extract the current archive into memory so we can modify it */ Archive archive; int containerType, containerVersion; Container container; if (file < store.GetFileCount(type) && oldArchiveSize != -1) { container = Read(type, file); containerType = container.GetType(); containerVersion = container.GetVersion(); archive = Archive.Decode(container.GetData(), oldArchiveSize); } else { containerType = Container.COMPRESSION_GZIP; containerVersion = 1; archive = new Archive(member + 1); } /* expand the archive if it is not large enough */ if (member >= archive.Size()) { var newArchive = new Archive(member + 1); for (var id = 0; id < archive.Size(); id++) { newArchive.PutEntry(id, archive.GetEntry(id)); } archive = newArchive; } /* put the member into the archive */ archive.PutEntry(member, data); /* create 'dummy' entries */ for (var id = 0; id < archive.Size(); id++) { if (archive.GetEntry(id) == null) { entry.PutEntry(id, new ReferenceTable.ChildEntry()); archive.PutEntry(id, ByteBuffer.allocate(1)); } } /* write the reference table out again */ tableContainer = new Container(tableContainer.GetType(), table.Encode()); store.Write(255, type, tableContainer.Encode()); /* and write the archive back to memory */ container = new Container(containerType, archive.Encode(), containerVersion); Write(type, file, container); }
/// <summary> /// Writes a file to the cache and updates the <seealso cref="ReferenceTable" /> that /// it is associated with. /// </summary> /// <param name="type"> The type of file. </param> /// <param name="file"> The file id. </param> /// <param name="container"> The <seealso cref="Container" /> to write. </param> /// <exception cref="IOException"> if an I/O error occurs. </exception> public void Write(int type, int file, Container container) { /* we don't want people reading/manipulating these manually */ if (type == 255) { throw new IOException("Reference tables can only be modified with the low level FileStore API!"); } /* increment the container's version */ container.SetVersion(container.GetVersion() + 1); /* decode the reference table for this index */ var tableContainer = Container.Decode(store.Read(255, type)); var table = ReferenceTable.Decode(tableContainer.GetData()); /* grab the bytes we need for the checksum */ var buffer = container.Encode(); var bytes = new byte[buffer.limit() - 2]; // last two bytes are the version and shouldn't be included buffer.mark(); try { buffer.position(0); buffer.get(bytes, 0, bytes.Length); } finally { buffer.reset(); } /* calculate the new CRC checksum */ var crc = new CRC32(); crc.update(bytes, 0, bytes.Length); /* update the version and checksum for this file */ var entry = table.GetEntry(file); if (entry == null) { /* create a new entry for the file */ entry = new ReferenceTable.Entry(); table.PutEntry(file, entry); } entry.SetVersion(container.GetVersion()); entry.SetCrc((int)crc.getValue()); /* calculate and update the whirlpool digest if we need to */ if ((table.GetFlags() & ReferenceTable.FLAG_WHIRLPOOL) != 0) { var whirlpool = Whirlpool.Crypt(bytes, 0, bytes.Length); entry.SetWhirlpool(whirlpool); } /* update the reference table version */ table.SetVersion(table.GetVersion() + 1); /* save the reference table */ tableContainer = new Container(tableContainer.GetType(), table.Encode()); store.Write(255, type, tableContainer.Encode()); /* save the file itself */ store.Write(type, file, buffer); }