/// <summary> /// Unpack the specified File, returns unpacked dir. /// </summary> /// <param name="sourceFileName">Source file path.</param> /// <param name="savePath">Save path.</param> /// <param name="decodeAudio">If set to <c>true</c> decode audio.</param> /// <param name="extractSongXml">If set to <c>true</c> extract song xml from sng.</param> /// <param name="overwriteSongXml">If set to <c>true</c> overwrite existing song xml with produced.</param> /// <param name="predefinedPlatform">Predefined source platform.</param> public static string Unpack(string sourceFileName, string savePath, bool decodeAudio = false, bool extractSongXml = false, bool overwriteSongXml = true, Platform predefinedPlatform = null) { Platform platform = sourceFileName.GetPlatform(); if (predefinedPlatform != null && predefinedPlatform.platform != GamePlatform.None && predefinedPlatform.version != GameVersion.None) { platform = predefinedPlatform; } var fnameWithoutExt = Path.GetFileNameWithoutExtension(sourceFileName); var unpackedDir = Path.Combine(savePath, String.Format("{0}_{1}", fnameWithoutExt, platform.platform)); if (Directory.Exists(unpackedDir)) { DirectoryExtension.SafeDelete(unpackedDir); } var useCryptography = platform.version == GameVersion.RS2012; // Cryptography way is used only for PC in Rocksmith 1 switch (platform.platform) { case GamePlatform.Pc: case GamePlatform.Mac: if (platform.version == GameVersion.RS2014) { using (var inputStream = File.OpenRead(sourceFileName)) ExtractPSARC(sourceFileName, savePath, inputStream, platform); } else { using (var inputFileStream = File.OpenRead(sourceFileName)) using (var inputStream = new MemoryStream()) { if (useCryptography) { RijndaelEncryptor.DecryptFile(inputFileStream, inputStream, RijndaelEncryptor.DLCKey); } else { inputFileStream.CopyTo(inputStream); } ExtractPSARC(sourceFileName, savePath, inputStream, platform); } } break; case GamePlatform.XBox360: UnpackXBox360Package(sourceFileName, savePath, platform); break; case GamePlatform.PS3: UnpackPS3Package(sourceFileName, savePath, platform); break; case GamePlatform.None: throw new InvalidOperationException("Platform not found :("); } if (platform.platform == GamePlatform.PS3) { fnameWithoutExt = fnameWithoutExt.Substring(0, fnameWithoutExt.LastIndexOf(".")); } // DECODE AUDIO if (decodeAudio) { var audioFiles = Directory.EnumerateFiles(unpackedDir, "*.*", SearchOption.AllDirectories).Where(s => s.EndsWith(".ogg") || s.EndsWith(".wem")); foreach (var file in audioFiles) { var outputAudioFileName = Path.Combine(Path.GetDirectoryName(file), String.Format("{0}_fixed{1}", Path.GetFileNameWithoutExtension(file), ".ogg")); OggFile.Revorb(file, outputAudioFileName, Path.GetDirectoryName(Application.ExecutablePath), Path.GetExtension(file).GetWwiseVersion()); } } // EXTRACT XML FROM SNG if (extractSongXml && platform.version == GameVersion.RS2014) { var sngFiles = Directory.EnumerateFiles(unpackedDir, "*.sng", SearchOption.AllDirectories); foreach (var sngFile in sngFiles) { var xmlOutput = Path.Combine(Path.GetDirectoryName(sngFile), String.Format("{0}.xml", Path.GetFileNameWithoutExtension(sngFile))); xmlOutput = xmlOutput.Replace(String.Format("bin{0}{1}", Path.DirectorySeparatorChar, platform.GetPathName()[1].ToLower()), "arr"); if (File.Exists(xmlOutput) && !overwriteSongXml) { continue; } var arrType = ArrangementType.Guitar; if (Path.GetFileName(xmlOutput).ToLower().Contains("vocal")) { arrType = ArrangementType.Vocal; } Attributes2014 att = null; if (arrType != ArrangementType.Vocal) { var jsonFiles = Directory.EnumerateFiles(unpackedDir, String.Format("{0}.json", Path.GetFileNameWithoutExtension(sngFile)), SearchOption.AllDirectories).FirstOrDefault(); if (jsonFiles.Any() && !String.IsNullOrEmpty(jsonFiles)) { att = Manifest2014 <Attributes2014> .LoadFromFile(jsonFiles).Entries.ToArray()[0].Value.ToArray()[0].Value; } } var sngContent = Sng2014File.LoadFromFile(sngFile, platform); using (var outputStream = new FileStream(xmlOutput, FileMode.Create, FileAccess.ReadWrite)) { dynamic xmlContent = null; if (arrType == ArrangementType.Vocal) { xmlContent = new Vocals(sngContent); } else { xmlContent = new Song2014(sngContent, att); } xmlContent.Serialize(outputStream); } } } return(unpackedDir); }
private static void PackPC(string sourcePath, string saveFileName, bool useCryptography, bool updateSng) { foreach (var namesBlock in Directory.EnumerateFiles(sourcePath, "NamesBlock.bin", SearchOption.AllDirectories)) { if (File.Exists(namesBlock)) { File.Delete(namesBlock); } } using (var psarcStream = new MemoryStream()) using (var streamCollection = new DisposableCollection <Stream>()) { var psarc = new PSARC.PSARC(); foreach (var x in Directory.EnumerateFiles(sourcePath)) { var fileStream = File.OpenRead(x); streamCollection.Add(fileStream); var entry = new PSARC.Entry { Name = Path.GetFileName(x), Data = fileStream, Length = (ulong)fileStream.Length }; psarc.AddEntry(entry); } foreach (var directory in Directory.EnumerateDirectories(sourcePath)) { var innerPsarcStream = new MemoryStream(); streamCollection.Add(innerPsarcStream); var directoryName = Path.GetFileName(directory); // Recreate SNG if (updateSng) { if (directory.ToLower().IndexOf("dlc_tone_") < 0) { UpdateSng(directory, new Platform(GamePlatform.Pc, GameVersion.RS2012)); } } PackInnerPC(innerPsarcStream, directory); psarc.AddEntry(directoryName + ".psarc", innerPsarcStream); } psarc.Write(psarcStream, false); psarcStream.Flush(); psarcStream.Seek(0, SeekOrigin.Begin); if (Path.GetExtension(saveFileName) != ".dat") { saveFileName += ".dat"; } using (var outputFileStream = File.Create(saveFileName)) { if (useCryptography) { RijndaelEncryptor.EncryptFile(psarcStream, outputFileStream, RijndaelEncryptor.DLCKey); } else { psarcStream.CopyTo(outputFileStream); } } } }
private static void UnpackPS3Package(string sourceFileName, string savePath, Platform platform) { var outputFilename = Path.Combine(PS3_WORKDIR, Path.GetFileName(sourceFileName)); if (!Directory.Exists(PS3_WORKDIR)) { Directory.CreateDirectory(PS3_WORKDIR); } foreach (var junk in Directory.EnumerateFiles(PS3_WORKDIR, "*.*")) { File.Delete(junk); } if (File.Exists(sourceFileName)) { File.Copy(sourceFileName, outputFilename, true); } else { throw new FileNotFoundException(String.Format("File '{0}' not found.", sourceFileName)); } var outputMessage = RijndaelEncryptor.DecryptPS3Edat(); if (File.Exists(outputFilename)) { File.Delete(outputFilename); } foreach (var fileName in Directory.EnumerateFiles(PS3_WORKDIR, "*.psarc.dat")) { using (var outputFileStream = File.OpenRead(fileName)) { ExtractPSARC(fileName, Path.GetDirectoryName(fileName), outputFileStream, new Platform(GamePlatform.PS3, GameVersion.None)); } if (File.Exists(fileName)) { File.Delete(fileName); } } var outName = Path.GetFileNameWithoutExtension(sourceFileName); var outputDir = Path.Combine(savePath, outName.Substring(0, outName.LastIndexOf(".")) + String.Format("_{0}", platform.platform.ToString())); foreach (var unpackedDir in Directory.EnumerateDirectories(PS3_WORKDIR)) { if (Directory.Exists(unpackedDir)) { if (Directory.Exists(outputDir)) { DirectoryExtension.SafeDelete(outputDir); } DirectoryExtension.Move(unpackedDir, outputDir); } } if (outputMessage.IndexOf("Decrypt all EDAT files successfully") < 0) { throw new InvalidOperationException("Rebuilder error, please check if .edat files are created correctly and see output below:" + Environment.NewLine + Environment.NewLine + outputMessage); } }
/// <summary> /// Unpack the specified File, returns unpacked dir. /// </summary> /// <param name="sourceFileName">Source file path.</param> /// <param name="savePath">Save path.</param> /// <param name="decodeAudio">If set to <c>true</c> decode audio.</param> /// <param name="overwriteSongXml">If set to <c>true</c> overwrite existing song (EOF) xml with SNG data</param> /// <param name="predefinedPlatform">Predefined source platform.</param> public static string Unpack(string sourceFileName, string savePath, bool decodeAudio = false, bool overwriteSongXml = false, Platform predefinedPlatform = null) { Platform platform = sourceFileName.GetPlatform(); if (predefinedPlatform != null && predefinedPlatform.platform != GamePlatform.None && predefinedPlatform.version != GameVersion.None) { platform = predefinedPlatform; } var fnameWithoutExt = Path.GetFileNameWithoutExtension(sourceFileName); if (platform.platform == GamePlatform.PS3) { fnameWithoutExt = fnameWithoutExt.Substring(0, fnameWithoutExt.LastIndexOf(".")); } var unpackedDir = Path.Combine(savePath, String.Format("{0}_{1}", fnameWithoutExt, platform.platform)); if (Directory.Exists(unpackedDir)) { DirectoryExtension.SafeDelete(unpackedDir); } var useCryptography = platform.version == GameVersion.RS2012; // Cryptography way is used only for PC in Rocksmith 1 switch (platform.platform) { case GamePlatform.Pc: case GamePlatform.Mac: if (platform.version == GameVersion.RS2014) { using (var inputStream = File.OpenRead(sourceFileName)) ExtractPSARC(sourceFileName, savePath, inputStream, platform); } else { using (var inputFileStream = File.OpenRead(sourceFileName)) using (var inputStream = new MemoryStream()) { if (useCryptography) { RijndaelEncryptor.DecryptFile(inputFileStream, inputStream, RijndaelEncryptor.DLCKey); } else { inputFileStream.CopyTo(inputStream); } ExtractPSARC(sourceFileName, savePath, inputStream, platform); } } break; case GamePlatform.XBox360: UnpackXBox360Package(sourceFileName, savePath, platform); break; case GamePlatform.PS3: UnpackPS3Package(sourceFileName, savePath, platform); break; case GamePlatform.None: throw new InvalidOperationException("Platform not found :("); } // DECODE AUDIO if (decodeAudio) { GlobalExtension.ShowProgress("Decoding Audio ...", 50); var audioFiles = Directory.EnumerateFiles(unpackedDir, "*.*", SearchOption.AllDirectories).Where(s => s.EndsWith(".ogg") || s.EndsWith(".wem")); foreach (var file in audioFiles) { var outputAudioFileName = Path.Combine(Path.GetDirectoryName(file), String.Format("{0}_fixed{1}", Path.GetFileNameWithoutExtension(file), ".ogg")); OggFile.Revorb(file, outputAudioFileName, Path.GetDirectoryName(Application.ExecutablePath), Path.GetExtension(file).GetWwiseVersion()); } //GlobalExtension.HideProgress(); } // for debugging //overwriteSongXml = false; // Extract XML from SNG and check it against the EOF XML (correct bass tuning from older toolkit/EOF xml files) if (platform.version == GameVersion.RS2014) { var sngFiles = Directory.EnumerateFiles(unpackedDir, "*.sng", SearchOption.AllDirectories).ToList(); var step = Math.Round(1.0 / (sngFiles.Count + 2) * 100, 3); double progress = 0; GlobalExtension.ShowProgress("Extracting XML from SNG ..."); foreach (var sngFile in sngFiles) { var xmlEofFile = Path.Combine(Path.GetDirectoryName(sngFile), String.Format("{0}.xml", Path.GetFileNameWithoutExtension(sngFile))); xmlEofFile = xmlEofFile.Replace(String.Format("bin{0}{1}", Path.DirectorySeparatorChar, platform.GetPathName()[1].ToLower()), "arr"); var xmlSngFile = xmlEofFile.Replace(".xml", ".sng.xml"); var arrType = ArrangementType.Guitar; if (Path.GetFileName(xmlSngFile).ToLower().Contains("vocal")) { arrType = ArrangementType.Vocal; } Attributes2014 att = null; if (arrType != ArrangementType.Vocal) { var jsonFiles = Directory.EnumerateFiles(unpackedDir, String.Format("{0}.json", Path.GetFileNameWithoutExtension(sngFile)), SearchOption.AllDirectories).FirstOrDefault(); if (!String.IsNullOrEmpty(jsonFiles) && jsonFiles.Any()) { att = Manifest2014 <Attributes2014> .LoadFromFile(jsonFiles).Entries.ToArray()[0].Value.ToArray()[0].Value; } } var sngContent = Sng2014File.LoadFromFile(sngFile, platform); using (var outputStream = new FileStream(xmlSngFile, FileMode.Create, FileAccess.ReadWrite)) { dynamic xmlContent = null; if (arrType == ArrangementType.Vocal) { xmlContent = new Vocals(sngContent); } else { xmlContent = new Song2014(sngContent, att); } xmlContent.Serialize(outputStream); } // correct old toolkit/EOF xml (tuning) issues ... sync with SNG data if (File.Exists(xmlEofFile) && !overwriteSongXml && arrType != ArrangementType.Vocal) { var eofSong = Song2014.LoadFromFile(xmlEofFile); var sngSong = Song2014.LoadFromFile(xmlSngFile); if (eofSong.Tuning != sngSong.Tuning) { eofSong.Tuning = sngSong.Tuning; var xmlComments = Song2014.ReadXmlComments(xmlEofFile); using (var stream = File.Open(xmlEofFile, FileMode.Create)) eofSong.Serialize(stream, true); Song2014.WriteXmlComments(xmlEofFile, xmlComments, customComment: "Synced with SNG file"); } File.Delete(xmlSngFile); } else { if (arrType != ArrangementType.Vocal) { Song2014.WriteXmlComments(xmlSngFile, customComment: "Generated from SNG file"); } File.Copy(xmlSngFile, xmlEofFile, true); File.Delete(xmlSngFile); } progress += step; GlobalExtension.UpdateProgress.Value = (int)progress; } //GlobalExtension.HideProgress(); } return(unpackedDir); }