123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190 |
- using System;
- using System.Collections.Generic;
- using System.IO;
- using System.Linq;
- using System.Text;
- using ArcToolkitCLI.Commands.Options;
- using ArcToolkitCLI.Util;
- using CommandLine;
- namespace ArcToolkitCLI.Commands.Converters
- {
- [Verb("nei", HelpText = "Convert NEI files into CSV and back")]
- class NeiConverter : IConverterCommand, IInputOptions, IOutputOptions
- {
- private static readonly byte[] NEI_KEY = { 0xAA, 0xC9, 0xD2, 0x35, 0x22, 0x87, 0x20, 0xF2, 0x40, 0xC5, 0x61, 0x7C, 0x01, 0xDF, 0x66, 0x54 };
- private static readonly byte[] NEI_MAGIC = { 0x77, 0x73, 0x76, 0xFF };
- private static readonly Encoding ShiftJisEncoding = Encoding.GetEncoding(932);
- public int Run()
- {
- var files = Glob.EnumerateFiles(Input);
- if (!files.Any())
- {
- Console.WriteLine("No files specified. Run `convert help nei` for help.");
- return 0;
- }
- foreach (var file in files)
- {
- int result = 0;
- switch (file.Extension.ToLowerInvariant())
- {
- case ".nei":
- if ((result = ToCSV(file.FullName)) != 0)
- return result;
- break;
- case ".csv":
- if ((result = ToNei(file.FullName)) != 0)
- return result;
- break;
- default:
- Console.WriteLine($"File {file.FullName} is neither .nei nor .csv file. Skipping...");
- break;
- }
- }
- return 0;
- }
- int ToNei(string filePath)
- {
- string nameNoExt = Path.GetFileNameWithoutExtension(filePath);
- List<string[]> values = new List<string[]>();
- int cols = 0;
- int rows = 0;
- using (var tr = File.OpenText(filePath))
- {
- string line;
- while ((line = tr.ReadLine()) != null)
- {
- var colValues = line.Split(new []{ValueSeparator}, StringSplitOptions.None);
- if(colValues.Length == 0)
- continue;
- cols = Math.Max(cols, colValues.Length);
- values.Add(colValues);
- rows++;
- }
- }
- byte[][] encodedValues = new byte[rows * cols][];
- for (var rowIndex = 0; rowIndex < values.Count; rowIndex++)
- {
- var row = values[rowIndex];
- for (int colIndex = 0; colIndex < cols; colIndex++)
- {
- encodedValues[colIndex + rowIndex * cols] = colIndex < row.Length
- ? ShiftJisEncoding.GetBytes(row[colIndex])
- : new byte[0];
- }
- }
- using (var ms = new MemoryStream())
- {
- using (var bw = new BinaryWriter(ms))
- {
- bw.Write(NEI_MAGIC);
- bw.Write(cols);
- bw.Write(rows);
- int totalLength = 0;
- foreach (var encodedValue in encodedValues)
- {
- var len = encodedValue.Length;
- if (len != 0)
- len++;
- bw.Write(encodedValue.Length == 0 ? 0 : totalLength);
- bw.Write(len);
- totalLength += len;
- }
- for (var i = 0; i < encodedValues.Length; i++)
- {
- var encodedValue = encodedValues[i];
- if(encodedValue.Length == 0)
- continue;
- bw.Write(encodedValue);
- if (i != encodedValue.Length - 1)
- bw.Write((byte) 0x00);
- }
- }
- var data = ms.ToArray();
- File.WriteAllBytes(Path.Combine(Output, $"{nameNoExt}.nei"), Encryption.EncryptBytes(data, NEI_KEY));
- }
- return 0;
- }
- int ToCSV(string filePath)
- {
- string nameNoExt = Path.GetFileNameWithoutExtension(filePath);
- byte[] neiData = Encryption.DecryptBytes(File.ReadAllBytes(filePath), NEI_KEY);
- using (var ms = new MemoryStream(neiData))
- {
- using (var br = new BinaryReader(ms))
- {
- if (!br.ReadBytes(4).SequenceEqual(NEI_MAGIC))
- {
- Console.WriteLine($"File {filePath} is not a valid NEI file");
- return 1;
- }
- var cols = br.ReadUInt32();
- var rows = br.ReadUInt32();
- var strLengths = new int[cols * rows];
- for (int cell = 0; cell < cols * rows; cell++)
- {
- br.ReadInt32(); // Total length of all strings because why not
- strLengths[cell] = br.ReadInt32();
- }
- var values = new string[cols * rows];
- for (int cell = 0; cell < cols * rows; cell++)
- {
- var len = strLengths[cell];
- values[cell] = ShiftJisEncoding.GetString(br.ReadBytes(len), 0, Math.Max(len - 1, 0));
- }
- using (var tw = File.CreateText(Path.Combine(Output, $"{nameNoExt}.csv")))
- {
- for (int row = 0; row < rows; row++)
- {
- for (int col = 0; col < cols; col++)
- {
- tw.Write(values[row * cols + col]);
- if(col != cols - 1)
- tw.Write(ValueSeparator);
- }
- tw.WriteLine();
- }
- }
- }
- }
- return 0;
- }
- [Value(0, HelpText = "Input NEI or CSV files")]
- public IEnumerable<string> Input { get; set; }
- public string Output { get; set; }
- [Option('s', "separator", Default = ";", HelpText = "Value separator of the CSV file")]
- public string ValueSeparator { get; set; }
- }
- }
|