예제 #1
0
        /// <summary>
        /// Writes the newly imported data to the .dat for modifications.
        /// </summary>
        /// <param name="data">The data to be written.</param>
        /// <param name="modEntry">The modlist entry (if any) for the given file.</param>
        /// <param name="inModList">Is the item already contained within the mod list.</param>
        /// <param name="internalFilePath">The internal file path of the item being modified.</param>
        /// <param name="category">The category of the item.</param>
        /// <param name="itemName">The name of the item being modified.</param>
        /// <param name="lineNum">The line number of the existing mod list entry for the item if it exists.</param>
        /// <param name="dataFile">The data file to which we write the data</param>
        /// <returns>The new offset in which the modified data was placed.</returns>
        public int WriteToDat(List <byte> data, ModInfo modEntry, bool inModList, string internalFilePath,
                              string category, string itemName, int lineNum, XivDataFile dataFile)
        {
            var offset          = 0;
            var dataOverwritten = false;

            var index = new Index(_gameDirectory);

            var datNum = GetLargestDatNumber(dataFile);

            var modDatPath = _gameDirectory + "\\" + dataFile.GetDataFileName() + DatExtension + datNum;

            if (inModList)
            {
                datNum     = ((modEntry.modOffset / 8) & 0x0F) / 2;
                modDatPath = _gameDirectory + "\\" + modEntry.datFile + DatExtension + datNum;
            }
            else
            {
                var fileLength = new FileInfo(modDatPath).Length;

                // Creates a new Dat if the current dat is at the 2GB limit
                if (fileLength >= 2000000000)
                {
                    var newDatNum = CreateNewDat(dataFile);

                    modDatPath = _gameDirectory + "\\" + modEntry.datFile + DatExtension + newDatNum;
                }
                else
                {
                    // If it is an original dat and not a new empty mod dat file, then create a new mod dat file
                    // Note: If the file length is 2048, then it is a new empty mod dat file
                    if (IsOriginalDat(dataFile) && fileLength != 2048)
                    {
                        var newDatNum = CreateNewDat(dataFile);

                        modDatPath = _gameDirectory + "\\" + modEntry.datFile + DatExtension + newDatNum;
                    }
                }
            }

            // Checks to make sure the offsets in the mod list are not 0
            // If they are 0, something went wrong in the import proccess (Technically shouldn't happen)
            if (inModList)
            {
                if (modEntry.modOffset == 0)
                {
                    throw new Exception("The mod offset located in the mod list cannot be 0");
                }

                if (modEntry.originalOffset == 0)
                {
                    throw new Exception("The original offset located in the mod list cannot be 0");
                }
            }

            /*
             * If the item has been previously modified and the compressed data being imported is smaller or equal to the exisiting data
             *  replace the existing data with new data.
             */
            if (inModList && data.Count <= modEntry.modSize)
            {
                if (modEntry.modOffset != 0)
                {
                    var sizeDiff = modEntry.modSize - data.Count;

                    datNum     = ((modEntry.modOffset / 8) & 0x0F) / 2;
                    modDatPath = _gameDirectory + "\\" + modEntry.datFile + DatExtension + datNum;
                    var datOffsetAmount = 16 * datNum;

                    using (var bw = new BinaryWriter(File.OpenWrite(modDatPath)))
                    {
                        bw.BaseStream.Seek(modEntry.modOffset - datOffsetAmount, SeekOrigin.Begin);

                        bw.Write(data.ToArray());

                        bw.Write(new byte[sizeDiff]);
                    }

                    index.UpdateIndex(modEntry.modOffset, internalFilePath, dataFile);
                    index.UpdateIndex2(modEntry.modOffset, internalFilePath, dataFile);

                    offset = modEntry.modOffset;

                    dataOverwritten = true;
                }
            }
            else
            {
                var emptyLine = 0;

                /*
                 * If there is an empty entry in the modlist and the compressed data being imported is smaller or equal to the available space
                 *  write the compressed data in the existing space.
                 */

                foreach (var line in File.ReadAllLines(_modListDirectory.FullName))
                {
                    var emptyEntry = JsonConvert.DeserializeObject <ModInfo>(line);

                    if (emptyEntry.fullPath.Equals("") && emptyEntry.datFile.Equals(dataFile.GetDataFileName()))
                    {
                        if (emptyEntry.modOffset != 0)
                        {
                            var emptyLength = emptyEntry.modSize;

                            if (emptyLength > data.Count)
                            {
                                var sizeDiff = emptyLength - data.Count;

                                datNum     = ((emptyEntry.modOffset / 8) & 0x0F) / 2;
                                modDatPath = _gameDirectory + "\\" + emptyEntry.datFile + DatExtension + datNum;
                                var datOffsetAmount = 16 * datNum;

                                using (var bw = new BinaryWriter(File.OpenWrite(modDatPath)))
                                {
                                    bw.BaseStream.Seek(emptyEntry.modOffset - datOffsetAmount, SeekOrigin.Begin);

                                    bw.Write(data.ToArray());

                                    bw.Write(new byte[sizeDiff]);
                                }

                                var originalOffset = index.UpdateIndex(emptyEntry.modOffset, internalFilePath, dataFile) * 8;
                                index.UpdateIndex2(emptyEntry.modOffset, internalFilePath, dataFile);

                                if (inModList)
                                {
                                    originalOffset = modEntry.originalOffset;

                                    var replaceOriginalEntry = new ModInfo
                                    {
                                        category       = string.Empty,
                                        name           = "Empty Replacement",
                                        fullPath       = string.Empty,
                                        originalOffset = 0,
                                        modOffset      = modEntry.modOffset,
                                        modSize        = modEntry.modSize,
                                        datFile        = dataFile.GetDataFileName()
                                    };

                                    var oLines = File.ReadAllLines(_modListDirectory.FullName);
                                    oLines[lineNum] = JsonConvert.SerializeObject(replaceOriginalEntry);
                                    File.WriteAllLines(_modListDirectory.FullName, oLines);
                                }


                                var replaceEntry = new ModInfo
                                {
                                    category       = category,
                                    name           = itemName,
                                    fullPath       = internalFilePath,
                                    originalOffset = originalOffset,
                                    modOffset      = emptyEntry.modOffset,
                                    modSize        = emptyEntry.modSize,
                                    datFile        = dataFile.GetDataFileName()
                                };

                                var lines = File.ReadAllLines(_modListDirectory.FullName);
                                lines[emptyLine] = JsonConvert.SerializeObject(replaceEntry);
                                File.WriteAllLines(_modListDirectory.FullName, lines);

                                offset = emptyEntry.modOffset;

                                dataOverwritten = true;
                                break;
                            }
                        }
                    }
                    emptyLine++;
                }

                if (!dataOverwritten)
                {
                    using (var bw = new BinaryWriter(File.OpenWrite(modDatPath)))
                    {
                        bw.BaseStream.Seek(0, SeekOrigin.End);

                        while ((bw.BaseStream.Position & 0xFF) != 0)
                        {
                            bw.Write((byte)0);
                        }

                        var eof = (int)bw.BaseStream.Position + data.Count;

                        while ((eof & 0xFF) != 0)
                        {
                            data.AddRange(new byte[16]);
                            eof = eof + 16;
                        }

                        var datOffsetAmount = 16 * datNum;
                        offset = (int)bw.BaseStream.Position + datOffsetAmount;

                        if (offset != 0)
                        {
                            bw.Write(data.ToArray());
                        }
                        else
                        {
                            throw new Exception("There was an issue obtaining the offset to write to.");
                        }
                    }
                }
            }

            if (!dataOverwritten)
            {
                if (offset != 0)
                {
                    var oldOffset = index.UpdateIndex(offset, internalFilePath, dataFile) * 8;
                    index.UpdateIndex2(offset, internalFilePath, dataFile);

                    /*
                     * If the item has been previously modifed, but the new compressed data to be imported is larger than the existing data
                     * remove the data from the modlist, leaving the offset and size intact for future use
                     */
                    if (inModList && data.Count > modEntry.modSize)
                    {
                        oldOffset = modEntry.originalOffset;

                        var replaceEntry = new ModInfo
                        {
                            category       = string.Empty,
                            name           = string.Empty,
                            fullPath       = string.Empty,
                            originalOffset = 0,
                            modOffset      = modEntry.modOffset,
                            modSize        = modEntry.modSize,
                            datFile        = dataFile.GetDataFileName()
                        };

                        var lines = File.ReadAllLines(_modListDirectory.FullName);
                        lines[lineNum] = JsonConvert.SerializeObject(replaceEntry);
                        File.WriteAllLines(_modListDirectory.FullName, lines);
                    }

                    var entry = new ModInfo
                    {
                        category       = category,
                        name           = itemName,
                        fullPath       = internalFilePath,
                        originalOffset = oldOffset,
                        modOffset      = offset,
                        modSize        = data.Count,
                        datFile        = dataFile.GetDataFileName()
                    };

                    using (var modFile = new StreamWriter(_modListDirectory.FullName, true))
                    {
                        modFile.BaseStream.Seek(0, SeekOrigin.End);
                        modFile.WriteLine(JsonConvert.SerializeObject(entry));
                    }
                }
            }

            return(offset);
        }