Browse Source

Add CSV to NEI converter

ghorsington 5 years ago
parent
commit
cd8cb33b2b
2 changed files with 55 additions and 37 deletions
  1. 30 20
      ArcToolkitCLI/Commands/Converters/NeiConverter.cs
  2. 25 17
      ArcToolkitCLI/Util/Encryption.cs

+ 30 - 20
ArcToolkitCLI/Commands/Converters/NeiConverter.cs

@@ -73,6 +73,19 @@ namespace ArcToolkitCLI.Commands.Converters
                 }
             }
 
+            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))
@@ -82,34 +95,31 @@ namespace ArcToolkitCLI.Commands.Converters
                     bw.Write(rows);
 
                     int totalLength = 0;
-                    foreach (var row in values)
+                    foreach (var encodedValue in encodedValues)
                     {
-                        for (int colIndex = 0; colIndex < cols; colIndex++)
-                        {
-                            bw.Write(totalLength);
-                            var strLen = colIndex < row.Length ? row[colIndex].Length : 0;
-                            bw.Write(strLen);
-                            totalLength += strLen;
-                        }
+                        var len = encodedValue.Length;
+                        if (len != 0)
+                            len++;
+
+                        bw.Write(encodedValue.Length == 0 ? 0 : totalLength);
+                        bw.Write(len);
+                        totalLength += len;
                     }
 
-                    foreach (var row in values)
+                    for (var i = 0; i < encodedValues.Length; i++)
                     {
-                        for (int colIndex = 0; colIndex < cols; colIndex++)
-                        {
-                            if(colIndex < row.Length)
-                                bw.Write(ShiftJisEncoding.GetBytes(row[colIndex]));
-                            bw.Write(0x00); // Add null terminator
-                        }
+                        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();
-                byte[] extraData = null;
-                if ((data.Length & 0xf) == 0) // If the data size is padded to 16 bytes, add a bit of junk data at the end
-                    extraData = new []{ (byte)0x00 };
-
-                File.WriteAllBytes(Path.Combine(Output, $"{nameNoExt}.nei"), Encryption.EncryptBytes(data, NEI_KEY, extraData: extraData));
+                File.WriteAllBytes(Path.Combine(Output, $"{nameNoExt}.nei"), Encryption.EncryptBytes(data, NEI_KEY));
             }
 
             return 0;

+ 25 - 17
ArcToolkitCLI/Util/Encryption.cs

@@ -8,7 +8,7 @@ namespace ArcToolkitCLI.Util
 {
     public static class Encryption
     {
-        private static Random Random = new Random();
+        private static readonly Random Random = new Random();
 
         public static byte[] ReadKeyFromFile(string filename)
         {
@@ -48,11 +48,11 @@ namespace ArcToolkitCLI.Util
 
         public static byte[] GenerateIV(byte[] ivSeed)
         {
-            uint[] seed = { 0x075BCD15, 0x159A55E5, 0x1F123BB5, BitConverter.ToUInt32(ivSeed, 0) ^ 0xBFBFBFBF };
+            uint[] seed = {0x075BCD15, 0x159A55E5, 0x1F123BB5, BitConverter.ToUInt32(ivSeed, 0) ^ 0xBFBFBFBF};
 
-            for (int i = 0; i < 4; i++)
+            for (var i = 0; i < 4; i++)
             {
-                uint n = seed[0] ^ (seed[0] << 11);
+                var n = seed[0] ^ (seed[0] << 11);
                 seed[0] = seed[1];
                 seed[1] = seed[2];
                 seed[2] = seed[3];
@@ -72,14 +72,14 @@ namespace ArcToolkitCLI.Util
             var ivSeed = new byte[4];
             Array.Copy(encryptedBytes, encryptedBytes.Length - 4, ivSeed, 0, 4);
 
-            byte[] iv = GenerateIV(ivSeed);
+            var iv = GenerateIV(ivSeed);
 
             using (var rijndael = new RijndaelManaged())
             {
                 rijndael.Padding = PaddingMode.None;
 
-                using (ICryptoTransform decryptor = rijndael.CreateDecryptor(key, iv))
-                using (var mem = new MemoryStream(encryptedBytes, 0, encryptedBytes.Length - extraDataSize - 5))
+                using (var decryptor = rijndael.CreateDecryptor(key, iv))
+                using (var mem = new MemoryStream(encryptedBytes, 0, encryptedBytes.Length - 5))
                 using (var stream = new CryptoStream(mem, decryptor, CryptoStreamMode.Read))
                 {
                     var output = new byte[encryptedBytes.Length - extraDataSize - 5];
@@ -91,30 +91,38 @@ namespace ArcToolkitCLI.Util
             }
         }
 
-        public static byte[] EncryptBytes(byte[] data, byte[] key, byte[] ivSeed = null, byte[] extraData = null)
+        public static byte[] EncryptBytes(byte[] data, byte[] key, byte[] ivSeed = null)
         {
-            if(extraData?.Length > 255)
-                throw new ArgumentException("Extra data cannot be larger than 255 bytes!", nameof(extraData));
-
             if (ivSeed == null)
                 ivSeed = BitConverter.GetBytes(Random.Next());
 
+            var iv = GenerateIV(ivSeed);
 
-            byte[] iv = GenerateIV(ivSeed);
+            byte[] extraData = null;
+            if ((data.Length & 0xf) != 0) // Rijndael requires padding to 16 bytes in order to encrypt
+            {
+                var newSize = (data.Length & 0xfffffff0) + 0x10;
+                extraData = new byte[newSize - data.Length];
+            }
 
             using (var rijndael = new RijndaelManaged())
             {
                 rijndael.Padding = PaddingMode.None;
 
-                using (ICryptoTransform encryptor = rijndael.CreateEncryptor(key, iv))
+                using (var encryptor = rijndael.CreateEncryptor(key, iv))
                 using (var mem = new MemoryStream())
                 {
                     using (var stream = new CryptoStream(mem, encryptor, CryptoStreamMode.Write))
+                    {
                         stream.Write(data, 0, data.Length);
-
-                    byte extraLength = (byte) (extraData?.Length ?? 0);
-                    mem.Write(new []{ (byte)(extraLength ^ ivSeed[0])}, 0, 1);
-                    mem.Write(ivSeed, 0, ivSeed.Length);
+                        if (extraData != null)
+                            stream.Write(extraData, 0, extraData.Length);
+                        stream.Flush();
+
+                        var extraLength = (byte) (extraData?.Length ?? 0);
+                        mem.Write(new[] {(byte) (extraLength ^ ivSeed[0])}, 0, 1);
+                        mem.Write(ivSeed, 0, ivSeed.Length);
+                    }
 
                     return mem.ToArray();
                 }