Exemplo n.º 1
0
        /// <summary>
        /// Returns array of bytes for file data section
        /// </summary>
        /// <param name="files"></param>
        /// <returns></returns>
        private byte[] _MakeFileData(IEnumerable <byte[]> files)
        {
            byte[] returnedData = new byte[0];

            if (files != null)
            {
                // Computing theorical size: current size of each file + up to 16 padding bytes per file
                int maxSize = 0;

                foreach (byte[] anotherFileData in files)
                {
                    maxSize += (anotherFileData.Length + 16);
                }

                byte[] tempData = new byte[maxSize];
                long   realDataSize;

                // Writing all files
                Section fileDataSection = _GetSection(SectionType.FileData);

                using (BinaryWriter writer = new BinaryWriter(new MemoryStream(tempData)))
                {
                    int index = 0;

                    foreach (byte[] anotherFileData in files)
                    {
                        // Updating packed file information
                        PackedFile correspondingFile = _FileList[index++];

                        correspondingFile.fileSize     = (uint)anotherFileData.Length;
                        correspondingFile.startAddress = (uint)writer.BaseStream.Position + fileDataSection.address;

                        // Data
                        writer.Write(anotherFileData);

                        // Padding...
                        if (index < _FileList.Count)
                        {
                            uint   paddingLength = _GetPaddingLength((uint)anotherFileData.Length, _SecondaryBlockSize);
                            byte[] padding       = new byte[paddingLength];
                            byte[] paddingString = String2.ToByteArray(_PADDING_SEQUENCE);

                            Array.Copy(paddingString, padding, paddingLength);
                            writer.Write(padding);
                        }
                    }

                    realDataSize = writer.BaseStream.Position;
                }

                // Putting real data into result
                returnedData = new byte[realDataSize];
                Array.Copy(tempData, 0, returnedData, 0, realDataSize);

                // Updating usableSize
                fileDataSection.usableSize = (uint)realDataSize;
            }

            return(returnedData);
        }
Exemplo n.º 2
0
        /// <summary>
        /// Convertit un fichier DDS en fichier 2DB. Utilise l'en-tête du fichier 2DB d'origine.
        /// </summary>
        /// <param name="original2DBFile">ancien fichier 2DB</param>
        /// <param name="sourceDDSFile">fichier DDS à convertir</param>
        /// <param name="target2DBFile">nouveau fichier 2DB à créer</param>
        /// <param name="newTextureName">if not null, allows to override texture name</param>
        /// <param name="mipmapCount">if not -1, forces mipmap count</param>
        public static void DDSTo2DB(string original2DBFile, string sourceDDSFile, string target2DBFile, string newTextureName, int mipmapCount)
        {
            // EVO_37 : 1. Récupérer les dimensions de la texture
            DDS ddsFile = (DDS)TduFile.GetFile(sourceDDSFile);

            DDS.TextureHeader ddsHeader = (DDS.TextureHeader)ddsFile.Header;
            uint ddsWidth       = ddsHeader.ddsd.dwWidth;
            uint ddsHeight      = ddsHeader.ddsd.dwHeight;
            uint ddsMipmapCount = ddsHeader.ddsd.dwMipMapCount;

            // 2. Prendre l'en-tête du fichier 2DB original
            _2DB old2DBFile = (_2DB)TduFile.GetFile(original2DBFile);

            _2DB.TextureHeader old2DBHeader = (_2DB.TextureHeader)old2DBFile.Header;

            // 3.  Mettre à jour les dimensions et nombre de mipmap
            old2DBHeader.height = (short)ddsHeight;
            old2DBHeader.width  = (short)ddsWidth;
            // BUG_58 : mipmap count in 2DB takes main texture into account (so always >= 1)

            // Mipmap count enforcement
            if (mipmapCount == KEEP_ORIGINAL_MIPMAP_COUNT)
            {
                old2DBHeader.bMipMapCount = old2DBHeader.bMipMapCountBis = (byte)(ddsMipmapCount + 1);
            }
            else
            {
                old2DBHeader.bMipMapCount = old2DBHeader.bMipMapCountBis = (byte)mipmapCount;
            }

            // 4. Calcul de bourrage / découpage éventuels
            long fileSize = _2DB.HEADER_SIZE + (ddsFile.Size - DDS.HEADER_SIZE) + _2DB.FINALIZATION_STRING.LongLength;

            // 5. Création du nouveau fichier et assemblage
            using (BinaryWriter writer = new BinaryWriter(new FileStream(target2DBFile, FileMode.Create, FileAccess.Write)))
            {
                // Mettre à jour la taille du fichier dans l'entete
                old2DBHeader.dwSize  = (uint)fileSize;
                old2DBHeader.dwSize2 = old2DBHeader.dwSize2Bis = (uint)(fileSize - 32);

                // Override texture name ?
                if (newTextureName != null)
                {
                    old2DBHeader.strName = String2.ToByteArray(Tools.NormalizeName(newTextureName));
                }

                // Ecriture de l'en-tête
                old2DBFile.Header = old2DBHeader;
                writer.Write(old2DBFile.HeaderData);

                // Data writing
                byte[] imageData = ddsFile.ImageData;

                writer.Write(imageData);

                // Finalization: REAL  (??)
                writer.Write(_2DB.FINALIZATION_STRING);
            }
        }
