Exemple #1
0
        /// <summary>
        /// Updates both the index and pack file sizes
        /// </summary>
        public void UpdateFileSizes()
        {
            // Lazy way of doing it...
            try
            {
                var s = String.Format("{0}{1}", MainWindowVm.Instance.SelectedWorkingProfile.WorkingDirectory,
                                      EterHelper.ReplaceWithEixExt(Filename));
                SizeOfIndexFile = new FileInfo(s).Length;
            }
            catch (Exception)
            {
                SizeOfIndexFile = 0;
            }

            try
            {
                SizeOfPackFile = new FileInfo(String.Format("{0}{1}", MainWindowVm.Instance.SelectedWorkingProfile.WorkingDirectory,
                                                            EterHelper.ReplaceWithEpkExt(Filename))).Length;
            }
            catch (Exception)
            {
                SizeOfIndexFile = 0;
            }
        }
Exemple #2
0
        /// <summary>
        /// Action performed when Pack file is hit
        /// </summary>
        /// <param name="param"></param>
        private async void PackFileAction(object param)
        {
            if (SelectedFilter < 0)
            {
                UserInput.ShowMessage("USER_SELECT_PACK_TYPE");
                return;
            }

            QueueActionType = ActionType.Pack;

            if (!IsItemReady())
            {
                return;
            }

            FilesActionVm.Instance.CcFiles++;
            SetItemState(State.Packing | State.LongAction);
            //await Task.Delay(1000);
            //this.SetItemState(State.Ready);
            //WorkingListVM.Instance.ProcessQueueUponActionFinalization(this);
            //return;

            HashMismatchFiles.Clear();
            ErrorList.Clear();
            _successCounter = 0;

            var filesInDir = IOHelper.GetAllFilesFromDir(String.Format("{0}{1}", MainWindowVm.Instance.SelectedWorkingProfile.UnpackDirectory, DisplayName));
            var indexItems = new List <IndexItem>();

            string indexFilePath = String.Format("{0}{1}",
                                                 MainWindowVm.Instance.SelectedWorkingProfile.WorkingDirectory,
                                                 String.Format("{0}{1}",
                                                               DisplayName,
                                                               MainWindowVm.Instance.SelectedWorkingProfile.IndexExtension));

            string packFilePath = String.Format("{0}{1}",
                                                MainWindowVm.Instance.SelectedWorkingProfile.WorkingDirectory,
                                                String.Format("{0}{1}",
                                                              DisplayName,
                                                              MainWindowVm.Instance.SelectedWorkingProfile.PackExtension));

            if (File.Exists(packFilePath))
            {
                // File already packed, but will be overwritten
                WindowLog.Warning("FILE_ALREADY_PACKED_BUT_OVER", Filename);
                File.Delete(packFilePath);
            }

            if (File.Exists(indexFilePath))
            {
                File.Delete(EterHelper.ReplaceWithEpkExt(indexFilePath));
            }

            await Task.Run(() =>
            {
                int counter = 0;
                foreach (var file in filesInDir)
                {
                    //int type = -1;

                    //string fileExtension = Path.GetExtension(file.FullName);

                    //if (SelectedFilter.RawExtensions != null)
                    //{
                    //    foreach (var rawExt in SelectedFilter.RawExtensions)
                    //        if (rawExt.ToLower() == fileExtension.ToLower())
                    //            type = 0;

                    //    foreach (var lzoExt in SelectedFilter.LzoExtensions)
                    //        if (lzoExt.ToLower() == fileExtension.ToLower())
                    //            type = 1;

                    //    foreach (var xteaExt in SelectedFilter.XteaExtensions)
                    //        if (xteaExt.ToLower() == fileExtension.ToLower())
                    //            type = 2;
                    //}

                    //if (type == -1)
                    //    type = SelectedFilter.NotIncludedExtensionsType;

                    string toReplaceStr = String.Format("{0}{1}", MainWindowVm.Instance.SelectedWorkingProfile.UnpackDirectory, DisplayName).Replace("/", "\\");

                    string fileName = file.FullName.Substring(file.FullName.IndexOf(toReplaceStr) + toReplaceStr.Length + 1);

                    indexItems.Add(new IndexItem(
                                       counter,
                                       fileName,
                                       null,
                                       0,
                                       0,
                                       null,
                                       0,
                                       SelectedFilter,
                                       DisplayName));
                    counter++;
                }

                double lastProgressValue = 0;

                try
                {
                    EterFilesDal.BuildIndexAndPackFiles(
                        indexItems,
                        packFilePath,
                        String.Format("{0}{1}\\",
                                      MainWindowVm.Instance.SelectedWorkingProfile.UnpackDirectory,
                                      DisplayName),
                        MainWindowVm.Instance.SelectedWorkingProfile.IndexKey,
                        MainWindowVm.Instance.SelectedWorkingProfile.PackKey,
                        (error) =>
                    {
                        if (error != null)
                        {
                            ErrorList.Add(error);
                        }
                    },
                        (result, progress) =>
                    {
                        if (result == 0)
                        {
                            _successCounter++;
                        }

                        if (((progress - lastProgressValue) >= 5))
                        {
                            ActionProgress    = progress;
                            lastProgressValue = progress;
                        }
                    },
                        () => SetItemState(State.CriticalError));
                }
                catch (OutOfMemoryException ex)
                {
                    WindowLog.Warning("FILE_TOO_BIG", DisplayName);
                    SetItemState(State.CriticalError);
                }
                catch (EterPackFileNotFoundException ex)
                {
                    WindowLog.Error("ETER_EPK_FILE_NOT_FOUND", DisplayName);
                    SetItemState(State.CriticalError);
                }
                catch (FileNotFoundException ex)
                {
                    WindowLog.Error("FILE_NOT_FOUND", DisplayName, new object[] { ex.FileName });
                    SetItemState(State.CriticalError);
                }
                catch (UnauthorizedAccessException ex)
                {
                    WindowLog.Error("COULD_NOT_ACCESS_FILE", DisplayName, DisplayName);
                    SetItemState(State.CriticalError);
                }
                catch (System.IO.IOException ex)
                {
                    WindowLog.Error("ERROR_WITH_CUSTOM_MSG", DisplayName, ex.Message);
                    SetItemState(State.CriticalError);
                }
            });

            SetItemState(ErrorList.Count > 0 ? State.ReadyWithErrors : State.Ready);

            ActionProgress = 100;
            WindowLog.Information("ETER_PACK_RESULT", DisplayName, new object[] { _successCounter, HashMismatchFiles.Count, ErrorList.Count });
            AfterLongAction(param);
        }
