Beispiel #1
0
        /// <summary>
        /// Recursivly adds the specified GGPK DirectoryTree to the TreeListView
        /// </summary>
        /// <param name="directoryTreeNode">Node to add to tree</param>
        /// <param name="parentControl">TreeViewItem to add children to</param>
        private void AddDirectoryTreeToControl(DirectoryTreeNode directoryTreeNode, TreeViewItem parentControl)
        {
            TreeViewItem rootItem = new TreeViewItem();
            rootItem.Header = directoryTreeNode;
            if ((directoryTreeNode.ToString() == "ROOT") || (directoryTreeNode.ToString() == "")) rootItem.IsExpanded = true;

            if (parentControl == null)
            {
                treeView1.Items.Add(rootItem);
            }
            else
            {
                parentControl.Items.Add(rootItem);
            }

            directoryTreeNode.Children.Sort();
            foreach (var item in directoryTreeNode.Children)
            {
                AddDirectoryTreeToControl(item, rootItem);
            }

            directoryTreeNode.Files.Sort();
            foreach (var item in directoryTreeNode.Files)
            {
                rootItem.Items.Add(item);
            }
        }
        /// <summary>
        /// Builds a directory tree by traversing the list of record headers found in the pack file
        /// </summary>
        /// <param name="recordOffsets">Map of record offsets and headers to create directory tree from</param>
        /// <returns>Root node of directory tree</returns>
        internal static DirectoryTreeNode BuildDirectoryTree(Dictionary <long, BaseRecord> recordOffsets)
        {
            // This offset is a directory, add it as a child of root and process all of it's entries
            GGPKRecord currentDirectory = recordOffsets[0] as GGPKRecord;

            DirectoryTreeNode root = new DirectoryTreeNode()
            {
                Children = new List <DirectoryTreeNode>(),
                Files    = new List <FileRecord>(),
                Name     = "",
                Parent   = null,
                Record   = null
            };

            // First level only contains a empty string name directory record and a free record
            if (currentDirectory == null)
            {
                return(root);
            }
            foreach (var item in from Offset in currentDirectory.RecordOffsets
                     where recordOffsets.ContainsKey(Offset)
                     where recordOffsets[Offset] is DirectoryRecord
                     select recordOffsets[Offset] as DirectoryRecord
                     into firstDirectory
                     from item in firstDirectory.Entries
                     select item)
            {
                BuildDirectoryTree(item, root, recordOffsets);
            }
            return(root);
        }
Beispiel #3
0
        /// <summary>
        /// Gets the absolute directory of this node
        /// </summary>
        /// <returns>Absolute directory of this node</returns>
        public string GetDirectoryPath()
        {
            if (directoryPath != null)
            {
                return(directoryPath);
            }

            Stack <string> pathQueue = new Stack <string>();
            StringBuilder  sb        = new StringBuilder();

            // Traverse the directory tree until we hit the root node, pushing all
            //  encountered directory names onto the stack
            DirectoryTreeNode iter = this;

            while (iter != null && iter.Name.Length > 0)
            {
                pathQueue.Push(iter.Name);
                iter = iter.Parent;
            }

            foreach (var item in pathQueue)
            {
                sb.Append(item + Path.DirectorySeparatorChar);
            }

            directoryPath = sb.ToString();
            return(directoryPath);
        }
 private static void BuildDirectoryTree(long fileOffset, DirectoryTreeNode root, Dictionary <long, BaseRecord> recordOffsets)
 {
     if (!recordOffsets.ContainsKey(fileOffset))
     {
         return;
     }
     if (recordOffsets[fileOffset] is DirectoryRecord)
     {
         DirectoryRecord   directoryRecord   = recordOffsets[fileOffset] as DirectoryRecord;
         DirectoryTreeNode directoryTreeNode = new DirectoryTreeNode
         {
             Name     = directoryRecord.Name,
             Parent   = root,
             Children = new List <DirectoryTreeNode>(),
             Files    = new List <FileRecord>(),
             Record   = directoryRecord
         };
         root.Children.Add(directoryTreeNode);
         DirectoryRecord.DirectoryEntry[] entries = directoryRecord.Entries;
         for (int i = 0; i < entries.Length; i++)
         {
             DirectoryRecord.DirectoryEntry directoryEntry = entries[i];
             DirectoryTreeMaker.BuildDirectoryTree(directoryEntry.Offset, directoryTreeNode, recordOffsets);
         }
         return;
     }
     if (recordOffsets[fileOffset] is FileRecord)
     {
         FileRecord fileRecord = recordOffsets[fileOffset] as FileRecord;
         fileRecord.ContainingDirectory = root;
         root.Files.Add(fileRecord);
     }
 }