Exemplo n.º 3
0
        /// <summary>
        /// Writes header section into a byte array
        /// </summary>
        private byte[] _WriteHeaderSection()
        {
            // Max length = 64 bytes
            int dataLength = 64;

            byte[] tempData = new byte[dataLength];

            using (BinaryWriter dataWriter = new BinaryWriter(new MemoryStream(tempData)))
            {
                // TAG
                dataWriter.Write(String2.ToByteArray(_BANK_TAG));

                // 0 data
                dataWriter.Seek(0x8, SeekOrigin.Current);
                // Special flags
                dataWriter.Write(_SpecialFlag1);
                dataWriter.Write(_SpecialFlag2);

                // BNK file size
                dataWriter.Write(_GetTotalSize());

                // Packed content size (% 0x10)
                dataWriter.Write(PackedContentSize);

                // TODO 2x4 octets ....
                dataWriter.Write(_MainBlockSize);
                dataWriter.Write(_SecondaryBlockSize);

                // Packed files count
                dataWriter.Write(PackedFilesCount);

                // Year
                dataWriter.Write((uint)DateTime.Today.Year);

                // Section addresses
                uint fileSizeSectionAddress    = _GetSection(SectionType.FileSize).address;
                uint typeMappingSectionAddress = _GetSection(SectionType.TypeMapping).address;
                uint fileNameSectionAddress    = _GetSection(SectionType.FileName).address;
                uint fileOrderSectionAddress   = _GetSection(SectionType.FileOrder).address;
                uint fileDataSectionAddress    = _GetSection(SectionType.FileData).address;

                dataWriter.Write(fileSizeSectionAddress);
                dataWriter.Write(typeMappingSectionAddress);
                dataWriter.Write(fileNameSectionAddress);
                dataWriter.Write(fileOrderSectionAddress);
                dataWriter.Write(_Unknown);
                dataWriter.Write(fileDataSectionAddress);

                // Data size
                dataLength = (int)dataWriter.BaseStream.Position;
            }

            byte[] returnedData = new byte[dataLength];

            Array.Copy(tempData, returnedData, dataLength);

            return(returnedData);
        }
Exemplo n.º 4
0
        /// <summary>
        /// Utility method returning internal view name from a clean one + custom properties (if necessary)
        /// </summary>
        /// <param name="currentView"></param>
        /// <returns></returns>
        private static byte[] _SetViewName(View currentView)
        {
            byte[] returnedBytes = new byte[16];

            if (currentView.isValid)
            {
                string currentViewName = currentView.name;
                int    index           = 0;

                foreach (char anotherCharacter in currentViewName)
                {
                    returnedBytes[index] = (byte)anotherCharacter;
                    index++;
                }

                // Finalization of string
                returnedBytes[index] = (byte)'\0';
                index++;

                // Properties for custom camera, if there's enough place to store them...
                if (currentView.parentCameraId != 0 && index <= 8)
                {
                    // Parent id
                    string parentCameraId = currentView.parentCameraId.ToString();
                    byte[] idArray        = String2.ToByteArray(parentCameraId);

                    Array.Copy(idArray, 0, returnedBytes, index, idArray.Length);
                    index += idArray.Length;

                    // Separator
                    returnedBytes[index] = (byte)Tools.SYMBOL_VALUE_SEPARATOR;
                    index++;

                    // Parent type
                    string parentType = ((int)currentView.parentType).ToString();
                    byte[] typeArray  = String2.ToByteArray(parentType);

                    Array.Copy(typeArray, 0, returnedBytes, index, typeArray.Length);
                    index += typeArray.Length;
                }

                // Padding
                for (int i = index; i < 16; i++)
                {
                    returnedBytes[i] = 0xCD;
                }
            }

            return(returnedBytes);
        }