Exemple #3
0
        /// <summary>
        /// Action performed when Unpack file is hit
        /// </summary>
        /// <param name="param"></param>
        private async void UnpackFileAction(object param)
        {
            QueueActionType = ActionType.Unpack;

            if (!IsItemReady())
            {
                return;
            }

            FilesActionVm.Instance.CcFiles++;
            SetItemState(State.Unpacking | State.LongAction);

            await Task.Run(() =>
            {
                // Set state to unpacking
                SetItemState(State.Unpacking);

                // Clear lists
                HashMismatchFiles.Clear();
                ErrorList.Clear();

                // Reset counters
                _successCounter          = 0;
                double lastProgressValue = 0;

                try
                {
                    // Unpack file
                    EterFilesDal.UnpackFile(
                        new FileInfo(EterHelper.ReplaceWithEpkExt(Path.Combine(MainWindowVm.Instance.SelectedWorkingProfile.WorkingDirectory, Filename))),
                        MainWindowVm.Instance.SelectedWorkingProfile.UnpackDirectory,
                        MainWindowVm.Instance.SelectedWorkingProfile.IndexKey,
                        MainWindowVm.Instance.SelectedWorkingProfile.PackKey,
                        (operationResult, globalProgress) =>
                    {
                        if ((globalProgress - lastProgressValue) >= 5)
                        {
                            ActionProgress    = globalProgress;
                            lastProgressValue = globalProgress;
                        }

                        if (operationResult == 0)
                        {
                            _successCounter++;
                        }
                    },
                        (error, hash) =>
                    {
                        if (error != null)
                        {
                            ErrorList.Add(error);
                        }

                        if (!String.IsNullOrWhiteSpace(hash))
                        {
                            HashMismatchFiles.Add(hash);
                        }
                    });
                }
                catch (ErrorReadingIndexException ex)
                {
                    WindowLog.Error("ETER_WRONG_INDEX_KEY", DisplayName);
                    SetItemState(State.CriticalError);
                }
                catch (OutOfMemoryException ex)
                {
                    WindowLog.Warning("FILE_TOO_BIG", DisplayName);
                    SetItemState(State.CriticalError);
                }
                catch (EterPackFileNotFoundException ex)
                {
                    WindowLog.Error("ETER_EPK_FILE_NOT_FOUND", DisplayName);
                    SetItemState(State.CriticalError);
                }
                catch (FileNotFoundException ex)
                {
                    WindowLog.Error("FILE_NOT_FOUND", DisplayName, new object[] { ex.FileName });
                    SetItemState(State.CriticalError);
                }
                catch (UnauthorizedAccessException ex)
                {
                    WindowLog.Error("COULD_NOT_ACCESS_FILE", DisplayName, DisplayName);
                    SetItemState(State.CriticalError);
                }
                catch (System.IO.IOException ex)
                {
                    WindowLog.Error("ERROR_WITH_CUSTOM_MSG", DisplayName, ex.Message);
                    SetItemState(State.CriticalError);
                }
            });

            // If any file produced an error, set state accordingly
            if (ErrorList.Count > 0 && ItemState != State.CriticalError)
            {
                SetItemState(State.ReadyWithErrors);
            }
            else if (ErrorList.Count == 0 && ItemState != State.CriticalError)
            {
                SetItemState(State.Ready);
            }

            // Make sure progress bar is at 100%
            ActionProgress = 100;

            // Logging stuff
            if (ItemState != State.CriticalError)
            {
                // Get all failed items
                int failedCount = ErrorList.Count;

                // Were any unnamed files present?
                var item = ErrorList.FirstOrDefault(x => x.ErrorMotive.Contains("(no name)"));

                // If so, add it
                if (item != null)
                {
                    failedCount += Convert.ToInt32(item.Arg) - 1;
                }

                WindowLog.Information("ETER_UNPACK_RESULT", DisplayName, _successCounter, HashMismatchFiles.Count, failedCount);
            }


            AfterLongAction(param);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="packFile"></param>
        /// <param name="saveFilesPath"></param>
        /// <param name="indexKey"></param>
        /// <param name="packKey"></param>
        /// <param name="progressCallback"></param>
        /// <param name="fileLoggingCallback"></param>
        public static void UnpackFile(
            FileInfo packFile,
            string saveFilesPath,
            byte[] indexKey,
            byte[] packKey,
            Action<int, int> progressCallback,
            Action<ErrorItem, string> fileLoggingCallback)
        {
            if (!File.Exists(packFile.FullName))
            {
                throw new EterPackFileNotFoundException();
            }

            // Reads the index file
            List<IndexItem> workingList = ReadIndexFile(EterHelper.ReplaceWithEixExt(packFile.FullName), indexKey, StringHelpers.TrimExtension(packFile.Name));

            if (workingList == null)
                return;

            // Check userData paths
            Directory.CreateDirectory(saveFilesPath);

            // File result counters
            double totalFilesCounter = 0;
            int unnamedFilesCounter = 0;
            int operationResult = 0;

            foreach (IndexItem item in workingList)
            {
                if (item.Size < 16 && item.PackType > 0)
                {
                    //WindowLog.LogOutputMessage(Log.LogId.FILE_SIZE_TOO_SMALL, args: new object[] { item.Filename, item.Size }); TODO
                    continue;
                }

                DrivePointManager.CheckIfContainsDrivePoint(item.Filename);

                if (String.IsNullOrWhiteSpace(item.Filename))
                {
                    unnamedFilesCounter++;
                    continue;
                }

                switch (item.PackType)
                {
                    // Raw format
                    case 0:
                        operationResult = ProcessFileType0(
                            packFile.FullName,
                            String.Format("{0}{1}/", saveFilesPath, StringHelpers.TrimExtension(packFile.Name)),
                            item,
                            fileLoggingCallback);
                        break;
                    // LZO compressed file
                    case 1:
                        operationResult = ProcessFileType1(
                            packFile.FullName,
                            String.Format("{0}{1}/", saveFilesPath, StringHelpers.TrimExtension(packFile.Name)),
                            item,
                            fileLoggingCallback);
                        break;
                    // XTEA encrypted and LZO compressed file
                    case 2:
                        operationResult = ProcessFileType2(
                            packFile.FullName,
                            String.Format("{0}{1}/", saveFilesPath, StringHelpers.TrimExtension(packFile.Name)),
                            item,
                            packKey,
                            fileLoggingCallback);
                        break;
                    // Panama encryption
                    case 3:
                        operationResult = ProcessFileType3(
                            packFile.FullName,
                            String.Format("{0}{1}/", saveFilesPath, StringHelpers.TrimExtension(packFile.Name)),
                            item,
                            packKey,
                            fileLoggingCallback);
                        break;
                    default:
                        fileLoggingCallback(
                            new ErrorItem(item.Filename, String.Format("Type {0} is not yet supported.", item.PackType)),
                            null);
                        break;
                }

                totalFilesCounter += 1.0;

                // Update progress
                double actionProgress = (totalFilesCounter / workingList.Count * 100.0);
                progressCallback(operationResult, (int)actionProgress);
            }

            // If unnamed files were found, log it
            if (unnamedFilesCounter > 0)
                fileLoggingCallback(
                    new ErrorItem("UNDEFINED", unnamedFilesCounter + " files were ignored due to incomplete header info (no name)", unnamedFilesCounter),
                    null);
        }
        /// <summary>
        /// Buils EIX and EPK files
        /// </summary>
        /// <param name="list">Deserialized list</param>
        /// <param name="packFilePath">Path to EPK file, including the name</param>
        /// <param name="unpackedFilesPath">Path to unpacked files</param>
        /// <param name="indexKey">Index XTEA key</param>
        /// <param name="packKey">Pack XTEA key</param>
        /// <param name="errorLogCallBack"></param>
        /// <param name="progressCallback">Callback if progress updates are needed</param>
        /// <returns></returns>
        public static bool BuildIndexAndPackFiles(
            List<IndexItem> list,
            string packFilePath,
            string unpackedFilesPath,
            byte[] indexKey,
            byte[] packKey,
            Action<ErrorItem> errorLogCallBack,
            Action<int, int> progressCallback,
            Action fatalErrorCallback)
        {
            using (var fStream = new MemoryStream())
            {
                packFilePath = packFilePath.Replace("\\", "/");
                // Check if directory exists
                string directoryPath = packFilePath.Substring(0, packFilePath.LastIndexOf("/"));
                Directory.CreateDirectory(directoryPath);

                // Create stream to EPK file
                var epkStream = new FileStream(EterHelper.ReplaceWithEpkExt(packFilePath), FileMode.Create);

                // Size from header for each file
                int decompressedSize = 0;
                int compressedSize = 0;
                uint encryptedSize = 0;

                // File counter to index files
                int indexCount = 0;

                // Progress variables
                double actionProgress = 0;

                // FileOffset holder (EPK stream's length)
                int fileOffset = 0;

                // Write first header to EIX file
                fStream.Write(ConstantsBase.EterFourCc, 0, ConstantsBase.EterFourCc.Length);
                fStream.Write(BitConverter.GetBytes(2), 0, 4);
                fStream.Write(BitConverter.GetBytes(list.Count), 0, 4);

                try
                {
                    foreach (IndexItem item in list)
                    {
                        // Loop through items
                        var fileName = new byte[161];
                        var fileNameCrc = new byte[4];

                        //Index item's structure (totalizing 192 bytes)
                        #region Byte Holders

                        var fileIndex = new byte[4];
                        var realDataSize = new byte[4];
                        var dataSize = new byte[4];
                        var dataCrc = new byte[4];
                        var dataOffset = new byte[4];
                        var padding3B = new byte[3];

                        #endregion

                        // Set all backslashs to forwards slashes
                        item.Filename = item.Filename.Replace('\\', '/');

                        // Get raw data
                        byte[] rawData = IOHelper.ReadFile(unpackedFilesPath + item.Filename);

                        // Header sizees
                        int encryptedFileSize = 0;
                        int compressedFileSize = 0;
                        int decompressedFileSize = 0;

                        // Set real data & decompressed size to raw data's lenth
                        realDataSize = BitConverter.GetBytes(rawData.Length);
                        decompressedFileSize = rawData.Length;

                        // Set fileoffset to actual stream's length
                        fileOffset = (int)epkStream.Length;

                        #region File Type Processing

                        // Switch through the 3 possible cases
                        switch (item.PackType)
                        {
                            case 0:
                                // Write data to EPK stream
                                epkStream.Write(rawData, 0, rawData.Length);

                                // Set data size equal to raw data since no compression nor encrypted occured
                                dataSize = BitConverter.GetBytes(rawData.Length);
                                break;
                            case 1:
                            case 2:
                                // Compress data
                                byte[] compressedDataBuffer = LzoHelper.CompressData(rawData.Length, rawData);

                                // Create buffer to hold header + compressedData
                                byte[] compressedDataWithHeaderBuffer = new byte[compressedDataBuffer.Length + 4];

                                // Copy header and compressedData to previously created buffer
                                Array.Copy(ConstantsBase.LzoFourCc, 0, compressedDataWithHeaderBuffer, 0, 4);
                                Array.Copy(compressedDataBuffer, 0, compressedDataWithHeaderBuffer, 4, compressedDataBuffer.Length);

                                // Set dataSize to compressedSize (since it assumes it's type 1)
                                dataSize = BitConverter.GetBytes(compressedDataWithHeaderBuffer.Length + 16);

                                // Set compressedSize
                                compressedFileSize = compressedDataBuffer.Length;

                                // If type 2
                                if (item.PackType == 2)
                                {
                                    // Get encrypted size (ALWAYS the upper multiple)
                                    encryptedFileSize = GetUpperMultiple(compressedDataWithHeaderBuffer.Length);

                                    // Resize data to fit encryptedSize
                                    Array.Resize(ref compressedDataWithHeaderBuffer, encryptedFileSize);

                                    // Encrypt Data
                                    Xtea.Encrypt2(ref compressedDataWithHeaderBuffer, packKey);

                                    // Set dataSize to encryptedData + header
                                    dataSize = BitConverter.GetBytes(compressedDataWithHeaderBuffer.Length + 16);
                                }

                                // Write header of file to EPK stream
                                epkStream.Write(ConstantsBase.LzoFourCc, 0, 4);
                                epkStream.Write(BitConverter.GetBytes(encryptedFileSize), 0, 4);
                                epkStream.Write(BitConverter.GetBytes(compressedFileSize), 0, 4);
                                epkStream.Write(BitConverter.GetBytes(decompressedFileSize), 0, 4);

                                // Write actual data
                                epkStream.Write(compressedDataWithHeaderBuffer, 0, compressedDataWithHeaderBuffer.Length);
                                break;
                        }

                        #endregion

                        #region Building index file

                        // Check if string replacment is needed
                        string virtualPathFile = DrivePointManager.InsertDrivePoints(item.Filename);

                        // Populate byte[] with data
                        fileIndex = BitConverter.GetBytes(item.Index);
                        byte[] fileNameTemp = Encoding.Default.GetBytes(virtualPathFile);
                        fileNameCrc = CrcHelper.GetCrc32HashFromMemoryToByteArray(Encoding.Default.GetBytes(virtualPathFile));
                        realDataSize = (realDataSize == null) ? BitConverter.GetBytes(item.DiskSize) : realDataSize;
                        dataSize = (dataSize == null) ? BitConverter.GetBytes(item.Size) : dataSize;
                        dataCrc = CrcHelper.GetCrc32HashToByteArray(unpackedFilesPath + item.Filename);
                        dataOffset = BitConverter.GetBytes(fileOffset);
                        var compressedType = (byte)item.PackType;

                        // Check if filename buffer is expectedSize
                        if (fileNameTemp.Length != 161)
                        {
                            Array.Copy(fileNameTemp, 0, fileName, 0, fileNameTemp.Length);
                        }

                        // Write data to EIX's stream
                        fStream.Write(fileIndex, 0, fileIndex.Length);
                        fStream.Write(fileName, 0, 161);
                        fStream.Write(padding3B, 0, padding3B.Length);
                        fStream.Write(fileNameCrc.Reverse().ToArray(), 0, fileNameCrc.Length);
                        fStream.Write(realDataSize, 0, realDataSize.Length);
                        fStream.Write(dataSize, 0, dataSize.Length);
                        fStream.Write(dataCrc.Reverse().ToArray(), 0, dataCrc.Length);
                        fStream.Write(dataOffset, 0, dataOffset.Length);
                        fStream.WriteByte(compressedType);
                        fStream.Write(padding3B, 0, padding3B.Length);

                        indexCount++;
                        #endregion

                        // Update progress
                        actionProgress = (indexCount / (double)list.Count * 100.0);
                        progressCallback(0, (int)actionProgress);
                    }
                }
                catch (Exception ex)
                {
                    //WindowLog.LogExceptioToFile(ex.ToString()); TODO
                    fatalErrorCallback();
                    throw;
                }

                // Assign current stream's lenght to decmopressedSize
                decompressedSize = (int)fStream.Length;

                // Buffer to hold compressedData
                byte[] compressedData = LzoHelper.CompressData(decompressedSize, fStream.ToArray());

                // Buffer with compressedData + MCOZ header
                byte[] compressedDataWithHeader = new byte[compressedData.Length + 4];

                // Copy Header to buffer
                Array.Copy(ConstantsBase.LzoFourCc, 0, compressedDataWithHeader, 0, 4);

                // Copy data to buffer
                Array.Copy(compressedData, 0, compressedDataWithHeader, 4, compressedData.Length);

                // Save compressedSize
                compressedSize = compressedData.Length;

                // Save encryptedSize (round to upper multiple)
                encryptedSize = (uint)GetUpperMultiple(compressedSize + 4);

                // Resize array to fit new size
                Array.Resize(ref compressedDataWithHeader, (int)encryptedSize);

                // Encrypt data
                Xtea.Encrypt2(ref compressedDataWithHeader, indexKey);

                // Create buffer to hold final data + header
                var outputFileBuffer = new byte[compressedDataWithHeader.Length + 16];

                // Copy header to buffer
                Array.Copy(ConstantsBase.LzoFourCc, 0, outputFileBuffer, 0, 4);
                Array.Copy(BitConverter.GetBytes(encryptedSize), 0, outputFileBuffer, 4, 4);
                Array.Copy(BitConverter.GetBytes(compressedSize), 0, outputFileBuffer, 8, 4);
                Array.Copy(BitConverter.GetBytes(decompressedSize), 0, outputFileBuffer, 12, 4);

                // Copy data to buffer
                Array.Copy(compressedDataWithHeader, 0, outputFileBuffer, 16, compressedDataWithHeader.Length);

                // Close stream
                epkStream.Close();
                epkStream.Dispose();

                // Save file
                File.WriteAllBytes(EterHelper.ReplaceWithEixExt(packFilePath), outputFileBuffer);

                return true;
            }
        }