#region CPL License /* Nuclex Framework Copyright (C) 2002-2007 Nuclex Development Labs This library is free software; you can redistribute it and/or modify it under the terms of the IBM Common Public License as published by the IBM Corporation; either version 1.0 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the IBM Common Public License for more details. You should have received a copy of the IBM Common Public License along with this library */ #endregion using System; using System.Collections.Generic; using System.IO; using SevenZip.Compression.LZMA; using Nuclex.Support; using Nuclex.Support.Parsing; namespace Nuclex.Game.ContentCompressor { /// /// Contains the main program code for the nuclex game content compression utility /// /// /// /// Valid command lines /// - Nuclex.Game.ContentCompressor Content\*.* /// - Nuclex.Game.ContentCompressor -package:Content.lzma Content\*.* /// /// public static class Program { /// Program entry point /// Not used public static void Main(string[] arguments) { CommandLine commandLine = CommandLine.Parse(Environment.CommandLine); if(commandLine.HasArgument("help") || commandLine.Arguments.Count <= 1) { displayHelp(); return; } // Obtain the current working directory string cwd = System.Environment.CurrentDirectory; // Scan any folders the user has specified for .xnb assets List files = determineFilesToCompress(commandLine); // If the '--package' argument was provided, build a single big package // containing all the content files if(commandLine.HasArgument("package")) { string packagePath = getCommandLineOption(commandLine, "package"); if(packagePath == null) { Console.WriteLine("No package file specified"); return; } Console.WriteLine(string.Format("Creating package file {0}...", packagePath)); LzmaPackageBuilder.Build(packagePath, transformToPackageFile(cwd, files)); } else { // Otherwise, compress each file individually for(int index = 0; index < files.Count; ++index) { LzmaContentCompressor.CompressContentFile(files[index]); } } // After successful compression, delete the input files if the user so requested // by specifying the '--delete' argument. if(commandLine.HasArgument("delete")) { Console.WriteLine("Deleting input files..."); for(int index = 0; index < files.Count; ++index) { File.Delete(files[index]); } } Console.WriteLine( string.Format( "Successfully compressed {0} file{1}", files.Count, (files.Count == 1) ? "" : "s" ) ); } /// Displays syntax help for the application private static void displayHelp() { Console.WriteLine("Nuclex LZMA Content Compressor for XNA"); Console.WriteLine(); Console.WriteLine("Syntax: Compress [/package:] [/delete] {@filelist(s)|file(s)}"); Console.WriteLine(); Console.WriteLine("/package: Will compress the files into a package, similar to"); Console.WriteLine(" to a .7z archive. Otherwise, files will be compressed"); Console.WriteLine(" individually"); Console.WriteLine(); Console.WriteLine("/delete Deletes the original files after they were"); Console.WriteLine(" successfully compressed. Useful for scripting."); Console.WriteLine(); Console.WriteLine("@filelist Opens the file 'filelist' as a text file and reads"); Console.WriteLine(" the files to be compressed from this text file"); Console.WriteLine(); Console.WriteLine("file File or wildcards of files that will be compressed"); } /// Builds a list of the files that should be compressed /// /// Command line from which to take the paths and masks that will be compressed /// /// A list of all files to compress with the absolute paths private static List determineFilesToCompress(CommandLine commandLine) { List files = new List(); // Search for any loose values on the command line for(int index = 1; index < commandLine.Arguments.Count; ++index) { if(commandLine.Arguments[index].Name == null) { string value = commandLine.Arguments[index].Value; // if this is a directory, recursively add all files in the directory if(value.StartsWith("@")) { files.AddRange(allLinesInFile(value.Substring(1))); } else if(Directory.Exists(value)) { files.AddRange(allFiles(value, "*.*")); } else { // otherwise, assume it's a file mask string directory = Path.GetDirectoryName(value); string mask = Path.GetFileName(value); files.AddRange(allFiles(directory, mask)); } } } return files; } /// Enumerates over all lines in a text file /// Path to a text file whose lines will be enumerated /// An enumerable list of strings for the lines in the file private static IEnumerable allLinesInFile(string path) { using( FileStream stream = new FileStream( path, FileMode.Open, FileAccess.Read, FileShare.Read ) ) { StreamReader reader = new StreamReader(stream); string line; while((line = reader.ReadLine()) != null) { yield return line; } } } /// Retrieves the value of an option on the command line /// Command line the option will be retrieved from /// Name of the option that will be retrieved /// The value assigned to the specified option private static string getCommandLineOption( CommandLine commandLine, string optionName ) { for(int index = 0; index < commandLine.Arguments.Count; ++index) { if(commandLine.Arguments[index].Name == optionName) { return commandLine.Arguments[index].Value; } } return null; } /// Transforms a list of absolute paths into a list of package files /// /// Base path to which the packaged files' names will be relative /// /// List of absolute paths to be transformed /// An enumerable list of package files private static IEnumerable transformToPackageFile( string basePath, IEnumerable files ) { foreach(string file in files) { string name = Path.ChangeExtension(file, null); name = PathHelper.MakeRelative(basePath, Path.GetFullPath(name)); yield return new LzmaPackageBuilder.PackageFile(file, name); } } /// /// Returns an enumerator that iterates over all files that match the specified mask /// in a given directory and its subdirectories. /// /// Directory to begin the enumeration in /// Mask of files to search for /// An enumerator that iterates of all files matching the mask private static IEnumerable allFiles(string directory, string mask) { Queue remainingDirectories = new Queue(); remainingDirectories.Enqueue(directory); while(remainingDirectories.Count > 0) { string searchedDirectory = remainingDirectories.Dequeue(); if(searchedDirectory == string.Empty) { searchedDirectory = "."; } string[] subDirectories = Directory.GetDirectories(searchedDirectory); foreach(string subDirectory in subDirectories) remainingDirectories.Enqueue(subDirectory); string[] contentFiles = Directory.GetFiles(searchedDirectory, mask); foreach(string contentFile in contentFiles) yield return contentFile; } } } } // namespace Nuclex.Game.ContentCompressor