예제 #1
0
        /// <summary>
        ///     Computes the <seealso cref="ChecksumTable" /> for this cache. The checksum table
        ///     forms part of the so-called "update keys".
        /// </summary>
        /// <returns> The <seealso cref="ChecksumTable" />. </returns>
        /// <exception cref="IOException"> if an I/O error occurs. </exception>
        public ChecksumTable CreateChecksumTable()
        {
            /* create the checksum table */
            var size  = store.GetTypeCount();
            var table = new ChecksumTable(size);

            /* loop through all the reference tables and get their CRC and versions */
            for (var i = 0; i < size; i++)
            {
                var buf = store.Read(255, i);

                var crc       = 0;
                var version   = 0;
                var whirlpool = new byte[64];

                /*
                 * if there is actually a reference table, calculate the CRC,
                 * version and whirlpool hash
                 */
                if (buf.limit() > 0) // some indices are not used, is this appropriate?
                {
                    var @ref = ReferenceTable.Decode(Container.Decode(buf)
                                                     .GetData());
                    crc     = ByteBufferExtensions.GetCrcChecksum(buf);
                    version = @ref.GetVersion();
                    buf.position(0);
                    whirlpool = ByteBufferExtensions.GetWhirlpoolDigest(buf);
                }

                table.SetEntry(i, new ChecksumTable.Entry(crc, version, whirlpool));
            }

            /* return the table */
            return(table);
        }
예제 #2
0
        /// <summary>
        ///     Reads a file contained in an archive in the cache.
        /// </summary>
        /// <param name="type"> The type of the file. </param>
        /// <param name="file"> The archive id. </param>
        /// <param name="file"> The file within the archive. </param>
        /// <returns> The file. </returns>
        /// <exception cref="IOException"> if an I/O error occurred. </exception>
        public ByteBuffer Read(int type, int file, int member)
        {
            /* grab the container and the reference table */
            var container      = Read(type, file);
            var tableContainer = Container.Decode(store.Read(255, type));
            var table          = ReferenceTable.Decode(tableContainer.GetData());

            /* check if the file/member are valid */
            var entry = table.GetEntry(file);

            if (entry == null || member < 0 || member >= entry.Capacity())
            {
                throw new FileNotFoundException();
            }

            /* extract the entry from the archive */
            var archive = Archive.Decode(container.GetData(), entry.Capacity());

            return(archive.GetEntry(member));
        }
예제 #3
0
        /// <summary>
        ///     Decodes the slave checksum table contained in the specified
        ///     <seealso cref="ByteBuffer" />.
        /// </summary>
        /// <param name="buffer"> The buffer. </param>
        /// <returns> The slave checksum table. </returns>
        public static ReferenceTable Decode(ByteBuffer buffer)
        {
            /* create a new table */
            var table = new ReferenceTable();

            /* read header */
            table.format = buffer.get() & 0xFF;
            if (table.format >= 6)
            {
                table.version = buffer.getInt();
            }
            table.flags = buffer.get() & 0xFF;

            /* read the ids */
            var ids         = new int[buffer.getShort() & 0xFFFF];
            int accumulator = 0,
                size        = -1;

            for (var i = 0; i < ids.Length; i++)
            {
                var delta = buffer.getShort() & 0xFFFF;
                ids[i] = accumulator += delta;
                if (ids[i] > size)
                {
                    size = ids[i];
                }
            }
            size++;

            /* and allocate specific entries within that array */
            foreach (var id in ids)
            {
                table.entries[id] = new Entry();
            }

            /* read the identifiers if present */
            if ((table.flags & FLAG_IDENTIFIERS) != 0)
            {
                foreach (var id in ids)
                {
                    table.entries[id].identifier = buffer.getInt();
                }
            }

            /* read the CRC32 checksums */
            foreach (var id in ids)
            {
                table.entries[id].crc = buffer.getInt();
            }

            /* read the whirlpool digests if present */
            if ((table.flags & FLAG_WHIRLPOOL) != 0)
            {
                foreach (var id in ids)
                {
                    buffer.get(table.entries[id].whirlpool);
                }
            }

            /* read the version numbers */
            foreach (var id in ids)
            {
                table.entries[id].version = buffer.getInt();
            }

            /* read the child sizes */
            var members = new int[size][];

            foreach (var id in ids)
            {
                members[id] = new int[buffer.getShort() & 0xFFFF];
            }

            /* read the child ids */
            foreach (var id in ids)
            {
                /* reset the accumulator and size */
                accumulator = 0;
                size        = -1;

                /* loop through the array of ids */
                for (var i = 0; i < members[id].Length; i++)
                {
                    var delta = buffer.getShort() & 0xFFFF;
                    members[id][i] = accumulator += delta;
                    if (members[id][i] > size)
                    {
                        size = members[id][i];
                    }
                }
                size++;

                /* and allocate specific entries within the array */
                foreach (var child in members[id])
                {
                    table.entries[id].entries.Add(child, new ChildEntry());
                }
            }

            /* read the child identifiers if present */
            if ((table.flags & FLAG_IDENTIFIERS) != 0)
            {
                foreach (var id in ids)
                {
                    foreach (var child in members[id])
                    {
                        table.entries[id].entries[child].identifier = buffer.getInt();
                    }
                }
            }

            /* return the table we constructed */
            return(table);
        }
예제 #4
0
        /// <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);
        }
예제 #5
0
        /// <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);
        }