Beispiel #5
0
        /// <summary>
        /// Builds a directory tree by traversing the list of record headers found in the pack file
        /// </summary>
        /// <returns>Root node of directory tree</returns>
        private DirectoryTreeNode BuildDirectoryTree()
        {
            var ggpkRecord = RecordOffsets[0] as GgpkRecord;
            if (ggpkRecord == null)
                throw new Exception("First record isn't GGPK record");

            // First level only contains a empty string name directory record and a free record
            var rootDirectoryOffset = ggpkRecord.RecordOffsets
                .Where(RecordOffsets.ContainsKey).FirstOrDefault(o => RecordOffsets[o] is DirectoryRecord);
            if (rootDirectoryOffset == 0) // default value
                throw new Exception("Couldn't find root directory offset");

            var firstDirectory = RecordOffsets[rootDirectoryOffset] as DirectoryRecord;
            if (firstDirectory == null)
                throw new Exception("Couldn't find root directory record");

            var root = new DirectoryTreeNode
            {
                Children = new List<DirectoryTreeNode>(),
                Files = new List<FileRecord>(),
                Name = "ROOT",
                Parent = null,
                Record = firstDirectory,
            };

            // start building files tree
            foreach (var item in firstDirectory.Entries)
            {
                BuildDirectoryTree(item, root);
            }
            return root;
        }
Beispiel #6
0
 public void DeleteDirectoryRecord(DirectoryTreeNode dir)
 {
     var parent = dir.Parent;
     if (parent == null) // root directory
         return;
     parent.RemoveDirectory(dir);
 }
 /// <summary>
 /// Creates a directory tree using the parsed record headers and offsets
 /// </summary>
 /// <param name="output">Output function</param>
 private void CreateDirectoryTree(Action <string> output)
 {
     DirectoryRoot = BuildDirectoryTree();
     output(String.Format("Found {0} directories and {1} files", _directories.Count, _files.Count) + Environment.NewLine);
     FreeRoot = BuildFreeList();
     output(String.Format("Found {0} FREE records", _freeRecords.Count) + Environment.NewLine);
 }
        /// <summary>
        /// Builds a directory tree by traversing the list of record headers found in the pack file
        /// </summary>
        /// <param name="recordOffsets">Map of record offsets and headers to create directory tree from</param>
        /// <returns>Root node of directory tree</returns>
        internal static DirectoryTreeNode BuildDirectoryTree(Dictionary<long, BaseRecord> recordOffsets)
        {
            // This offset is a directory, add it as a child of root and process all of it's entries
            GGPKRecord currentDirectory = recordOffsets[0] as GGPKRecord;

            DirectoryTreeNode root = new DirectoryTreeNode()
            {
                Children = new List<DirectoryTreeNode>(),
                Files = new List<FileRecord>(),
                Name = "",
                Parent = null,
                Record = null,
            };

            // First level only contains a empty string name directory record and a free record
            foreach (var Offset in currentDirectory.RecordOffsets)
            {
                if (!recordOffsets.ContainsKey(Offset))
                {
                    continue;
                }

                if (recordOffsets[Offset] is DirectoryRecord)
                {
                    DirectoryRecord firstDirectory = recordOffsets[Offset] as DirectoryRecord;

                    foreach (var item in firstDirectory.Entries)
                    {
                        BuildDirectoryTree(item, root, recordOffsets);
                    }
                }
            }

            return root;
        }
        /// <summary>
        /// Recursivly creates a directory tree by traversing PDIR records. Adds FILE records to the current directory
        /// tree node. Recursivly traverses PDIR records and adds them to the current directory tree node's children.
        /// </summary>
        /// <param name="directoryEntry">Directory Entry</param>
        /// <param name="root">Parent node</param>
        private void BuildDirectoryTree(DirectoryRecord.DirectoryEntry directoryEntry, DirectoryTreeNode root)
        {
            if (!RecordOffsets.ContainsKey(directoryEntry.Offset))
            {
                return; // TODO throw error
            }
            if (RecordOffsets[directoryEntry.Offset] is DirectoryRecord)
            {
                // This offset is a directory, add it as a child of root and process all of it's entries
                var currentDirectory = RecordOffsets[directoryEntry.Offset] as DirectoryRecord;
                _directories.Add(currentDirectory);
                var child = new DirectoryTreeNode
                {
                    Name     = currentDirectory.Name,
                    Parent   = root,
                    Children = new List <DirectoryTreeNode>(),
                    Files    = new List <FileRecord>(),
                    Record   = currentDirectory,
                };

                root.Children.Add(child);

                foreach (var entry in currentDirectory.Entries)
                {
                    BuildDirectoryTree(entry, child);
                }
            }
            else if (RecordOffsets[directoryEntry.Offset] is FileRecord)
            {
                var currentFile = RecordOffsets[directoryEntry.Offset] as FileRecord;
                _files.Add(currentFile);
                currentFile.ContainingDirectory = root;
                root.Files.Add(currentFile);
            }
        }
