private void AddEntryToDictionary( EdataDictionaryPathEntry entry, ContentPathSplitInfo entryPathSplitInfo, EdataDictionaryRootEntry dictionaryRoot) { if (entryPathSplitInfo.SplitIndex == 0) { dictionaryRoot.AddFollowingEntry(entry); //entry.PrecedingEntry = dictionaryRoot; } else { var precedingPath = entryPathSplitInfo.GetPathToSplitIndex(); EdataDictionaryPathEntry precedingPathEntry = dictionaryRoot.SelectEntryByPath(precedingPath); var pp = precedingPathEntry as EdataDictionaryDirEntry; if (precedingPathEntry != null) { pp.AddFollowingEntry(entry); //entry.PrecedingEntry = pp; } else { throw new Exception(String.Format( "Cannot find a following precedding entry: {0}", precedingPath)); } } }
/// <summary> /// /// </summary> /// <param name="source"></param> /// <param name="dictionaryRoot"></param> /// <param name="contentFilesSectionOffset"></param> /// <returns></returns> protected virtual IEnumerable <EdataContentFile> TranslateDictionaryEntriesToContentFiles( Stream source, uint contentFilesSectionOffset, EdataDictionaryRootEntry dictionaryRoot) { var contentFiles = new List <EdataContentFile>(); var fileEntries = dictionaryRoot.SelectEntriesOfType <EdataDictionaryFileEntry>(); foreach (var entry in fileEntries) { var newCotnetFile = new EdataContentFile(); newCotnetFile.Offset = entry.FileOffset; newCotnetFile.TotalOffset = entry.FileOffset + contentFilesSectionOffset; newCotnetFile.Length = entry.FileLength; newCotnetFile.Checksum = entry.FileChecksum; newCotnetFile.Path = entry.FullPath; //To można by stąd wydzielić ResolveContentFileType(source, newCotnetFile, contentFilesSectionOffset); contentFiles.Add(newCotnetFile); } return(contentFiles); }
/// <summary> /// Creates a hierarchy of the dictionary content entries based on the provided collection of content files. /// </summary> /// <param name="contentFiles"></param> /// <returns></returns> /// <remarks>This metohd requires that there are no two content files with the same paths.</remarks> protected virtual EdataDictionaryRootEntry CreateDictionaryEntries( IEnumerable <EdataContentFile> contentFiles) { List <ContentPathSplitInfo> pathsToSplit = contentFiles .OrderBy(file => file.Path, new EdataDictStringComparer()) .Select(file => new ContentPathSplitInfo() { Path = file.Path }) .ToList(); var dictionaryRoot = new EdataDictionaryRootEntry(); //Wide match can't be picked over a long match. while (pathsToSplit.Count > 0) { List <ContentPathSplitInfo> pathsToCompare = TakePathsToCompare(pathsToSplit); if (pathsToCompare.Count == 1) { var newEntry = new EdataDictionaryFileEntry(pathsToCompare[0].GetPathFromSplitIndex()); AddEntryToDictionary(newEntry, pathsToCompare[0], dictionaryRoot); pathsToSplit.Remove(pathsToCompare[0]); } else if (pathsToCompare.Count > 1) { int matchIndex = 0; while (true) //Zastanowić sie co z warunkiem kończoaczym, czy to break moze nie zaistnieć. { bool allPathsMatched = CheckIfAllPathsMatchAtIndex(pathsToCompare, matchIndex);; if (allPathsMatched) { matchIndex++; } else { var newEntry = new EdataDictionaryDirEntry(pathsToCompare[0].GetPathFromSplitIndex(length: matchIndex)); AddEntryToDictionary(newEntry, pathsToCompare[0], dictionaryRoot); //czy tu powinno być += czy tylko przypisanie? pathsToCompare.ForEach(x => x.SplitIndex += matchIndex); break; } } } } return(dictionaryRoot); }
/// <summary> /// Assigns a dictionary data of the content files to the corresponding dictionary entries. /// </summary> /// <param name="contentFiles"></param> /// <param name="dictionaryRoot"></param> protected virtual void AssignContentFilesInfoToDictEntries( IEnumerable <EdataContentFile> contentFiles, EdataDictionaryRootEntry dictionaryRoot) { foreach (var file in contentFiles) { var matchingEntry = dictionaryRoot.SelectEntryByPath(file.Path); EdataDictionaryFileEntry fileEntry = matchingEntry as EdataDictionaryFileEntry; if (fileEntry != null) { fileEntry.FileOffset = file.Offset; fileEntry.FileLength = file.Length; fileEntry.FileChecksum = file.Checksum; } } }
protected virtual uint ComputeDictionaryLength(EdataDictionaryRootEntry dictionaryRoot) { uint dictHeaderSize = 10; uint totalSize = dictHeaderSize; var entriesQueue = new Queue <EdataDictionaryPathEntry>(); entriesQueue.Enqueue(dictionaryRoot); while (entriesQueue.Count > 0) { var entry = entriesQueue.Dequeue(); totalSize += (uint)entry.Length; foreach (var subEntry in entry.FollowingEntries) { entriesQueue.Enqueue(subEntry); } } return(totalSize); }
/// <summary> /// /// </summary> /// <param name="target"></param> /// <param name="dictionaryRoot"></param> /// <param name="dictOffset"></param> /// <returns></returns> protected virtual DictionaryWriteInfo WriteDictionary( Stream target, EdataDictionaryRootEntry dictionaryRoot, uint dictOffset) { var info = new DictionaryWriteInfo(); target.Seek(dictOffset, SeekOrigin.Begin); //Need to use depth-traversal var entriesStack = new Stack <EdataDictionaryPathEntry>(); entriesStack.Push(dictionaryRoot); while (entriesStack.Count > 0) { var entry = entriesStack.Pop(); var entryBuffer = entry.ToBytes(); target.Write(entryBuffer, 0, entryBuffer.Length); info.Length += (uint)entryBuffer.Length; foreach (var subEntry in entry.FollowingEntries.Reverse()) { entriesStack.Push(subEntry); } } var dictBuff = new byte[info.Length]; target.Seek(dictOffset, SeekOrigin.Begin); target.Read(dictBuff, 0, dictBuff.Length); info.Checksum = MD5.Create().ComputeHash(dictBuff); return(info); }
/// <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); }