Beispiel #1
0
        private static void fileCache_updateFiletable(FileCache fileCache, Int32 extraEntriesToAllocate)
        {
            // recreate file table with bigger size (optional)
            fileCache.FileTableEntries[0].Name1 = FilecacheFiletableFreeName;
            fileCache.FileTableEntries[0].Name2 = FilecacheFiletableFreeName;
            Int32 newFileTableEntryCount = (Int32)fileCache.FileTableEntryCount + extraEntriesToAllocate;

            Array.Resize(ref fileCache.FileTableEntries, newFileTableEntryCount);
            for (Int32 f = (Int32)fileCache.FileTableEntryCount; f < newFileTableEntryCount; f++)
            {
                fileCache.FileTableEntries[f] = new FileCacheEntry
                {
                    Name1      = FilecacheFiletableFreeName,
                    Name2      = FilecacheFiletableFreeName,
                    FileOffset = 0,
                    FileSize   = 0
                };
            }
            fileCache.FileTableEntryCount = (UInt32)newFileTableEntryCount;

            byte[] fileTable = AsByteArray(fileCache.FileTableEntries);
            fileCache_addFile(fileCache, FilecacheFiletableName1, FilecacheFiletableName2, fileTable, SizeofFileCacheEntryT * newFileTableEntryCount);

            // update file table info in struct
            if (fileCache.FileTableEntries[0].Name1 != FilecacheFiletableName1 || fileCache.FileTableEntries[0].Name2 != FilecacheFiletableName2)
            {
                __debugbreak();
            }
            fileCache.FileTableOffset = fileCache.FileTableEntries[0].FileOffset;
            fileCache.FileTableSize   = fileCache.FileTableEntries[0].FileSize;
            // update header
            stream_setSeek64(fileCache.StreamFile2, 0);
            stream_writeU32(fileCache.StreamFile2, FilecacheMagicV2);
            stream_writeU32(fileCache.StreamFile2, fileCache.ExtraVersion);
            stream_writeU64(fileCache.StreamFile2, fileCache.DataOffset);
            stream_writeU64(fileCache.StreamFile2, fileCache.FileTableOffset);
            stream_writeU32(fileCache.StreamFile2, fileCache.FileTableSize);
        }
Beispiel #2
0
        public static FileCache fileCache_create(string path, UInt32 extraVersion)
        {
            FileCache    fileCache  = new FileCache();
            BinaryWriter streamFile = new BinaryWriter(File.Open(path, FileMode.Create));

            // init file cache
            fileCache.StreamFile2         = streamFile;
            fileCache.DataOffset          = FilecacheHeaderResv;
            fileCache.FileTableEntryCount = 32;
            fileCache.FileTableOffset     = 0;
            fileCache.FileTableSize       = SizeofFileCacheEntryT * fileCache.FileTableEntryCount;
            fileCache.FileTableEntries    = new FileCacheEntry[fileCache.FileTableEntryCount];
            for (Int32 f = 0; f < (Int32)fileCache.FileTableEntryCount; f++)
            {
                fileCache.FileTableEntries[f] = new FileCacheEntry();
            }

            fileCache.ExtraVersion = extraVersion;
            // file table stores info about itself
            fileCache.FileTableEntries[0].Name1      = FilecacheFiletableName1;
            fileCache.FileTableEntries[0].Name2      = FilecacheFiletableName2;
            fileCache.FileTableEntries[0].FileOffset = fileCache.FileTableOffset;
            fileCache.FileTableEntries[0].FileSize   = fileCache.FileTableSize;
            // write header
            stream_writeU32(streamFile, FilecacheMagicV2);
            stream_writeU32(fileCache.StreamFile2, fileCache.ExtraVersion);
            stream_writeU64(fileCache.StreamFile2, fileCache.DataOffset);
            stream_writeU64(fileCache.StreamFile2, fileCache.FileTableOffset);
            stream_writeU32(fileCache.StreamFile2, fileCache.FileTableSize);
            // write file table
            stream_setSeek64(fileCache.StreamFile2, fileCache.DataOffset + fileCache.FileTableOffset);
            stream_writeData(fileCache.StreamFile2, fileCache.FileTableEntries, fileCache.FileTableEntryCount);

            // done
            return(fileCache);
        }
