Ejemplo n.º 1
0
 /// <summary>
 /// Adds a multiple files, located in <paramref name="innerFolder"/>, to <see cref="Mythic.Package.MythicPackageBlock.Files"/> table.
 /// </summary>
 /// <param name="fileNames">Array of file paths on HD.</param>
 /// <param name="innerFolder">Relative folder within KR (destination).</param>
 /// <param name="flag">Compression type.</param>
 public void AddFiles(string[] fileNames, string innerFolder, CompressionFlag flag)
 {
     foreach (string file in fileNames)
     {
         AddFile(file, innerFolder, flag);
     }
 }
        /// <summary>
        /// Initializes a new instance from existing Mythic package file.
        /// </summary>
        /// <param name="reader">Binary file (.uop source).</param>
        /// <param name="parent">Parent entity.</param>
        public MythicPackageFile(BinaryReader reader, MythicPackageBlock parent)
        {
            m_Parent = parent;

            m_DataBlockAddress = m_OldDataBlockAddress = reader.ReadInt64();
            m_DataBlockLength  = reader.ReadInt32();
            m_CompressedSize   = reader.ReadInt32();
            m_DecompressedSize = reader.ReadInt32();
            m_FileHash         = reader.ReadUInt64();

            if (m_FileHash != 0)
            {
                m_FileName = HashDictionary.Get(m_FileHash, true);
            }

            m_DataBlockHash = reader.ReadUInt32();

            short flag = reader.ReadInt16();

            switch (flag)
            {
            case 0x0: m_Compression = CompressionFlag.None; break;

            case 0x1: m_Compression = CompressionFlag.Zlib; break;

            default: throw new InvalidCompressionException(flag);
            }
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Adds all files within a certain folder to .uop package.
        /// </summary>
        /// <param name="folder">Folder, which contains files.</param>
        /// <param name="flag">Compression type.</param>
        public void AddFolder(string folder, CompressionFlag flag)
        {
            if (!Directory.Exists(folder))
            {
                throw new ArgumentException(String.Format("'{0}' is not a folder!", folder));
            }

            Stack <string> stack = new Stack <string>();

            stack.Push(folder);

            while (stack.Count > 0)
            {
                string f     = stack.Pop();
                string inner = f.Remove(0, folder.Length);

                foreach (string file in Directory.GetFiles(f))
                {
                    AddFile(file, inner, flag);
                }

                foreach (string newFolder in Directory.GetDirectories(f))
                {
                    stack.Push(newFolder);
                }
            }
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Adds a file, located in <paramref name="fileName"/>, to <see cref="Mythic.Package.MythicPackageBlock.Files"/> table.
        /// </summary>
        /// <param name="fileName">Path to a file on HD.</param>
        /// <param name="innerFolder">Relative folder within KR (destination).</param>
        /// <param name="flag">Compression type.</param>
        public void AddFile(string fileName, string innerFolder, CompressionFlag flag)
        {
            if (String.IsNullOrEmpty(fileName))
            {
                throw new ArgumentException("fileName");
            }

            MythicPackageBlock block;

            if (m_Blocks.Count > 0)
            {
                block = m_Blocks[m_Blocks.Count - 1];
            }
            else
            {
                block = NewBlock();
            }

            if (block.IsFull)
            {
                block = NewBlock();
            }

            block.AddFile(fileName, innerFolder, flag);
        }
        /// <summary>
        /// Updates <see cref="Mythic.Package.MythicPackageFile.DataBlockAddress"/> within .uop file,
        /// <see cref="Mythic.Package.MythicPackageFile.CompressedSize"/> and <see cref="Mythic.Package.MythicPackageFile.DecompressedSize"/>.
        /// </summary>
        /// <param name="pointer">Address of <see cref="Mythic.Package.MythicPackageFile.DataBlockAddress"/>.</param>
        public void UpdateOffsets(ref long pointer)
        {
            m_DataBlockAddress = pointer;
            m_DataBlockLength  = 0;            // Custom .uop files don't need data header.

            if (m_Added || m_Modified)
            {
                if (!File.Exists(m_SourceFileName))
                {
                    throw new FileNotFoundException();
                }

                FileInfo info = new FileInfo(m_SourceFileName);

                m_CompressedSize   = (int)info.Length;
                m_DecompressedSize = (int)info.Length;

                byte[] sourceBuffer;

                using (BinaryReader reader = new BinaryReader(info.OpenRead()))
                {
                    sourceBuffer = reader.ReadBytes(m_DecompressedSize);
                }

                if (sourceBuffer.Length < 4)
                {
                    m_Compression = CompressionFlag.None;
                }

                switch (m_Compression)
                {
                case CompressionFlag.Zlib:
                {
                    m_SourceBuffer = new byte[m_CompressedSize];
                    ZLibError error = Zlib.Compress(m_SourceBuffer, ref m_CompressedSize, sourceBuffer, m_DecompressedSize, ZLibQuality.Speed);

                    if (error != ZLibError.Okay)
                    {
                        throw new CompressionException(error);
                    }

                    break;
                }

                case CompressionFlag.None:
                {
                    m_SourceBuffer = sourceBuffer;
                    break;
                }
                }
            }
            else
            {
                m_SourceBuffer = null;
            }

            pointer += m_DataBlockLength + m_CompressedSize;
        }
Ejemplo n.º 6
0
 public SortedList<Interval, Block> ConvertArrayToIntervalTree(Block[] blocks, out float compressionRatio, CompressionFlag flag = CompressionFlag.None)
 {
     var scanDirection = ScanDirection.Xyz;
     CompressionMode compressionMode;
     if (flag == CompressionFlag.None)
     {
         float hilbertCompressionRatio;
         float linearCompressionRatio;
         EvaluateHilbertTree(blocks, out hilbertCompressionRatio);
         EvaluateLinearTree(blocks, out linearCompressionRatio, out scanDirection);
         compressionMode = hilbertCompressionRatio > linearCompressionRatio ? CompressionMode.Hilbert : CompressionMode.Linear;
     }
     else
     {
         switch (flag)
         {
             case CompressionFlag.LinearXyz:
                 compressionMode = CompressionMode.Linear;
                 scanDirection = ScanDirection.Xyz;
                 break;
             case CompressionFlag.LinearXzy:
                 compressionMode = CompressionMode.Linear;
                 scanDirection = ScanDirection.Xzy;
                 break;
             case CompressionFlag.LinearYxz:
                 compressionMode = CompressionMode.Linear;
                 scanDirection = ScanDirection.Yxz;
                 break;
             case CompressionFlag.LinearYzx:
                 compressionMode = CompressionMode.Linear;
                 scanDirection = ScanDirection.Yzx;
                 break;
             case CompressionFlag.LinearZxy:
                 compressionMode = CompressionMode.Linear;
                 scanDirection = ScanDirection.Zxy;
                 break;
             case CompressionFlag.LinearZyx:
                 compressionMode = CompressionMode.Linear;
                 scanDirection = ScanDirection.Zyx;
                 break;
             case CompressionFlag.Hilbert:
                 compressionMode = CompressionMode.Hilbert;
                 break;
             default:
                 throw new ArgumentOutOfRangeException("flag");
         }
     }
     if (compressionMode == CompressionMode.Hilbert)
     {
         //Console.Out.WriteLine(CompressionMode.Hilbert.ToString());
         return ConvertArrayToIntervalTreeHilbert(blocks, out compressionRatio);
     }
     else
     {
         //Console.Out.WriteLine(scanDirection.ToString());
         return ConvertArrayToIntervalTreeLinear(blocks, scanDirection, out compressionRatio);
     }
 }
 /// <summary>
 /// Adds a multiple files, located in <paramref name="fileNames"/>, to <see cref="MythicPackageBlock.Files"/> table.
 /// </summary>
 /// <param name="fileNames">Array of file paths on HD.</param>
 /// <param name="innerFolder">Relative folder within the UOP file (destination).</param>
 /// <param name="flag">Compression type.</param>
 public void AddFiles(string[] fileNames, string innerFolder, CompressionFlag flag = CompressionFlag.Zlib)
 {
     // parse all the files in the array
     foreach (string file in fileNames)
     {
         // add the file inside the first block that can accomodate it
         AddFile(file, innerFolder, flag);
     }
 }
        /// <summary>
        /// Replaces this file with another.
        /// </summary>
        /// <param name="fileName">Path to the file on HD.</param>
        /// <param name="packageFolder">Relative folder within KR.</param>
        /// <param name="flag">Compression type.</param>
        public void Replace(string fileName, string packageFolder, CompressionFlag flag)
        {
            m_FileName        = Path.Combine(packageFolder, Path.GetFileName(fileName)).ToLower();
            m_FileHash        = HashDictionary.HashFileName(m_FileName);
            m_SourceFileName  = fileName;
            m_Compression     = flag;
            m_DataBlockLength = 0;
            m_DataBlockHash   = 0;

            Modified = true;
        }
        /// <summary>
        /// Adds all files within a certain folder to .uop package.
        /// </summary>
        /// <param name="folder">Folder, which contains files.</param>
        /// <param name="flag">Compression type.</param>
        public void AddFolder(string folder, CompressionFlag flag = CompressionFlag.Zlib)
        {
            // if the folder doesn't exist, we throw an exception
            if (!Directory.Exists(folder))
            {
                throw new ArgumentException(string.Format("'{0}' is not a folder!", folder));
            }

            // create a stack of strings
            Stack <string> stack = new Stack <string>();

            // add the main folder to the stack
            stack.Push(folder);

            // keep looping until we parsed all folders
            while (stack.Count > 0)
            {
                // get the current folder
                string f = stack.Pop();

                // remove the root path (to create the relative path to use inside the uop)
                string inner = f.Remove(0, folder.Length);

                try // we use a try because if in the folder there is something weird (like a link), we would get an exception
                {
                    // add all the files in this folder
                    foreach (string file in Directory.GetFiles(f))
                    {
                        AddFile(file, inner, flag);
                    }

                    // add all the sub-folders of this folder inside the stack
                    foreach (string newFolder in Directory.GetDirectories(f))
                    {
                        stack.Push(newFolder);
                    }
                }
                catch
                { }
            }
        }
        /// <summary>
        /// Initializes a new instance.
        /// </summary>
        /// <param name="fileName">Absolute path to the file on HD.</param>
        /// <param name="innerFolder">Relative folder within KR (destination).</param>
        /// <param name="flag">Compression type.</param>
        public MythicPackageFile(string fileName, string innerFolder, CompressionFlag flag)
        {
            if (String.IsNullOrEmpty(fileName))
            {
                throw new ArgumentException("fileName");
            }

            m_FileName = Path.Combine(innerFolder, Path.GetFileName(fileName)).ToLower();

            if (m_FileName.StartsWith("\\") || m_FileName.StartsWith("/"))
            {
                m_FileName = m_FileName.Substring(1);
            }

            m_FileName        = m_FileName.Replace('\\', '/');
            m_FileHash        = HashDictionary.HashFileName(m_FileName);
            m_SourceFileName  = fileName;
            m_Compression     = flag;
            m_DataBlockLength = 0;
            m_DataBlockHash   = 0;
        }
        // --------------------------------------------------------------
        #region ADD/REMOVE FILES
        // --------------------------------------------------------------

        /// <summary>
        /// Adds a file, located in <paramref name="fileName"/>, to <see cref="MythicPackageBlock.Files"/> table.
        /// </summary>
        /// <param name="fileName">Path to a file on HD.</param>
        /// <param name="innerFolder">Relative folder within the UOP file (destination).</param>
        /// <param name="flag">Compression type.</param>
        public void AddFile(string fileName, string innerFolder, CompressionFlag flag = CompressionFlag.Zlib)
        {
            // empty file name? throw an exception
            if (string.IsNullOrEmpty(fileName))
            {
                throw new ArgumentException("fileName");
            }

            // if the file doesn't exist, throw an exception
            if (!File.Exists(fileName))
            {
                throw new Exception(string.Format("Cannot find {0}!", Path.GetFileName(fileName)));
            }

            // initialize the block variable to use
            MythicPackageBlock block;

            // do we have at least one block in the file?
            if (Blocks.Count > 0)
            {
                // use the last block
                block = Blocks[Blocks.Count - 1];
            }

            else // create a new block
            {
                block = NewBlock();
            }

            // is the block full? create a new block then
            if (block.IsFull)
            {
                block = NewBlock();
            }

            // add the file to the block
            block.AddFile(fileName, innerFolder, flag);
        }
Ejemplo n.º 12
0
        /// <summary>
        /// Adds a file, located in <paramref name="fileName"/>, to <see cref="Mythic.Package.MythicPackageBlock.Files"/> table.
        /// </summary>
        /// <param name="fileName">Path to a file on HD.</param>
        /// <param name="innerFolder">Relative folder within KR (destination).</param>
        /// <param name="flag">Compression type.</param>
        public void AddFile(string fileName, string innerFolder, CompressionFlag flag)
        {
            if (String.IsNullOrEmpty(fileName))
            {
                throw new ArgumentException("fileName");
            }

            if (IsFull)
            {
                throw new BlockFullException();
            }

            MythicPackageFile index = new MythicPackageFile(fileName, innerFolder, flag);

            index.Parent = this;
            index.Index  = m_Files.Count;
            index.Added  = true;

            m_FileCount += 1;
            m_Files.Add(index);

            m_Parent.Header.FileCount += 1;
        }
        private void EvaluateCompressionMode <T>(IList <T> blocks, out CompressionFlag optimal, out int nodeCount)
        {
            var count           = _chunkSize * _chunkSize * _chunkSize;
            var maxNodesRemoved = 0;

            optimal   = CompressionFlag.LinearXyz;
            nodeCount = 0;
            for (var scanDirection = 0; scanDirection < (int)CompressionFlag.None; scanDirection++)
            {
                var currentNodesRemoved = 0;
                var current             = default(T);
                var mappingFunction     = _intervalToBlock[(CompressionFlag)scanDirection];
                for (var i = 0; i < count; ++i)
                {
                    var block = blocks[mappingFunction[i]];
                    if (Equals(block, current))
                    {
                        ++currentNodesRemoved;
                        continue;
                    }
                    current = block;
                }
                if (currentNodesRemoved <= maxNodesRemoved)
                {
                    continue;
                }
                maxNodesRemoved = currentNodesRemoved;
                nodeCount       = count - maxNodesRemoved;
                optimal         = (CompressionFlag)scanDirection;
                //this means we are mostly uniform and can just exit out now!
                if (maxNodesRemoved / (float)count > 0.97f)
                {
                    break;
                }
            }
        }
        /// <summary>
        /// Replace the existing files inside the current package with the one with the same names provided on the files list.
        /// </summary>
        /// <param name="filesList">List of the files to replace</param>
        /// <param name="rootDir">Root directory of the file structure. Used to create the relative path for the files to add. Only necessary if <paramref name="addMissing"/> is true.</param>
        /// <param name="addMissing">Do we need to add the files that are not present in the current package?</param>
        /// <param name="flag">Compression type.</param>
        /// <param name="backupFolder">if a backup folder is specified, all files that needs replacing will be extracted there first.</param>
        public void ReplaceFiles(List <string> filesList, string rootDir = "", bool addMissing = false, CompressionFlag flag = CompressionFlag.Zlib, string backupFolder = null)
        {
            // create a queue for the files
            Queue <string> q = new Queue <string>(filesList);

            // keep looping until the queue is empty
            while (q.Count > 0)
            {
                // get the file from the list and make sure is lower case
                string currFile = q.Dequeue().ToLower();

                // search for a file with the current file name
                MythicPackageFile found = (from b in Blocks
                                           from f in b.Files
                                           where !string.IsNullOrEmpty(f.FileName) && Path.GetFileName(f.FileName) == Path.GetFileName(currFile)
                                           select f).FirstOrDefault();

                // if we found a file, we execute the replace
                if (found != null)
                {
                    // if a backup is required, we unpack the current file first
                    if (!string.IsNullOrEmpty(backupFolder))
                    {
                        found.Unpack(backupFolder, true);
                    }

                    // replace the file
                    found.Replace(currFile, found.FilePath, flag);
                }

                // if the file doesn't exit, we add it to the archive (if addMissing is true)
                else if (addMissing)
                {
                    AddFile(currFile, GetRelativePath(rootDir, currFile));
                }
            }
        }