Exemple #1
0
        /// <summary>
        /// Merges 2 tlk objects, saving the results in the specified tlk file. The merge tlk file
        /// is just added to the end of the source tlk file.  Unlike 2da merging, the merge tlk
        /// does not overwrite any entries in the source tlk.  Tlk entries are not row critical like
        /// 2da rows (since tlk strings are not saved in character files), so exact positioning of
        /// them is not as critical.
        /// </summary>
        /// <param name="source">The source tlk</param>
        /// <param name="merge">The merge tlk</param>
        /// <param name="outFile">The name of the output tlk file</param>
        /// <returns>The offset of the first entry of the merge tlk in the output file.  This offset
        /// can be used to fixup 2da entries that refer to the merge tlk.</returns>
        public static int MergeTlk(Tlk source, Tlk merge, string outFile)
        {
            /*
            // Open the output tlk.
            using (FileStream writer =
               new FileStream(outFile, FileMode.Create, FileAccess.Write, FileShare.None))
            {
                // Build a RawResRef array containing both the source and merge RawResRef arrays.  Then
                // loop through all of the merge entries and fixup the string offsets to point
                // past the source data to the merge data, which we will glue on the end of the
                // source data.
                RawResRef[] outResRefs = new RawResRef[source.resRefs.Length + merge.resRefs.Length];
                source.resRefs.CopyTo(outResRefs, 0);
                merge.resRefs.CopyTo(outResRefs, source.resRefs.Length);
                for (int i = source.resRefs.Length; i < outResRefs.Length; i++)
                {
                    if (0 != (outResRefs[i].flags & (int) ResRefFlags.textPresent))
                        outResRefs[i].offsetToString += source.stringBytes.Length;
                }

                // Build a header with a string count of all of the source + merge strings, then
                // write it out.
                TlkHeader headerOut = source.header;
                headerOut.stringCount += merge.header.stringCount;
                headerOut.stringOffset = headerSize + (outResRefs.Length * RawResRefSize);
                byte[] headerBytes = RawSerialize(headerOut);
                writer.Write(headerBytes, 0, headerBytes.Length);

                // Write the RawResRef data.
                for (int i = 0; i < outResRefs.Length; i++)
                {
                    byte[] bytes = RawSerialize(outResRefs[i]);
                    writer.Write(bytes, 0, bytes.Length);
                }

                // Write the source and merge string data out to the file.
                writer.Write(source.stringBytes, 0, source.stringBytes.Length);
                writer.Write(merge.stringBytes, 0, merge.stringBytes.Length);

                writer.Flush();
                writer.Close();
            }

            // Return the number of strings in the source tlk.  Since we glued the merge
            // tlk onto the end of the source tlk, this value will be the fixup value we need
            // to correct 2da tlk references.
            return source.header.stringCount;
            */
            return 0;
        }
        /// <summary>
        /// Attempts to resolve tlk file conflicts between the module tlk and any
        /// tlk's defined in the hifs.  It does this by attempting to build a
        /// new tlk file containing all of the tlk entries from all tlks.  If there
        /// are no overlapping entries in the tlks's then this will succeed and
        /// the name of the new tlk will be returned, if there are overlaps then
        /// this will fail and string.Empty will be returned.
        /// </summary>
        /// <param name="module">The module for which we are resolving conflicts</param>
        /// <param name="hifTlks">The list of tlk files from the HIFs being
        /// installed.</param>
        /// <returns>The name of the merge tlk file, or string.Empty if a merge tlk
        /// could not be generated.</returns>
        public string ResolveTlkConflict(Erf module, string[] hifTlks)
        {
            try
            {
                // Let the user know we are building a merge tlk.
                progress.SetMessage("Building merge tlk for module\n'{0}'.",
                    Path.GetFileNameWithoutExtension(module.FileName));

                // Create an array to hold all of the tlk objects.
                Tlk[] tlks = new Tlk[hifTlks.Length];

                // Load all of the tlk's.
                for (int i = 0; i < hifTlks.Length; i++)
                    tlks[i] = Tlk.LoadTlk(NWNInfo.GetFullFilePath(hifTlks[i]));

                // Generate the name of the new tlk file.
                string newTlkFileName = GetFileName(module, "tlk");
                if (null == newTlkFileName)
                    throw new NWNException("Cannot create new tlk file for module {0}", module.FileName);

                // Get the largest entry count in all of the tlk files, we cannot move any of the tlk
                // entries from where they are so the new tlk file will have as many entries as the
                // largest source tlk file.
                int count = 0;
                foreach (Tlk tlk in tlks)
                    if (tlk.Count > count) count = tlk.Count;

                // Create a new tlk file and add all of the entries from all of the tlk files
                // to it.
                Tlk newTlk = new Tlk(count);
                for (int i = 0; i < count; i++)
                {
                    // Check to see which tlk file contains this entry.  If multiple tlk
                    // files contain this entry we cannot merge the tlk's
                    Tlk.TlkEntry entry = null;
                    foreach (Tlk tlk in tlks)
                    {
                        // Ignore empty entries.
                        if (i >= tlk.Count || tlk.IsEmpty(i)) continue;

                        // If we haven't gotten an entry for this row yet
                        // then save this entry.  If we have then we cannot
                        // do the merge.
                        if (null == entry)
                            entry = tlk[i];
                        else
                        {
                            // Check to see if the data in two entries is the same.
                            // If it is then both tlk files have the same string
                            // data in the entry and we can still do the merge.  This
                            // is most likely to happen at index 0 where many tlk
                            // files place "Bad Strref".
                            if (0 == string.Compare(entry.Text, tlk[i].Text, true, CultureInfo.InvariantCulture))
                                continue;

                            throw new InvalidOperationException();
                        }
                    }

                    // Save the entry in our new tlk file.
                    if (null != entry) newTlk[i] = entry;
                }

                // Save the new tlk file and return it's file name.
                newTlk.SaveAs(NWN.NWNInfo.GetFullFilePath(newTlkFileName));
                return newTlkFileName;
            }
            catch (InvalidOperationException)
            {
                // If an error occurs return string.Empty to indicate we couldn't generate
                // a merge tlk.
                return string.Empty;
            }
        }