Exemplo n.º 5
0
        /// <summary>
        /// Writes specified file list node
        /// </summary>
        /// <param name="bnkWriter"></param>
        /// <param name="nodeToWrite"></param>
        /// <returns></returns>
        private static void _WriteFileNode(BinaryWriter bnkWriter, FileInfoNode nodeToWrite)
        {
            if (bnkWriter != null &&
                nodeToWrite != null &&
                bnkWriter.BaseStream.Position < bnkWriter.BaseStream.Length)
            {
                // Current node
                switch (nodeToWrite.type)
                {
                case FileInfoNodeType.File:
                    bnkWriter.Write((byte)nodeToWrite.name.Length);
                    break;

                case FileInfoNodeType.Folder:
                case FileInfoNodeType.ExtensionGroup:
                    byte nodeFlag = (byte)(_LIST_FOLDER_NODE_FLAG - nodeToWrite.name.Length);

                    bnkWriter.Write(nodeFlag);
                    bnkWriter.Write((byte)nodeToWrite.childNodes.Count);
                    break;
                }

                byte[] currentName = String2.ToByteArray(nodeToWrite.name);

                bnkWriter.Write(currentName);

                // Writing child nodes
                if (nodeToWrite.childNodes != null)
                {
                    foreach (FileInfoNode anotherChildNode in nodeToWrite.childNodes)
                    {
                        _WriteFileNode(bnkWriter, anotherChildNode);
                    }
                }
            }
        }
Exemplo n.º 6
0
        /// <summary>
        /// Generates specified section contents into a byte array
        /// </summary>
        /// <param name="type"></param>
        private byte[] _WriteSection(SectionType type)
        {
            Section sectionToWrite = _GetSection(type);

            byte[] returnedData = new byte[0];

            // Modification différente selon le type de section
            switch (type)
            {
            case SectionType.Header:
                #region HEADER
                sectionToWrite.data = _WriteHeaderSection();
                break;
                #endregion

            case SectionType.FileSize:
                #region INFOS SUR LE CONTENU
                sectionToWrite.data = _WriteContentInfoSection();
                break;
                #endregion

            case SectionType.TypeMapping:
                #region UNKNOWN SECTION
                // Original contents are kept
                break;
                #endregion

            case SectionType.FileName:
                #region LISTE DE NOMS DE FICHIERS
                // New! all data is now rewritten for this section
                sectionToWrite.data = _WriteFileListSection();
                break;
                #endregion

            case SectionType.FileOrder:
                #region ORDRE DES FICHIERS
                // Original contents are kept
                sectionToWrite.data = _WriteFileOrderSection();
                break;
                #endregion

            case SectionType.FileData:
                #region PACKED FILES
                // Contents already updated
                returnedData = sectionToWrite.data;
                break;
                #endregion

            default:
                throw new Exception("Writing " + type + " section is not supported here.");
            }

            if (SectionType.FileData == sectionToWrite.sectionType)
            {
                return(returnedData);
            }

            // New length update
            sectionToWrite.usableSize = (uint)sectionToWrite.data.Length;

            // Calcul du bourrage
            sectionToWrite.paddingSize =
                _GetPaddingLength(_PREDATA_LENGTH + (uint)sectionToWrite.data.Length, _MainBlockSize);

            // New size and checksum
            byte[] preData = new byte[_PREDATA_LENGTH];

            using (BinaryWriter preDataWriter = new BinaryWriter(new MemoryStream(preData)))
            {
                preDataWriter.Write((ushort)sectionToWrite.usableSize);
                preDataWriter.BaseStream.Seek(0x2, SeekOrigin.Current);
                preDataWriter.Write(sectionToWrite.Checksum);
            }

            // Padding calculation
            byte[] padding = new byte[0];

            if (type != SectionType.FileData)
            {
                string paddingString = _PADDING_SEQUENCE.Substring(0, (int)sectionToWrite.paddingSize);

                padding = String2.ToByteArray(paddingString);
            }

            // Writing
            int dataLength = 0;

            if (sectionToWrite.data != null)
            {
                dataLength = sectionToWrite.data.Length;
            }

            returnedData = new byte[preData.Length + dataLength + padding.Length];
            Array.Copy(preData, returnedData, preData.Length);

            if (dataLength != 0)
            {
                Array.Copy(sectionToWrite.data, 0, returnedData, preData.Length, dataLength);
            }

            Array.Copy(padding, 0, returnedData, preData.Length + dataLength, padding.Length);

            return(returnedData);
        }
