|
1 | | -using FEZRepacker.Converter.FileSystem; |
| 1 | +using System.IO; |
| 2 | + |
| 3 | +using FEZRepacker.Converter.FileSystem; |
2 | 4 | using FEZRepacker.Converter.XNB; |
3 | 5 |
|
4 | 6 | namespace FEZRepacker.Interface |
@@ -173,12 +175,177 @@ public static void ListPackageContent(string pakPath) |
173 | 175 |
|
174 | 176 | public static void ConvertFromXNB(string inputPath, string outputPath) |
175 | 177 | { |
176 | | - Console.WriteLine("Feature currently not supported."); |
| 178 | + var xnbFilesToConvert = new List<string>(); |
| 179 | + |
| 180 | + if (Directory.Exists(inputPath)) |
| 181 | + { |
| 182 | + xnbFilesToConvert = Directory.GetFiles(inputPath, "*.xnb", SearchOption.AllDirectories).ToList(); |
| 183 | + Console.WriteLine($"Found {xnbFilesToConvert.Count()} XNB files in given directory."); |
| 184 | + } |
| 185 | + else if (File.Exists(inputPath)) |
| 186 | + { |
| 187 | + xnbFilesToConvert.Add(inputPath); |
| 188 | + if (Path.GetExtension(inputPath) != ".xnb") |
| 189 | + { |
| 190 | + throw new Exception("An input file must be an .XNB file."); |
| 191 | + } |
| 192 | + inputPath = Path.GetDirectoryName(inputPath) ?? ""; |
| 193 | + } |
| 194 | + else |
| 195 | + { |
| 196 | + throw new FileNotFoundException("Specified input path does not lead to any file or a directory"); |
| 197 | + } |
| 198 | + |
| 199 | + if (outputPath.Length == 0) |
| 200 | + { |
| 201 | + outputPath = inputPath; |
| 202 | + } |
| 203 | + if (!Directory.Exists(outputPath)) |
| 204 | + { |
| 205 | + Directory.CreateDirectory(outputPath); |
| 206 | + } |
| 207 | + |
| 208 | + var filesDone = 0; |
| 209 | + foreach (var xnbPath in xnbFilesToConvert) |
| 210 | + { |
| 211 | + Console.WriteLine($"({filesDone + 1}/{xnbFilesToConvert.Count}) {xnbPath}"); |
| 212 | + |
| 213 | + using var xnbStream = File.OpenRead(xnbPath); |
| 214 | + |
| 215 | + var converter = new XnbConverter(); |
| 216 | + var outputBundle = converter.Convert(xnbStream); |
| 217 | + var formatName = converter.HeaderValid ? converter.FileType.Name.Replace("Reader", "") : ""; |
| 218 | + if (converter.Converted) |
| 219 | + { |
| 220 | + outputBundle.MainExtension = converter.FormatConverter!.FileFormat; |
| 221 | + var storageTypeName = (outputBundle.Count > 1 ? "bundle" : "file"); |
| 222 | + Console.WriteLine($" Format {formatName} converted into {outputBundle.MainExtension} {storageTypeName}."); |
| 223 | + } |
| 224 | + else |
| 225 | + { |
| 226 | + Console.WriteLine(converter.HeaderValid ? $" Unknown format {formatName}." : $" Not a valid XNB file." + " Skipping."); |
| 227 | + continue; |
| 228 | + } |
| 229 | + |
| 230 | + var relativePath = Path.GetRelativePath(inputPath, xnbPath) |
| 231 | + .Replace("/", "\\") |
| 232 | + .Replace(".xnb", "", StringComparison.InvariantCultureIgnoreCase); |
| 233 | + outputBundle.BundlePath = Path.Combine(outputPath, relativePath + outputBundle.MainExtension); |
| 234 | + var outputDirectory = Path.GetDirectoryName(outputBundle.BundlePath) ?? ""; |
| 235 | + if (!Directory.Exists(outputDirectory)) |
| 236 | + { |
| 237 | + Directory.CreateDirectory(outputDirectory); |
| 238 | + } |
| 239 | + |
| 240 | + foreach (var outputFile in outputBundle) |
| 241 | + { |
| 242 | + using var fileOutputStream = File.Open(outputBundle.BundlePath + outputFile.Extension, FileMode.Create); |
| 243 | + outputFile.Data.CopyTo(fileOutputStream); |
| 244 | + } |
| 245 | + |
| 246 | + filesDone++; |
| 247 | + } |
177 | 248 | } |
178 | 249 |
|
179 | 250 | public static void ConvertIntoXNB(string inputPath, string outputPath) |
180 | 251 | { |
181 | | - Console.WriteLine("Feature currently not supported."); |
| 252 | + var fileNames = new string[0]; |
| 253 | + |
| 254 | + if (Directory.Exists(inputPath)) |
| 255 | + { |
| 256 | + fileNames = Directory.GetFiles(inputPath, "*.*", SearchOption.AllDirectories); |
| 257 | + Console.WriteLine($"Found {fileNames.Length} files."); |
| 258 | + } |
| 259 | + else if (File.Exists(inputPath)) |
| 260 | + { |
| 261 | + var fileName = Path.GetFileNameWithoutExtension(inputPath); |
| 262 | + inputPath = Path.GetDirectoryName(inputPath) ?? ""; |
| 263 | + fileNames = Directory.GetFiles(inputPath, $"{fileName}.*"); |
| 264 | + Console.WriteLine($"Found {fileNames.Length} linked files for a file bundle."); |
| 265 | + } |
| 266 | + else |
| 267 | + { |
| 268 | + throw new FileNotFoundException("Specified input path does not lead to any file or a directory"); |
| 269 | + } |
| 270 | + |
| 271 | + if (outputPath.Length == 0) |
| 272 | + { |
| 273 | + outputPath = inputPath; |
| 274 | + } |
| 275 | + if (!Directory.Exists(outputPath)) |
| 276 | + { |
| 277 | + Directory.CreateDirectory(outputPath); |
| 278 | + } |
| 279 | + |
| 280 | + // load and transform file list into bundles |
| 281 | + var fileList = new Dictionary<string, Stream>(); |
| 282 | + foreach (var filePath in fileNames) |
| 283 | + { |
| 284 | + var relativePath = Path.GetRelativePath(inputPath, filePath).Replace("/", "\\").ToLower(); |
| 285 | + fileList[relativePath] = File.OpenRead(filePath); |
| 286 | + } |
| 287 | + var fileBundles = FileBundle.BundleFiles(fileList); |
| 288 | + Console.WriteLine($"Converting {fileBundles.Count()} file bundles."); |
| 289 | + |
| 290 | + |
| 291 | + var xnbAssets = new Dictionary<(string Path, string Extension), Stream>(); |
| 292 | + |
| 293 | + // convert |
| 294 | + Console.WriteLine($"Converting {fileBundles.Count()} assets..."); |
| 295 | + var filesDone = 0; |
| 296 | + foreach (var fileBundle in fileBundles) |
| 297 | + { |
| 298 | + Console.WriteLine($"({filesDone + 1}/{fileBundles.Count}) {fileBundle.BundlePath}"); |
| 299 | + |
| 300 | + try |
| 301 | + { |
| 302 | + var deconverter = new XnbDeconverter(); |
| 303 | + |
| 304 | + var deconverterStream = deconverter.Deconvert(fileBundle); |
| 305 | + |
| 306 | + if (deconverter.Converted) |
| 307 | + { |
| 308 | + Console.WriteLine($" Format {fileBundle.MainExtension} deconverted into {deconverter.FormatConverter!.FormatName} XNB asset."); |
| 309 | + xnbAssets.Add((fileBundle.BundlePath, ".xnb"), deconverterStream); |
| 310 | + } |
| 311 | + else |
| 312 | + { |
| 313 | + Console.WriteLine($" Format {fileBundle.MainExtension} doesn't have a converter - packing asset as raw files."); |
| 314 | + |
| 315 | + foreach (var file in fileBundle) |
| 316 | + { |
| 317 | + file.Data.Seek(0, SeekOrigin.Begin); |
| 318 | + var ext = fileBundle.MainExtension + file.Extension; |
| 319 | + xnbAssets.Add((fileBundle.BundlePath, ext), file.Data); |
| 320 | + } |
| 321 | + } |
| 322 | + } |
| 323 | + catch (Exception ex) |
| 324 | + { |
| 325 | + Console.Error.WriteLine($"Unable to convert asset {fileBundle.BundlePath} - {ex.Message}"); |
| 326 | + } |
| 327 | + filesDone++; |
| 328 | + } |
| 329 | + |
| 330 | + Console.WriteLine($"Saving {xnbAssets.Count()} XNB assets..."); |
| 331 | + |
| 332 | + foreach (var assetRecord in xnbAssets) |
| 333 | + { |
| 334 | + var assetPath = assetRecord.Key.Path; |
| 335 | + var assetExtension = assetRecord.Key.Extension; |
| 336 | + var asset = assetRecord.Value; |
| 337 | + |
| 338 | + var assetOutputFullPath = Path.Combine(outputPath, $"{assetPath}{assetExtension}"); |
| 339 | + |
| 340 | + var directoryPath = Path.GetDirectoryName(assetOutputFullPath) ?? ""; |
| 341 | + if (directoryPath.Length > 0 && !Directory.Exists(directoryPath)) |
| 342 | + { |
| 343 | + Directory.CreateDirectory(directoryPath); |
| 344 | + } |
| 345 | + |
| 346 | + using var assetFile = File.Create(assetOutputFullPath); |
| 347 | + asset.CopyTo(assetFile); |
| 348 | + } |
182 | 349 | } |
183 | 350 |
|
184 | 351 | public static void AddToPackage(string inputPath, string outputPackagePath, string includePackagePath) |
|
0 commit comments