Beispiel #10
0
 /// <summary>
 /// Creates a directory tree using the parsed record headers and offsets
 /// </summary>
 /// <param name="output">Output function</param>
 private void CreateDirectoryTree(Action <string> output)
 {
     if (output == null)
     {
         throw new ArgumentNullException(nameof(output));
     }
     DirectoryRoot = DirectoryTreeMaker.BuildDirectoryTree(RecordOffsets);
     FreeRoot      = FreeListMaker.BuildFreeList(RecordOffsets);
 }
Beispiel #11
0
        public void RemoveDirectory(DirectoryTreeNode dir)
        {
            if (!Children.Contains(dir))
            {
                throw new Exception("Tried to removed directory than not belong to this directory: " + Name);
            }

            // remove from DirectoryTreeNode
            Children.Remove(dir);

            // remove from DirectoryRecord
            var entry = Record.Entries.FirstOrDefault(n => n.Offset == dir.Record.RecordBegin);

            Record.Entries.Remove(entry);
        }
        /// <summary>
        /// Traverses a directory tree in PostOrder (Traverse children, then preform directory action) and preforms actions on the files and directories
        /// </summary>
        /// <param name="root">Root of directory tree</param>
        /// <param name="directoryAction">Action to preform on each directory</param>
        /// <param name="fileAction">Action to preform on each file</param>
        public static void TraverseTreePostorder(DirectoryTreeNode root, Action <DirectoryTreeNode> directoryAction, Action <FileRecord> fileAction)
        {
            foreach (var childDirectory in root.Children)
            {
                TraverseTreePostorder(childDirectory, directoryAction, fileAction);
                directoryAction?.Invoke(childDirectory);
            }

            if (fileAction != null)
            {
                foreach (var file in root.Files)
                {
                    fileAction(file);
                }
            }
        }
Beispiel #13
0
 public static void TraverseTreePostorder(DirectoryTreeNode root, Action <DirectoryTreeNode> directoryAction, Action <FileRecord> fileAction)
 {
     foreach (DirectoryTreeNode current in root.Children)
     {
         DirectoryTreeNode.TraverseTreePostorder(current, directoryAction, fileAction);
         if (directoryAction != null)
         {
             directoryAction(current);
         }
     }
     if (fileAction != null)
     {
         foreach (FileRecord current2 in root.Files)
         {
             fileAction(current2);
         }
     }
 }
Beispiel #14
0
        /// <summary>
        /// Traverses a directory tree in PostOrder (Preform directory action, then traverse children) and preforms actions on the files and directories
        /// </summary>
        /// <param name="root">Root of directory tree</param>
        /// <param name="directoryAction">Action to preform on each directory</param>
        /// <param name="fileAction">Action to preform on each file</param>
        public static void TraverseTreePreorder(DirectoryTreeNode root, Action<DirectoryTreeNode> directoryAction, Action<FileRecord> fileAction)
        {
            foreach (var childDirectory in root.Children)
            {
                if (directoryAction != null)
                {
                    directoryAction(childDirectory);
                }
                TraverseTreePreorder(childDirectory, directoryAction, fileAction);
            }

            if (fileAction != null)
            {
                foreach (var file in root.Files)
                {
                    fileAction(file);
                }
            }
        }
