/// <summary>
        /// 同步解压一个IFS文件内存流
        /// </summary>
        /// <param name="filePath"></param>
        /// <param name="outDir"></param>
        /// <returns></returns>
        public static bool SyncUnarchiveIFSFile(MemoryStream fileS, string outDir)
        {
            if (FileUtil.IsDirectoryExist(outDir))
            {
                FileUtil.ClearDirectory(outDir);
            }
            else
            {
                FileUtil.CreateDirectory(outDir);
            }
            //
            JW.Common.Log.LogD("Begin->");
            Stopwatch st = new Stopwatch();

            st.Start();
            //
            IFSFile ifsFile = new IFSFile();

            //获取签名
            byte[] bbs    = new byte[16];
            int    offset = 0;

            fileS.Read(bbs, 0, 16);
            uint sig = (uint)ConvertBytesToInt(bbs, ref offset);

            if (sig != IFSFile.IFSSignature)
            {
                JW.Common.Log.LogE("IFSArchiver SyncUnarchiveIFSFile Error Signature ");
                fileS.Close();
                return(false);
            }
            ifsFile.Signature = sig;
            //获取压缩方式
            ifsFile.CompressType = (IFSCompressType)ConvertBytesToInt(bbs, ref offset);
            //条目个数
            ifsFile.EntryCount = ConvertBytesToInt(bbs, ref offset);
            //名称长度
            int entryNameL = ConvertBytesToInt(bbs, ref offset);

            if (ifsFile.EntryCount == 0)
            {
                JW.Common.Log.LogE("IFSArchiver SyncUnarchiveIFSFile Error  EntryCount");
                fileS.Close();
                return(false);
            }
            //条目名称段
            ifsFile.Entrys = new IFSEntry[ifsFile.EntryCount];
            for (int i = 0; i < ifsFile.EntryCount; i++)
            {
                ifsFile.Entrys[i] = new IFSEntry();
            }
            //
            bbs = null;
            //
            byte[] names = new byte[entryNameL];
            fileS.Read(names, 0, entryNameL);
            offset = 0;
            //读取条目名称
            for (int i = 0; i < ifsFile.EntryCount; i++)
            {
                IFSEntry entry = ifsFile.Entrys[i];
                entry.Name = ConvertBytesToString(names, ref offset);
            }
            //条目数据位置
            offset = 0;
            names  = null;
            byte[] poss = new byte[ifsFile.EntryCount * 4];
            fileS.Read(poss, 0, ifsFile.EntryCount * 4);
            for (int i = 0; i < ifsFile.EntryCount; i++)
            {
                IFSEntry entry = ifsFile.Entrys[i];
                int      vv    = ConvertBytesToInt(poss, ref offset);
                entry.DataPos = vv;
            }
            offset = 0;
            poss   = null;
            #region 无压缩 直接解压
            //无压缩 直接解压
            if (ifsFile.CompressType == IFSCompressType.None)
            {
                bool isOk = false;
                try
                {
                    //公用buffer
                    byte[] buffer = new byte[4 * 1024];
                    //解压数据到文件
                    for (int i = 0; i < ifsFile.EntryCount; i++)
                    {
                        IFSEntry entry     = ifsFile.Entrys[i];
                        string   outPath   = FileUtil.CombinePaths(outDir, entry.Name);
                        string   directory = Path.GetDirectoryName(outPath);
                        if (!Directory.Exists(directory))
                        {
                            Directory.CreateDirectory(directory);
                        }
                        FileStream output = new FileStream(outPath, FileMode.Create);
                        try
                        {
                            fileS.Seek(entry.DataPos, SeekOrigin.Begin);
                            byte[] ll = new byte[4];
                            fileS.Read(ll, 0, 4);
                            offset = 0;
                            int vv = ConvertBytesToInt(ll, ref offset);
                            entry.DataSize = vv;
                            //
                            bool copying   = true;
                            int  processed = 0;
                            while (copying)
                            {
                                int bytesRead = fileS.Read(buffer, 0, buffer.Length);
                                if (bytesRead > 0)
                                {
                                    if (entry.DataSize <= bytesRead)
                                    {
                                        output.Write(buffer, 0, entry.DataSize);
                                        copying = false;
                                    }
                                    else
                                    {
                                        processed += bytesRead;
                                        if (processed > entry.DataSize)
                                        {
                                            output.Write(buffer, 0, bytesRead - (processed - entry.DataSize));
                                            copying = false;
                                        }
                                        else
                                        {
                                            output.Write(buffer, 0, bytesRead);
                                            copying = true;
                                        }
                                    }
                                }
                                else
                                {
                                    copying = false;
                                }
                            }
                            //
                            output.Flush();
                        }
                        catch (Exception exc)
                        {
                            JW.Common.Log.LogE("Failed:" + entry.Name + "---" + exc.ToString());
                        }
                        finally
                        {
                            output.Close();
                            output.Dispose();
                            output = null;
                        }
                    }
                }
                catch (Exception exc)
                {
                    JW.Common.Log.LogE("IFSArchiver SyncUnarchiveIFSFile:" + exc.ToString());
                    isOk = false;
                }
                finally
                {
                    st.Stop();//终止计时
                    JW.Common.Log.LogD("Done:" + st.ElapsedMilliseconds.ToString());
                    fileS.Close();
                    fileS.Dispose();
                    fileS = null;
                }
                st.Stop();//终止计时
                JW.Common.Log.LogD("Done:" + st.ElapsedMilliseconds.ToString());
                return(isOk);
            }
            #endregion
            //
            if (ifsFile.CompressType == IFSCompressType.LZMA)
            {
                bool isOk = DoUnarchiveLZMAIFSFile(ifsFile, outDir, fileS);
                st.Stop();
                JW.Common.Log.LogD("Done:" + st.ElapsedMilliseconds.ToString());
                return(isOk);
            }
            return(true);
        }
        //
        private static bool DoUnarchiveLZMAIFSFile(IFSFile ifsFile, string outDir, Stream fileS)
        {
            bool isOk = true;

            try
            {
                //公用buffer
                byte[] buffer = new byte[4 * 1024];
                int    offset = 0;
                //解压数据到文件
                for (int i = 0; i < ifsFile.EntryCount; i++)
                {
                    IFSEntry entry = ifsFile.Entrys[i];
                    JW.Common.Log.LogD("Un LZMA File:" + entry.Name);
                    //
                    fileS.Seek(entry.DataPos, SeekOrigin.Begin);
                    byte[] ll = new byte[4];
                    fileS.Read(ll, 0, 4);
                    offset = 0;
                    int vv = ConvertBytesToInt(ll, ref offset);
                    entry.DataSize = vv;
                    //解压
                    string outPath   = FileUtil.CombinePaths(outDir, entry.Name);
                    string directory = Path.GetDirectoryName(outPath);
                    if (!Directory.Exists(directory))
                    {
                        Directory.CreateDirectory(directory);
                    }
                    FileStream output = new FileStream(outPath, FileMode.Create);
                    try
                    {
                        SevenZip.Compression.LZMA.Decoder coder = new SevenZip.Compression.LZMA.Decoder();
                        byte[] properties = new byte[5];
                        fileS.Read(properties, 0, 5);
                        byte[] fileLengthBytes = new byte[8];
                        fileS.Read(fileLengthBytes, 0, 8);
                        long fileLength = BitConverter.ToInt64(fileLengthBytes, 0);
                        coder.SetDecoderProperties(properties);
                        coder.Code(fileS, output, entry.DataSize, fileLength, null);
                        output.Flush();
                    }
                    catch (Exception exc)
                    {
                        JW.Common.Log.LogE("LZMA Failed:" + entry.Name + "---" + exc.ToString());
                    }
                    finally
                    {
                        output.Close();
                        output.Dispose();
                        output = null;
                    }
                }
            }
            catch (Exception exc)
            {
                JW.Common.Log.LogE("LZMA Failed:" + exc.ToString());
                isOk = false;
            }
            finally
            {
                fileS.Close();
                fileS.Dispose();
            }
            return(isOk);
        }
        //归档一批文件
        private static bool DoArchiveDir(string[] needfiles, string indir, string outPath, IFSCompressType compressType)
        {
            if (needfiles == null || needfiles.Length == 0)
            {
                return(false);
            }
            //
            int fileCnt = needfiles.Length;
            //
            IFSFile ifsFile = new IFSFile();

            ifsFile.EntryCount   = fileCnt;
            ifsFile.CompressType = compressType;
            ifsFile.Entrys       = new IFSEntry[fileCnt];
            for (int i = 0; i < fileCnt; i++)
            {
                ifsFile.Entrys[i] = new IFSEntry();
            }
            //
            //初始化条目
            for (int i = 0; i < fileCnt; i++)
            {
                IFSEntry entry        = ifsFile.Entrys[i];
                string   relativePath = FileUtil.GetRelativePath(needfiles[i], indir);
                entry.Name     = relativePath;
                entry.DataSize = FileUtil.GetFileLength(needfiles[i]);
            }
            int entryNameSegL = 0;
            //写入开始
            int begin = 0;

            //签名
            begin += 4;
            //压缩方式
            begin += 4;
            //条目个数
            begin += 4;
            //条目名字段长度
            begin += 4;
            //条目名称信息
            for (int i = 0; i < ifsFile.Entrys.Length; i++)
            {
                IFSEntry entry = ifsFile.Entrys[i];
                int      l     = GetStringBytesLength(entry.Name);
                begin         += l;
                entryNameSegL += l;
            }
            //条目数据位置段
            for (int i = 0; i < ifsFile.Entrys.Length; i++)
            {
                begin += 4;
            }
            //设置
            for (int i = 0; i < ifsFile.Entrys.Length; i++)
            {
                IFSEntry entry = ifsFile.Entrys[i];
                if (i == 0)
                {
                    entry.DataPos = begin;
                }
                else
                {
                    IFSEntry entryPre = ifsFile.Entrys[i - 1];
                    //数据开始位置是上一个的开始位置+4+L
                    entry.DataPos = entryPre.DataPos + 4 + entryPre.DataSize;
                }
            }
            //开始写
            //写大文件
            FileStream outIfs = new FileStream(outPath, FileMode.Create);

            //先写入文件头签名
            byte[] bb = ConvertIntToBytes((int)ifsFile.Signature);
            outIfs.Write(bb, 0, bb.Length);
            //写入压缩方式
            bb = ConvertIntToBytes((int)ifsFile.CompressType);
            outIfs.Write(bb, 0, bb.Length);
            //条目个数
            bb = ConvertIntToBytes(ifsFile.Entrys.Length);
            outIfs.Write(bb, 0, bb.Length);
            //条目名称总长度
            bb = ConvertIntToBytes(entryNameSegL);
            outIfs.Write(bb, 0, bb.Length);
            //条目名字信息
            for (int i = 0; i < ifsFile.Entrys.Length; i++)
            {
                IFSEntry entry = ifsFile.Entrys[i];
                byte[]   bbs   = ConvertStringToBytes(entry.Name);
                //名字
                outIfs.Write(bbs, 0, bbs.Length);
            }
            //条目数据位置开始位置索引写入
            for (int i = 0; i < ifsFile.Entrys.Length; i++)
            {
                IFSEntry entry = ifsFile.Entrys[i];
                byte[]   bbs   = ConvertIntToBytes(entry.DataPos);
                //名字
                outIfs.Write(bbs, 0, bbs.Length);
            }
            try
            {
                //写入所有文件数据
                for (int i = 0; i < ifsFile.Entrys.Length; i++)
                {
                    IFSEntry entry = ifsFile.Entrys[i];
                    //长度
                    byte[] ddl = ConvertIntToBytes(entry.DataSize);
                    outIfs.Write(ddl, 0, ddl.Length);
                    //写入数据
                    byte[] fileData = FileUtil.ReadFile(needfiles[i]);
                    outIfs.Write(fileData, 0, entry.DataSize);
                }
            }
            catch (Exception exc)
            {
                JW.Common.Log.LogE("Archive Exception:" + exc.ToString());
                return(false);
            }
            outIfs.Flush();
            outIfs.Close();
            return(true);
        }