protected virtual IEnumerable <ProxyPathTableEntry> ReadPathTableEntries(Stream source, uint offset, uint length)
        {
            var entries = new List <ProxyPathTableEntry>();

            source.Seek(offset, SeekOrigin.Begin);

            uint sectionEnd = offset + length;

            while (source.Position < sectionEnd)
            {
                var path = MiscUtilities.ReadString(source, false);

                int skipSize = (int)ProxyPathTableEntry.EntryLength - 8 - path.Length;
                source.Seek(skipSize, SeekOrigin.Current);

                byte[] hash = new byte[8];
                source.Read(hash, 0, hash.Length);

                entries.Add(new ProxyPathTableEntry()
                {
                    Path = path,
                    Hash = hash,
                });
            }

            return(entries);
        }
        /// <remarks>
        /// Method based on enohka's code.
        /// See more at: http://github.com/enohka/moddingSuite
        /// </remarks>
        protected virtual void WriteDictionary(Stream target, EdataFile edataFile)
        {
            var sourceEdataHeader = edataFile.Header;
            var contentFilesDict  = edataFile
                                    .ContentFiles
                                    .OfType <EdataContentFile>()
                                    .ToDictionary(x => x.Id);

            target.Seek(sourceEdataHeader.DictOffset, SeekOrigin.Begin);
            long dictEnd = sourceEdataHeader.DictOffset + sourceEdataHeader.DictLength;
            uint id      = 0;

            //Odtworzenie słownika
            while (target.Position < dictEnd)
            {
                var buffer = new byte[4];
                target.Read(buffer, 0, 4);
                int fileGroupId = BitConverter.ToInt32(buffer, 0);

                if (fileGroupId == 0)
                {
                    EdataContentFile curFile = contentFilesDict[id];

                    // FileEntrySize
                    target.Seek(4, SeekOrigin.Current);

                    buffer = BitConverter.GetBytes(curFile.Offset);
                    target.Write(buffer, 0, buffer.Length);

                    buffer = BitConverter.GetBytes(curFile.Size);
                    target.Write(buffer, 0, buffer.Length);

                    byte[] checkSum = curFile.Checksum;
                    target.Write(checkSum, 0, checkSum.Length);

                    string name = MiscUtilities.ReadString(target);

                    if ((name.Length + 1) % 2 == 1)
                    {
                        target.Seek(1, SeekOrigin.Current);
                    }

                    id++;
                }
                else if (fileGroupId > 0)
                {
                    target.Seek(4, SeekOrigin.Current);
                    string name = MiscUtilities.ReadString(target);

                    if ((name.Length + 1) % 2 == 1)
                    {
                        target.Seek(1, SeekOrigin.Current);
                    }
                }
            }

            target.Seek(sourceEdataHeader.DictOffset, SeekOrigin.Begin);
            var dictBuffer = new byte[sourceEdataHeader.DictLength];

            target.Read(dictBuffer, 0, dictBuffer.Length);

            //Overwriting checksum
            byte[] dictCheckSum = MD5.Create().ComputeHash(dictBuffer);
            target.Seek(0x31, SeekOrigin.Begin);
            target.Write(dictCheckSum, 0, dictCheckSum.Length);
        }
        /// <summary>
        /// Reads Edata version 2 dictionary entries
        /// </summary>
        /// <param name="source"></param>
        /// <param name="header"></param>
        /// <param name="token"></param>
        /// <returns></returns>
        protected virtual EdataDictionaryRootEntry ReadDcitionaryEntries(
            Stream source,
            uint dictOffset,
            uint dictLength)
        {
            EdataDictionaryRootEntry dictRoot   = new EdataDictionaryRootEntry();
            EdataDictionaryDirEntry  workingDir = null;

            source.Seek(dictOffset + dictRoot.Length, SeekOrigin.Begin);

            long dictEnd = dictOffset + dictLength;

            while (source.Position < dictEnd)
            {
                var buffer = new byte[4];
                source.Read(buffer, 0, 4);
                int entrysFirstFour = BitConverter.ToInt32(buffer, 0);

                source.Read(buffer, 0, 4);
                int entrysSecondFour = BitConverter.ToInt32(buffer, 0);

                bool isFileEntry = (entrysFirstFour == 0);
                if (isFileEntry)
                {
                    int entryLength = entrysSecondFour;

                    //source.Read(buffer, 0, 4);
                    //int relevanceLength = BitConverter.ToInt32(buffer, 0);

                    buffer = new byte[8];
                    source.Read(buffer, 0, buffer.Length);
                    long offset = BitConverter.ToInt64(buffer, 0);

                    source.Read(buffer, 0, buffer.Length);
                    long length = BitConverter.ToInt64(buffer, 0);

                    var checksum = new byte[16];
                    source.Read(checksum, 0, checksum.Length);

                    String pathPart = MiscUtilities.ReadString(source);
                    if (pathPart.Length % 2 == 0)
                    {
                        source.Seek(1, SeekOrigin.Current);
                    }

                    var newFile = new EdataDictionaryFileEntry(pathPart, entryLength, offset, length, checksum);
                    if (workingDir != null)
                    {
                        workingDir.AddFollowingEntry(newFile);

                        //Usuwamy tylko jeśli pojawia się wpis pliku oznaczony jako kończący ścieżkę.
                        if (newFile.IsEndingEntry())
                        {
                            EdataDictionaryDirEntry previousEntry = null;
                            do
                            {
                                previousEntry = workingDir;
                                workingDir    = workingDir.PrecedingEntry as EdataDictionaryDirEntry;
                            }while (workingDir != null && previousEntry.IsEndingEntry());
                        }
                    }
                    else
                    {
                        dictRoot.AddFollowingEntry(newFile);
                    }
                }
                else //isDirEntry
                {
                    int entryLength     = entrysFirstFour;
                    int relevanceLength = entrysSecondFour;

                    //source.Read(buffer, 0, 4);
                    //int relevanceLength = BitConverter.ToInt32(buffer, 0);

                    String pathPart = MiscUtilities.ReadString(source);
                    if (pathPart.Length % 2 == 0)
                    {
                        source.Seek(1, SeekOrigin.Current);
                    }

                    var newDir = new EdataDictionaryDirEntry(pathPart, entryLength, relevanceLength);
                    if (workingDir != null)
                    {
                        workingDir.AddFollowingEntry(newDir);
                    }
                    else
                    {
                        dictRoot.AddFollowingEntry(newDir);
                    }
                    workingDir = newDir;
                }
            }

            return(dictRoot);
        }