Beispiel #15
0
        internal static DirectoryTreeNode BuildDirectoryTree(Dictionary <long, BaseRecord> recordOffsets)
        {
            GGPKRecord        gGPKRecord        = recordOffsets[0L] as GGPKRecord;
            DirectoryTreeNode directoryTreeNode = new DirectoryTreeNode
            {
                Children = new List <DirectoryTreeNode>(),
                Files    = new List <FileRecord>(),
                Name     = "ROOT",
                Parent   = null,
                Record   = null
            };

            long[] recordOffsets2 = gGPKRecord.RecordOffsets;
            for (int i = 0; i < recordOffsets2.Length; i++)
            {
                long fileOffset = recordOffsets2[i];
                DirectoryTreeMaker.BuildDirectoryTree(fileOffset, directoryTreeNode, recordOffsets);
            }
            return(directoryTreeNode);
        }
        /// <summary>
        /// Recursivly creates a directory tree by traversing PDIR records. Adds FILE records to the current directory
        /// tree node. Recursivly traverses PDIR records and adds them to the current directory tree node's children.
        /// </summary>
        /// <param name="directoryEntry">Directory Entry</param>
        /// <param name="root">Parent node</param>
        /// <param name="recordOffsets">Map of record offsets and headers to create directory tree from</param>
        private static void BuildDirectoryTree(DirectoryRecord.DirectoryEntry directoryEntry, DirectoryTreeNode root, IReadOnlyDictionary <long, BaseRecord> recordOffsets)
        {
            if (!recordOffsets.ContainsKey(directoryEntry.Offset))
            {
                return;
            }

            var record = recordOffsets[directoryEntry.Offset] as DirectoryRecord;

            if (record != null)
            {
                // This offset is a directory, add it as a child of root and process all of it's entries
                DirectoryRecord   currentDirectory = record;
                DirectoryTreeNode child            = new DirectoryTreeNode
                {
                    Name     = currentDirectory.Name,
                    Parent   = root,
                    Children = new List <DirectoryTreeNode>(),
                    Files    = new List <FileRecord>(),
                    Record   = currentDirectory,
                };

                root.Children.Add(child);

                foreach (var entry in currentDirectory.Entries)
                {
                    BuildDirectoryTree(entry, child, recordOffsets);
                }
            }
            else
            {
                var file = recordOffsets[directoryEntry.Offset] as FileRecord;
                if (file == null)
                {
                    return;
                }
                FileRecord currentFile = file;
                currentFile.ContainingDirectory = root;
                root.Files.Add(currentFile);
            }
        }
Beispiel #17
0
        public string GetDirectoryPath()
        {
            if (this.directoryPath != null)
            {
                return(this.directoryPath);
            }
            Stack <string>    stack             = new Stack <string>();
            StringBuilder     stringBuilder     = new StringBuilder();
            DirectoryTreeNode directoryTreeNode = this.ContainingDirectory;

            while (directoryTreeNode != null && directoryTreeNode.Name.Length > 0)
            {
                stack.Push(directoryTreeNode.Name);
                directoryTreeNode = directoryTreeNode.Parent;
            }
            foreach (string current in stack)
            {
                stringBuilder.Append(current + Path.DirectorySeparatorChar);
            }
            this.directoryPath = stringBuilder.ToString();
            return(this.directoryPath);
        }
Beispiel #18
0
        /// <summary>
        /// Traverses a directory tree in PostOrder (Preform directory action, then traverse children)
        /// and preforms actions on the files and directories
        /// </summary>
        /// <param name="root">Root of directory tree</param>
        /// <param name="directoryAction">Action to preform on each directory</param>
        /// <param name="fileAction">Action to preform on each file</param>
        public static void TraverseTreePreorder(
            DirectoryTreeNode root,
            Action <DirectoryTreeNode> directoryAction,
            Action <FileRecord> fileAction)
        {
            foreach (var childDirectory in root.Children)
            {
                if (directoryAction != null)
                {
                    directoryAction(childDirectory);
                }
                TraverseTreePreorder(childDirectory, directoryAction, fileAction);
            }

            if (fileAction == null)
            {
                return;
            }
            foreach (var file in root.Files)
            {
                fileAction(file);
            }
        }
