public void ExtractFiles(string tableOfContentsName)
        {
            string superBundlePath = Path.ChangeExtension(tableOfContentsName, "sb");
            string directory       = Path.GetDirectoryName(tableOfContentsName) + @"\" + Path.GetFileNameWithoutExtension(tableOfContentsName);

            // extract raw files from superbundles
            if (!myTableOfContents.Payload.Properties.ContainsKey("cas"))
            {
                foreach (var collection in myTableOfContents.Payload.BundleCollections)
                {
                    string collectionDirectory = directory + @"\" + collection.Name + @"\";
                    foreach (var item in collection.Bundles)
                    {
                        if (item.Properties.ContainsKey("offset") && item.Properties.ContainsKey("size"))
                        {
                            Directory.CreateDirectory(collectionDirectory);

                            using (FileStream inputFileStream = File.Open(superBundlePath, FileMode.Open))
                            {
                                BinaryReader reader = new BinaryReader(inputFileStream);

                                long a = (long)item.Properties["offset"].Value;
                                reader.BaseStream.Seek((int)a, SeekOrigin.Begin);

                                string finalName = collectionDirectory + Helpers.ByteArrayToString((byte[])item.Properties["id"].Value);

                                ChunkHandler.Dechunk(finalName, reader, (int)item.Properties["size"].Value);
                            }
                        }
                    }
                }
            }
            // extract from a catalogue
            else
            {
                foreach (CatalogueEntry entry in BuildFileListInCatalogues(myTableOfContents.Payload.BundleCollections))
                {
                    string compoundName = Path.GetDirectoryName(entry.Parent.Path) + @"\cas_" + entry.Archive.ToString("00") + ".cas";
                    using (FileStream inputFileStream = File.Open(compoundName, FileMode.Open))
                    {
                        BinaryReader reader = new BinaryReader(inputFileStream);
                        reader.BaseStream.Seek(entry.Offset, SeekOrigin.Begin);

                        string finalName = directory + @"\" + entry.ResolvedName.Replace(":", "_Dq_");
                        Directory.CreateDirectory(finalName.Substring(0, finalName.LastIndexOf('\\')));

                        ChunkHandler.Dechunk(finalName, reader, entry.Size);
                    }
                }
            }
        }
        public void ImportFiles(string tableOfContentsName)
        {
            Dictionary <string, string> filesToOverwriteMap = new Dictionary <string, string>();

            string directory = Path.GetDirectoryName(tableOfContentsName) + @"\" + Path.GetFileNameWithoutExtension(tableOfContentsName);
            Random generator = new Random();

            ResolveNewFiles(tableOfContentsName, directory);

            bool isIndirect = myTableOfContents.Payload.BundleCollections.Where(bundleList => bundleList.Bundles.Count() > 0).First().Bundles.First().Indirection != null;

            List <bool> isIndirectionConsistentAndMatching = myTableOfContents.Payload.BundleCollections.Select(bundleList => bundleList.Bundles.All(bundle => (bundle.Indirection != null) == isIndirect)).Distinct().ToList();
            bool        isIndirectOrMixed = false;

            if (isIndirectionConsistentAndMatching.Count() != 1 || !isIndirectionConsistentAndMatching.First())
            {
                isIndirectOrMixed = true;
            }

            string originalSuperBundlePath = Path.ChangeExtension(tableOfContentsName, "sb");
            string newSuperBundlePath      = Path.ChangeExtension(tableOfContentsName, "sb_" + generator.Next().ToString());

            // table of contents pointing directly to raw files in superbundles
            if (!myTableOfContents.Payload.Properties.ContainsKey("cas"))
            {
                filesToOverwriteMap.Add(originalSuperBundlePath, newSuperBundlePath);

                // write superbundle
                var allBundles = myTableOfContents.Payload.BundleCollections.SelectMany(bundleList => bundleList.Bundles).OrderBy(superBundle => (long)superBundle.Properties["offset"].Value);

                using (BinaryReader originalReader = new BinaryReader(File.Open(originalSuperBundlePath, FileMode.Open)))
                {
                    using (BundleBinaryWriter writer = new BundleBinaryWriter(File.Open(newSuperBundlePath, FileMode.Create)))
                    {
                        foreach (SuperBundle superBundle in allBundles)
                        {
                            Int64 initialFilePosition = writer.BaseStream.Position;

                            if (superBundle.Changed == null)
                            {
                                long offset = (long)superBundle.Properties["offset"].Value;
                                originalReader.BaseStream.Seek(offset, SeekOrigin.Begin);
                                writer.Write(originalReader.ReadBytes((int)superBundle.Properties["size"].Value));
                            }
                            else
                            {
                                superBundle.Properties["size"].Value = ChunkHandler.Chunk(writer, superBundle);
                            }
                            superBundle.Properties["offset"].Value = initialFilePosition;
                        }
                    }
                }

                // write table of contents
                string newTableOfContentsName = Path.ChangeExtension(tableOfContentsName, @".toc_" + generator.Next().ToString());
                filesToOverwriteMap.Add(tableOfContentsName, newTableOfContentsName);

                using (BundleBinaryWriter writer = new BundleBinaryWriter(File.Open(newTableOfContentsName, FileMode.Create)))
                {
                    writer.Write(myTableOfContents.Header);
                    writer.Write(myTableOfContents.Payload);
                }
            }
            // table of contents pointing to raw files in catalogues
            else
            {
                IEnumerable <SuperBundle> modifiedBundles;

                if (isIndirectOrMixed)
                {
                    modifiedBundles = myTableOfContents.Payload.BundleCollections
                                      .SelectMany(bundleList => bundleList.Bundles
                                                  .Where(superBundles => superBundles.Indirection != null)
                                                  .SelectMany(superBundles => superBundles.Indirection.BundleCollections
                                                              .SelectMany(indirectBundleList => indirectBundleList.Bundles)))
                                      .Where(bundle => bundle.Changed != null);
                }
                else
                {
                    modifiedBundles = myTableOfContents.Payload.BundleCollections.SelectMany(bundleList => bundleList.Bundles).Where(bundle => bundle.Changed != null);
                }

                // write cas
                foreach (SuperBundle superBundle in modifiedBundles)
                {
                    CatalogueEntry catEntry = FindCorrespondingCatalogueEntry((byte[])superBundle.Properties["sha1"].Value);
                    catEntry.Changed = true;

                    string pathToNewCascade = Path.GetDirectoryName(catEntry.Parent.Path) + @"\\" + "cas_99.cas";
                    catEntry.Archive = 99;

                    using (BundleBinaryWriter writer = new BundleBinaryWriter(File.Open(pathToNewCascade, FileMode.Append)))
                    {
                        if (writer.BaseStream.Position == 0 && myTableOfContents.Header.Version == 0x03)
                        {
                            writer.Write(Catalogue.CasHeader);
                        }

                        catEntry.Offset = (int)writer.BaseStream.Position;
                        int fileSize = ChunkHandler.Chunk(writer, superBundle);
                        catEntry.Size = fileSize;

                        if (superBundle.Properties.ContainsKey("size"))
                        {
                            superBundle.Properties["size"].Value = (Int64)fileSize;
                        }
                        if (superBundle.Properties.ContainsKey("originalSize"))
                        {
                            superBundle.Properties["originalSize"].Value = (Int64) new FileInfo(superBundle.Changed).Length;
                        }
                    }
                }

                // write catalogue
                foreach (Catalogue catalogue in myCatalogues.Where(_ => _.Files.Values.Any(entry => entry.Changed)))
                {
                    // fix for duplicates
                    catalogue.NumberOfFiles = catalogue.Files.Count;

                    string newCataloguePath = catalogue.Path + "_tmp" + generator.Next().ToString();
                    filesToOverwriteMap.Add(catalogue.Path, newCataloguePath);

                    using (BundleBinaryWriter writer = new BundleBinaryWriter(File.Open(newCataloguePath, FileMode.Create)))
                    {
                        writer.Write(myTableOfContents.Header.Version, catalogue);
                    }
                }

                // write superbundle
                if (isIndirectOrMixed)
                {
                    filesToOverwriteMap.Add(originalSuperBundlePath, newSuperBundlePath);

                    // write table of contents
                    using (BundleBinaryWriter writer = new BundleBinaryWriter(File.Open(newSuperBundlePath, FileMode.Create)))
                    {
                        using (BinaryReader originalReader = new BinaryReader(File.Open(originalSuperBundlePath, FileMode.Open)))
                        {
                            originalReader.BaseStream.Seek(0, SeekOrigin.Begin);
                            writer.Write(originalReader.ReadBytes(16));
                        }

                        foreach (SuperBundle indirectSuperBundle in myTableOfContents.Payload.BundleCollections.SelectMany(_ => _.Bundles.Select(x => x.Indirection)))
                        {
                            writer.Write(indirectSuperBundle);
                        }
                        writer.Write((Int16)0);
                    }
                }
            }

            CleanupTemporaryFiles(filesToOverwriteMap);
        }