Beispiel #3
0
        public static FileCache fileCache_openExisting(string path, UInt32 extraVersion)
        {
            FileCache fileCache = new FileCache();

            using (BinaryReader streamFile = new BinaryReader(File.Open(path, FileMode.Open)))
            {
                UInt32 headerMagic = stream_readU32(streamFile);
                bool   isV1        = false;
                if (headerMagic != FilecacheMagic && headerMagic != FilecacheMagicV2)
                {
                    stream_destroy();
                    return(null);
                }
                if (headerMagic == FilecacheMagic)
                {
                    isV1 = true;
                }

                UInt32 headerExtraVersion = stream_readU32(streamFile);
                if (headerExtraVersion != extraVersion)
                {
                    stream_destroy();
                    return(null);
                }

                UInt64 headerDataOffset;
                if (isV1)
                {
                    headerDataOffset = stream_readU32(streamFile);
                }
                else
                {
                    headerDataOffset = stream_readU64(streamFile);
                }
                UInt64 headerFileTableOffset;
                if (isV1)
                {
                    headerFileTableOffset = stream_readU32(streamFile);
                }
                else
                {
                    headerFileTableOffset = stream_readU64(streamFile);
                }

                UInt32 headerFileTableSize = stream_readU32(streamFile);

                UInt32 fileTableEntryCount;
                bool   invalidFileTableSize;
                if (isV1)
                {
                    fileTableEntryCount  = headerFileTableSize / 24;
                    invalidFileTableSize = (headerFileTableSize % 24) != 0;
                }
                else
                {
                    fileTableEntryCount  = headerFileTableSize / SizeofFileCacheEntryT;
                    invalidFileTableSize = (headerFileTableSize % SizeofFileCacheEntryT) != 0;
                }

                if (invalidFileTableSize)
                {
                    Console.WriteLine(Resources.FileCache_fileCache_openExisting___0___is_corrupted, path);
                    stream_destroy();
                    return(null);
                }

                InitializeCriticalSection();
                fileCache.StreamFile          = streamFile;
                fileCache.ExtraVersion        = extraVersion;
                fileCache.DataOffset          = headerDataOffset;
                fileCache.FileTableEntryCount = fileTableEntryCount;
                fileCache.FileTableOffset     = headerFileTableOffset;
                fileCache.FileTableSize       = fileTableEntryCount * SizeofFileCacheEntryT;
                fileCache.FileTableEntries    = new FileCacheEntry[fileTableEntryCount];

                stream_setSeek64(streamFile, fileCache.DataOffset + fileCache.FileTableOffset);

                if (isV1)
                {
                    // read file table entries in old format
                    for (UInt32 i = 0; i < fileTableEntryCount; i++)
                    {
                        UInt64 name1      = stream_readU64(streamFile);
                        UInt64 name2      = stream_readU64(streamFile);
                        UInt32 fileOffset = stream_readU32(streamFile);
                        UInt32 fileSize   = stream_readU32(streamFile);
                        fileCache.FileTableEntries[i].Name1         = name1;
                        fileCache.FileTableEntries[i].Name2         = name2;
                        fileCache.FileTableEntries[i].FileOffset    = fileOffset;
                        fileCache.FileTableEntries[i].FileSize      = fileSize;
                        fileCache.FileTableEntries[i].ExtraReserved = 0;
                    }
                }
                else
                {
                    stream_readData(streamFile, fileCache.FileTableEntries, fileTableEntryCount);
                }
                // upgrade file table and header if V1
                if (isV1)
                {
                    fileCache_updateFiletable(fileCache, 0);
                }
            }
            return(fileCache);
        }