Exemple #3
0
        /// <summary>
        /// Creates a Tlk object for the specified tlk file.
        /// </summary>
        /// <param name="fileName">The tlk file</param>
        /// <returns>A Tlk object representing the tlk file</returns>
        public static Tlk LoadTlk(string fileName)
        {
            // Open the tlk file.
            Tlk tlk = new Tlk();
            using (FileStream reader =
                new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
            {
                // Save the name of the tlk file.
                FileInfo info = new FileInfo(fileName);
                tlk.name = info.Name;

                // Read the header and decode it.
                byte[] buffer = new byte[Tlk.headerSize];
                if (reader.Read(buffer, 0, buffer.Length) != buffer.Length)
                    ThrowException("Tlk file {0} is corrupt", fileName);
                tlk.DeserializeHeader(buffer);

                // Do a reality check on the tlk file.
                if (tlk.header.fileType != tlkFile)
                    ThrowException("{0} is not a tlk file", fileName);
                if (tlk.header.fileVersion != tlkVersion)
                    ThrowException("{0} is an unsupported tlk file", fileName);

                // Read the RawResRef array and decode it.
                int size = tlk.header.stringCount * Tlk.RawResRefSize;
                buffer = new byte[size];
                if (reader.Read(buffer, 0, buffer.Length) != buffer.Length)
                    ThrowException("Tlk file {0} is corrupt", fileName);
                tlk.DeserializeRawResRefs(buffer);

                // Read the raw string data.
                buffer = new byte[reader.Length - tlk.header.stringOffset];
                if (reader.Read(buffer, 0, buffer.Length) != buffer.Length)
                    ThrowException("Tlk file {0} is corrupt", fileName);

                // Load the strings from the raw bytes into our string array.
                tlk.strings = new string[tlk.header.stringCount];
                for (int i = 0; i < tlk.header.stringCount; i++)
                    tlk.strings[i] = tlk.GetStringFromBuffer(buffer, i);
            }

            return tlk;
        }