Beispiel #19
0
        /// <summary>
        /// Recursivly creates a directory tree by traversing PDIR records. Adds FILE records to the current directory
        /// tree node. Recursivly traverses PDIR records and adds them to the current directory tree node's children.
        /// </summary>
        /// <param name="directoryEntry">Directory Entry</param>
        /// <param name="root">Parent node</param>
        /// <param name="recordOffsets">Map of record offsets and headers to create directory tree from</param>
        private static void BuildDirectoryTree(DirectoryRecord.DirectoryEntry directoryEntry, DirectoryTreeNode root, Dictionary <long, BaseRecord> recordOffsets)
        {
            if (!recordOffsets.ContainsKey(directoryEntry.Offset))
            {
                return;
            }

            if (recordOffsets[directoryEntry.Offset] is DirectoryRecord)
            {
                // This offset is a directory, add it as a child of root and process all of it's entries
                DirectoryRecord   currentDirectory = recordOffsets[directoryEntry.Offset] as DirectoryRecord;
                DirectoryTreeNode child            = new DirectoryTreeNode()
                {
                    Name     = currentDirectory.Name,
                    Parent   = root,
                    Children = new List <DirectoryTreeNode>(),
                    Files    = new List <FileRecord>(),
                    Record   = currentDirectory,
                };

                root.Children.Add(child);

                foreach (var entry in currentDirectory.Entries)
                {
                    BuildDirectoryTree(entry, child, recordOffsets);
                }
            }
            else if (recordOffsets[directoryEntry.Offset] is FileRecord)
            {
                FileRecord currentFile = recordOffsets[directoryEntry.Offset] as FileRecord;
                // Skip empty .dat Files under Data/
                //if (root.Name.Equals("Data") && currentFile.DataLength == 12)
                //	return;
                currentFile.ContainingDirectory = root;
                root.Files.Add(currentFile);
            }
        }
        /// <summary>
        /// Recursivly creates a directory tree by traversing PDIR records. Adds FILE records to the current directory
        /// tree node. Recursivly traverses PDIR records and adds them to the current directory tree node's children.
        /// </summary>
        /// <param name="directoryEntry">Directory Entry</param>
        /// <param name="root">Parent node</param>
        /// <param name="recordOffsets">Map of record offsets and headers to create directory tree from</param>
        private static void BuildDirectoryTree(DirectoryRecord.DirectoryEntry directoryEntry, DirectoryTreeNode root, Dictionary<long, BaseRecord> recordOffsets)
        {
            if (!recordOffsets.ContainsKey(directoryEntry.Offset))
            {
                return;
            }

            if (recordOffsets[directoryEntry.Offset] is DirectoryRecord)
            {
                // This offset is a directory, add it as a child of root and process all of it's entries
                DirectoryRecord currentDirectory = recordOffsets[directoryEntry.Offset] as DirectoryRecord;
                DirectoryTreeNode child = new DirectoryTreeNode()
                {
                    Name = currentDirectory.Name,
                    Parent = root,
                    Children = new List<DirectoryTreeNode>(),
                    Files = new List<FileRecord>(),
                    Record = currentDirectory,
                };

                root.Children.Add(child);

                foreach (var entry in currentDirectory.Entries)
                {
                    BuildDirectoryTree(entry, child, recordOffsets);
                }
            }
            else if (recordOffsets[directoryEntry.Offset] is FileRecord)
            {
                FileRecord currentFile = recordOffsets[directoryEntry.Offset] as FileRecord;
                // Skip empty .dat Files under Data/
                //if (root.Name.Equals("Data") && currentFile.DataLength == 12)
                //	return;
                currentFile.ContainingDirectory = root;
                root.Files.Add(currentFile);
            }
        }