Beispiel #4
0
        public static void fileCache_addFile(FileCache fileCache, UInt64 name1, UInt64 name2, byte[] fileData, Int32 fileSize, UInt32 extraReserved = 0)
        {
            if (fileCache == null)
            {
                return;
            }
            EnterCriticalSection();
            // find free entry in file table
            Int32 entryIndex = -1;

            // scan for already existing entry
            for (Int32 i = 0; i < fileCache.FileTableEntryCount; i++)
            {
                if (fileCache.FileTableEntries[i].Name1 == name1 && fileCache.FileTableEntries[i].Name2 == name2)
                {
                    entryIndex = i;
                    // note: We don't delete the entry right here to avoid it being overwritten before the new file is added
                    break;
                }
            }
            if (entryIndex == -1)
            {
                while (true)
                {
                    // if no entry exists, search for empty one
                    for (Int32 i = 0; i < fileCache.FileTableEntryCount; i++)
                    {
                        if (fileCache.FileTableEntries[i].Name1 == FilecacheFiletableFreeName && fileCache.FileTableEntries[i].Name2 == FilecacheFiletableFreeName)
                        {
                            entryIndex = i;
                            break;
                        }
                    }
                    if (entryIndex == -1)
                    {
                        if (name1 == FilecacheFiletableName1 && name2 == FilecacheFiletableName2)
                        {
                            __debugbreak();
                        }
                        // no free entry, recreate file table with bigger size
                        fileCache_updateFiletable(fileCache, 64);
                        // try again
                    }
                    else
                    {
                        break;
                    }
                }
            }
            // find free space
            UInt64 currentStartOffset = 0;
            int    s0 = 0;

            while (true)
            {
                bool   hasCollision     = false;
                UInt64 currentEndOffset = currentStartOffset + (UInt64)fileSize;

                int entry     = s0;
                int entryLast = (int)fileCache.FileTableEntryCount;
                while (entry < entryLast)
                {
                    if (fileCache.FileTableEntries[entry].Name1 == FilecacheFiletableFreeName && fileCache.FileTableEntries[entry].Name2 == FilecacheFiletableFreeName)
                    {
                        entry++;
                        continue;
                    }
                    if (currentEndOffset >= fileCache.FileTableEntries[entry].FileOffset && currentStartOffset < fileCache.FileTableEntries[entry].FileOffset + fileCache.FileTableEntries[entry].FileSize)
                    {
                        currentStartOffset = fileCache.FileTableEntries[entry].FileOffset + fileCache.FileTableEntries[entry].FileSize;
                        hasCollision       = true;
                        s0 = 0;
                        break;
                    }
                    s0 = entry;
                    entry++;
                }
                // special logic to speed up scanning for free offsets
                // assumes that most of the time entries are stored in direct succession (unless entries are frequently deleted)
                if (hasCollision && (entry + 1) < entryLast)
                {
                    entry++;
                    while (entry < entryLast)
                    {
                        if (fileCache.FileTableEntries[entry].Name1 == FilecacheFiletableFreeName && fileCache.FileTableEntries[entry].Name2 == FilecacheFiletableFreeName)
                        {
                            entry++;
                            continue;
                        }
                        if (fileCache.FileTableEntries[entry].FileOffset == currentStartOffset)
                        {
                            currentStartOffset = fileCache.FileTableEntries[entry].FileOffset + fileCache.FileTableEntries[entry].FileSize;
                            entry++;
                            continue;
                        }
                        entry = entryLast;
                    }
                }
                // retry in case of collision
                if (!hasCollision)
                {
                    break;
                }
            }
            // update file table entry
            fileCache.FileTableEntries[entryIndex].Name1         = name1;
            fileCache.FileTableEntries[entryIndex].Name2         = name2;
            fileCache.FileTableEntries[entryIndex].ExtraReserved = extraReserved;
            fileCache.FileTableEntries[entryIndex].FileOffset    = currentStartOffset;
            fileCache.FileTableEntries[entryIndex].FileSize      = (UInt32)fileSize;
            // write file data
            stream_setSeek64(fileCache.StreamFile2, fileCache.DataOffset + currentStartOffset);
            stream_writeData(fileCache.StreamFile2, fileData);
            // write file table entry
            stream_setSeek64(fileCache.StreamFile2, fileCache.DataOffset + fileCache.FileTableOffset + (UInt64)(SizeofFileCacheEntryT * entryIndex));

            stream_writeData(fileCache.StreamFile2, fileCache.FileTableEntries, fileCache.FileTableEntryCount);
            LeaveCriticalSection();
        }