Exemplo n.º 7
0
        /// <summary>
        /// Convertit un fichier DDS en fichier 2DB (EVO_37). Génère un nouvel en-tête.
        /// </summary>
        /// <param name="sourceDDSFile">fichier DDS à convertir</param>
        /// <param name="target2DBFile">nouveau fichier 2DB à créer</param>
        /// <param name="newTextureName">if not null, allows to override texture name</param>
        /// <param name="mipmapCount">if not -1, forces mipmap count</param>
        public static void DDSTo2DB(string sourceDDSFile, string target2DBFile, string newTextureName, int mipmapCount)
        {
            if (sourceDDSFile != null && target2DBFile != null)
            {
                DDS ddsFile = (DDS)TduFile.GetFile(sourceDDSFile);
                DDS.TextureHeader ddsHeader = (DDS.TextureHeader)ddsFile.Header;

                // Construction d'un fichier 2DB flambant neuf
                FileInfo           fi         = new FileInfo(target2DBFile);
                _2DB               new2DBFile = (_2DB)TduFile.GetFile(target2DBFile);
                _2DB.TextureHeader newHeader  = new _2DB.TextureHeader();
                string             picName;

                // Override texture name ?
                if (newTextureName != null)
                {
                    picName = Tools.NormalizeName(newTextureName);
                }
                else
                {
                    picName = Tools.NormalizeName(fi.Name.ToUpper());
                }

                // Valeurs connues
                newHeader.bID1    = String2.ToByteArray(_2DB.ID1_STRING);
                newHeader.bID2    = String2.ToByteArray(_2DB.ID2_STRING);
                newHeader.dwTwo   = 2;
                newHeader.dwZero1 = newHeader.dwZero2 = newHeader.dwZero3 = 0;
                newHeader.one     = 1;
                newHeader.height  = (short)ddsHeader.ddsd.dwHeight;
                newHeader.width   = (short)ddsHeader.ddsd.dwWidth;
                newHeader.strName = String2.ToByteArray(picName);

                // BUG_58 : mipmap count in 2DB takes main texture into account (so always >= 1)
                uint ddsMipmapCount = ddsHeader.ddsd.dwMipMapCount;

                // Mipmap count enforcement
                if (mipmapCount == KEEP_ORIGINAL_MIPMAP_COUNT)
                {
                    newHeader.bMipMapCount = newHeader.bMipMapCountBis = (byte)(ddsMipmapCount + 1);
                }
                else
                {
                    newHeader.bMipMapCount = newHeader.bMipMapCountBis = (byte)mipmapCount;
                }

                // Format & type (linked ??)
                byte format;
                uint type;

                switch (ddsHeader.ddsd.ddpfPixelFormat.dwFourCC)
                {
                case DDS.FORMAT_FOURCC_DXT1:
                    format = _2DB.FORMAT_ID_B1;
                    type   = _2DB.TYPE_DXT1;
                    break;

                case DDS.FORMAT_FOURCC_DXT5:
                    format = _2DB.FORMAT_ID_B5;
                    type   = _2DB.TYPE_DXT5;
                    break;

                case DDS.FORMAT_FOURCC_UNKNOWN:
                    format = _2DB.FORMAT_ID_BARGB8;
                    type   = _2DB.TYPE_ARGB8;
                    break;

                default:
                    // Log warning
                    Log.Warning("Unsupported texture format: '" + ddsHeader.ddsd.ddpfPixelFormat.dwFourCC +
                                "'. Treated as DXT5.");
                    // DXT5
                    format = _2DB.FORMAT_ID_B5;
                    type   = _2DB.TYPE_DXT5;
                    break;
                }
                newHeader.bFormat = format;
                newHeader.dwType  = type;

                // TODO A découvrir... et initialiser plus tard
                newHeader.dwFlags = 512;
                newHeader.dwUnk6  = 0;
                newHeader.dwUnk7  = 0;
                newHeader.bUnk2   = 0;
                newHeader.unk3    = 0;
                newHeader.dwUnk4  = 0;

                // Derniers calculs : taille du fichier
                uint _2dbSize = (uint)(_2DB.HEADER_SIZE + ddsFile.ImageData.Length + _2DB.FINALIZATION_STRING.Length);

                newHeader.dwSize  = _2dbSize;
                newHeader.dwSize2 = newHeader.dwSize2Bis = _2dbSize - 32;

                // Ecriture des sections
                try
                {
                    using (BinaryWriter writer = new BinaryWriter(new FileStream(target2DBFile, FileMode.Create, FileAccess.Write)))
                    {
                        // 1. En-tête
                        new2DBFile.Header = newHeader;
                        writer.Write(new2DBFile.HeaderData);

                        // 2. Données d'image
                        writer.Write(ddsFile.ImageData);

                        // Finalisation
                        writer.Write(_2DB.FINALIZATION_STRING);
                    }
                }
                catch (IOException ioe)
                {
                    Exception2.PrintStackTrace(ioe);
                    throw;
                }
            }
        }