Beispiel #21
0
 /// <summary>
 /// Creates a directory tree using the parsed record headers and offsets
 /// </summary>
 /// <param name="output">Output function</param>
 private void CreateDirectoryTree(Action<string> output)
 {
     DirectoryRoot = DirectoryTreeMaker.BuildDirectoryTree(RecordOffsets);
     FreeRoot = FreeListMaker.BuildFreeList(RecordOffsets);
 }
        public void Save(string pathToGgpkNew, Action <string> output)
        {
            if (output != null)
            {
                output("Saving GGPK..." + Environment.NewLine);
            }

            FileStream readStream;
            FileStream writeStream;

            using (readStream = File.OpenRead(_pathToGppk))
                using (writeStream = File.OpenWrite(pathToGgpkNew))
                {
                    var reader = new BinaryReader(readStream);
                    var writer = new BinaryWriter(writeStream);

                    var ggpkRecord = RecordOffsets[0] as GgpkRecord;
                    if (ggpkRecord == null)
                    {
                        throw new Exception("First record isn't GGPK record");
                    }

                    // Skip GGPK record for now
                    writer.Seek((int)ggpkRecord.Length, SeekOrigin.Begin);

                    // recursively write files and folders records
                    var changedOffsets          = new Dictionary <long, long>();
                    var previousPercentComplete = 0.0;
                    var fileCopied = 0.0;
                    DirectoryTreeNode.TraverseTreePostorder(
                        DirectoryRoot,
                        dir => dir.Record.Write(writer, changedOffsets),
                        file =>
                    {
                        var data = file.ReadFileContent(reader);
                        file.Write(writer, changedOffsets);
                        writer.Write(data);

                        fileCopied++;
                        var percentComplete = fileCopied / _files.Count;
                        if (!(percentComplete - previousPercentComplete >= 0.05f))
                        {
                            return;
                        }

                        if (output != null)
                        {
                            output(String.Format("  {0:00.00}%", 100.0 * percentComplete));
                        }
                        previousPercentComplete = percentComplete;
                    });
                    if (output != null)
                    {
                        output("  100%");
                    }

                    // write root directory
                    var rootDirectoryOffset = writer.BaseStream.Position;
                    DirectoryRoot.Record.Write(writer, changedOffsets);

                    // write single Free record
                    var firstFreeRecordOffset = writer.BaseStream.Position;
                    var freeRecord            = new FreeRecord(16, firstFreeRecordOffset, 0);
                    freeRecord.Write(writer, null);

                    // write GGPK record
                    writer.Seek(0, SeekOrigin.Begin);
                    var ggpkRecordNew = new GgpkRecord(ggpkRecord.Length);
                    ggpkRecordNew.RecordOffsets[0] = rootDirectoryOffset;
                    ggpkRecordNew.RecordOffsets[1] = firstFreeRecordOffset;
                    ggpkRecordNew.Write(writer, changedOffsets);
                    if (output != null)
                    {
                        output("Finished !!!");
                    }
                }
        }
Beispiel #23
0
        /// <summary>
        /// Exports entire DirectoryTreeNode to disk, preserving directory structure
        /// </summary>
        /// <param name="selectedDirectoryNode">Node to export to disk</param>
        private void ExportAllItemsInDirectory(DirectoryTreeNode selectedDirectoryNode)
        {
            List<FileRecord> recordsToExport = new List<FileRecord>();

            Action<FileRecord> fileAction = new Action<FileRecord>(recordsToExport.Add);

            DirectoryTreeNode.TraverseTreePreorder(selectedDirectoryNode, null, fileAction);

            try
            {
                SaveFileDialog saveFileDialog = new SaveFileDialog();
                saveFileDialog.FileName = Settings.Strings["ExportAllItemsInDirectory_Default_FileName"];
                if (saveFileDialog.ShowDialog() == true)
                {
                    string exportDirectory = Path.GetDirectoryName(saveFileDialog.FileName) + Path.DirectorySeparatorChar;
                    foreach (var item in recordsToExport)
                    {
                        item.ExtractFileWithDirectoryStructure(ggpkPath, exportDirectory);
                    }
                    MessageBox.Show(string.Format(Settings.Strings["ExportAllItemsInDirectory_Successful"], recordsToExport.Count), Settings.Strings["ExportAllItemsInDirectory_Successful_Caption"], MessageBoxButton.OK, MessageBoxImage.Information);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(string.Format(Settings.Strings["ExportAllItemsInDirectory_Failed"], ex.Message), Settings.Strings["Error_Caption"], MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }
Beispiel #24
0
 private void CreateDirectoryTree(Action <string> output)
 {
     this.DirectoryRoot = DirectoryTreeMaker.BuildDirectoryTree(this.RecordOffsets);
     this.FreeRoot      = FreeListMaker.BuildFreeList(this.RecordOffsets);
 }