static void Main(string[] args) { if (args.Length != 3 && args.Length != 4) { Usage(); Environment.Exit(ERROR_INVALID_USAGE); return; } FileType?type; bool additionalLobCompression = false; if (args[0].ToUpper() == "REPACK") { type = null; } else if (args[0].ToUpper() == "JH+LOB") { type = FileType.JH; additionalLobCompression = true; } else if (!Enum.TryParse <FileType>(args[0].ToUpper(), out FileType fileType)) { Console.WriteLine($"Invalid type '{args[0]}'"); Usage(); Environment.Exit(ERROR_INVALID_TYPE); return; } else { type = fileType; } if (type != FileType.JH && args.Length == 4) { Usage(); Environment.Exit(ERROR_INVALID_USAGE); return; } if (!File.Exists(args[1])) { if (type == null || type == FileType.JH || type == FileType.LOB || type == FileType.VOL1) { Console.WriteLine($"Source file '{args[1]}' not found."); Usage(); Environment.Exit(ERROR_SOURCE_FOUND); return; } else if (!Directory.Exists(args[1])) { Console.WriteLine($"Source file or directory '{args[1]}' not found."); Usage(); Environment.Exit(ERROR_SOURCE_FOUND); return; } } var writer = new DataWriter(); try { if (type == null) { try { var containerData = File.ReadAllBytes(args[1]); var container = new FileReader().ReadFile(Path.GetFileName(args[1]), containerData); var containerType = (FileType)container.Header; switch (containerType) { case FileType.JH: { var tempReader = new DataReader(containerData); var header = tempReader.ReadDword(); ushort key = (ushort)(((header & 0xffff0000u) >> 16) ^ (header & 0x0000ffffu)); containerData = Ambermoon.Data.Legacy.Compression.JH.Crypt(tempReader, key); tempReader = new DataReader(containerData); header = tempReader.ReadDword(); // read potential LOB/VOL1 header bool lob = header == (uint)FileType.LOB || header == (uint)FileType.VOL1; WriteFiles(writer, containerType, key, lob, container.Files.First().Value.ReadToEnd()); break; } case FileType.LOB: case FileType.VOL1: WriteFiles(writer, containerType, null, null, container.Files.First().Value.ReadToEnd()); break; default: WriteFiles(writer, containerType, null, null, container.Files.Select(f => f.Value.ReadToEnd()).ToArray()); break; } } catch { Console.WriteLine("Invalid source file for REPACK."); Environment.Exit(ERROR_INVALID_SOURCE_FILE); return; } } else if (type == FileType.JH) { string keyString; if (args.Length == 4) { keyString = args[3]; } else { Console.Write("Enter encrypt key (16 bit): "); keyString = Console.ReadLine(); } ushort key; try { if (keyString.StartsWith("0x", StringComparison.InvariantCultureIgnoreCase)) { key = ushort.Parse(keyString.Substring(2), System.Globalization.NumberStyles.HexNumber); } else { key = ushort.Parse(keyString); } } catch (FormatException) { Console.WriteLine("Invalid encrypt key. Provide a value from 0 to 65535 (or hex 0x0000 to 0xffff)."); Environment.Exit(ERROR_INVALID_JH_KEY); return; } WriteFiles(writer, FileType.JH, key, additionalLobCompression, File.ReadAllBytes(args[1])); } else if (type == FileType.LOB || type == FileType.VOL1) { WriteFiles(writer, type.Value, null, null, File.ReadAllBytes(args[1])); } else { if (File.Exists(args[1])) { WriteFiles(writer, type.Value, null, null, File.ReadAllBytes(args[1])); } else { WriteFiles(writer, type.Value, null, null, Directory.GetFiles(args[1]) .Select(file => File.ReadAllBytes(file)).ToArray()); } } try { var destinationDirectory = Path.GetDirectoryName(args[2]); if (!string.IsNullOrWhiteSpace(destinationDirectory)) { Directory.CreateDirectory(destinationDirectory); } var destinationStream = File.Create(args[2]); writer.CopyTo(destinationStream); } catch (Exception ex) { Console.WriteLine($"Error writing to destination '{args[2]}': {ex.Message}"); Console.WriteLine($" Ensure to specify a valid file path."); Console.WriteLine($" Ensure that you have write permission."); Console.WriteLine($" Ensure that the file is not opened in another program."); Environment.Exit(ERROR_WRITING_TO_DESTINATION); return; } Console.WriteLine("File was written successfully."); Environment.Exit(0); } catch (Exception ex) { Console.WriteLine("Internal error: " + ex.Message); Environment.Exit(ERROR_EXECUTION); } }