Exemplo n.º 1
0
        public UassetFile(byte[] data, string fullPath)
        {
            Fullpath = fullPath;
            Filename = Path.GetFileNameWithoutExtension(Fullpath);

            //Create a stream
            stream = new IOMemoryStream(new MemoryStream(data), true);

            stream.position = 0;

            var signature = stream.ReadUInt();

            // Check for the file's signature.
            if (signature != UNREAL_ASSET_MAGIC)
            {
                TKContext.LogError("The file provided is not a valid uasset file.");
                return;
            }

            Version = stream.ReadUInt();

            stream.ReadBytes(0x10);
            UnkOffset = stream.ReadInt();
            stream.ReadInt();

            PackageGroup = Encoding.ASCII.GetString(stream.ReadBytes(0x4));

            stream.ReadBytes(0x1);

            PackageFlags = stream.ReadUInt();
            NamesCount   = stream.ReadInt();
            NamesOffset  = stream.ReadInt();

            stream.ReadBytes(0x8);

            ExportsCount  = stream.ReadInt();
            ExportsOffset = stream.ReadInt();

            ImportsCount  = stream.ReadInt();
            ImportsOffset = stream.ReadInt();

            stream.ReadBytes(0x8);

            UnkOffset2 = stream.ReadInt();

            stream.ReadBytes(0x1C);

            NamesCount2 = stream.ReadInt();

            stream.ReadBytes(0x2C);

            UnkOffset3      = stream.ReadInt();
            EndOfFileOffset = stream.ReadInt();

            stream.ReadBytes(0x10);
            UnkOffset4 = stream.ReadInt();

            stream.position = NamesOffset;

            NamesTable = stream.ReadFNameEntries(NamesCount, UE4Version.UE4__4_14);


            for (int i = 0; i < NamesCount; i++)
            {
                TKContext.DebugLog("UassetFile", $"Name Table Entry {i}", NamesTable[i].Name, ConsoleColor.Yellow);
            }

            TKContext.LogInner("INFO", $"Uasset names count is {NamesCount}");

            //Starts directly after the name table. Assume we're already there
            ImportsTable = new FObjectImport[ImportsCount];
            for (int i = 0; i < ImportsCount; i++)
            {
                FObjectImport h = FObjectImport.ReadEntry(stream, this);
                ImportsTable[i] = h;
                DebugDump($"FObjectImport {i} @ {h.startPos}", ConsoleColor.Blue, "cType", h.coreType, "u1", h.unknown1.ToString(), "oType", h.objectType, "u2", h.unknown2.ToString(), "i", h.index.ToString(), "name", h.name, "u4", h.unknown4.ToString());
            }

            TKContext.LogInner("INFO", $"Uasset import table size is {ImportsCount}");

            //Starts directly after the referenced GameObject table. Assume we're already there
            ExportsTable = new FObjectExport[ExportsCount];
            for (int i = 0; i < ExportsCount; i++)
            {
                ExportsTable[i] = FObjectExport.ReadEntry(stream, this);
                DebugDump($"FObjectExport {i} @ {ExportsTable[i].entryLocation}", ConsoleColor.Magenta, "id", ExportsTable[i].id.ToString(), "u2", ExportsTable[i].unknown2.ToString(),
                          "u3", ExportsTable[i].unknown3.ToString(), "type", ExportsTable[i].type, "u4", ExportsTable[i].unknown4.ToString(), "u5", ExportsTable[i].unknown5.ToString(),
                          "length", ExportsTable[i].dataLength.ToString(), "location", ExportsTable[i].dataLocation.ToString(), "u6", ExportsTable[i].unknown6.ToString(), "u7",
                          ExportsTable[i].unknown7.ToString(), "u8", ExportsTable[i].unknown8.ToString(), "u9", ExportsTable[i].unknown9.ToString(), "u10", ExportsTable[i].unknown10.ToString(), "u11", ExportsTable[i].unknown11.ToString(),
                          "u12", ExportsTable[i].unknown12.ToString(), "u13", ExportsTable[i].unknown13.ToString(), "u14", ExportsTable[i].unknown14.ToString(), "u15", ExportsTable[i].unknown15.ToString(),
                          "u16", ExportsTable[i].unknown16.ToString(), "u17", ExportsTable[i].unknown17.ToString(), "u18", ExportsTable[i].unknown18.ToString(), "u19", ExportsTable[i].unknown19.ToString(),
                          "u20", ExportsTable[i].unknown20.ToString(), "u21", ExportsTable[i].unknown21.ToString(), "u22", ExportsTable[i].unknown22.ToString());
            }

            TKContext.LogInner("INFO", $"Uasset export table size is {ExportsCount}");

            using (MemoryStream ms = new MemoryStream())
            {
                stream.position = 0;
                stream.ms.CopyTo(ms);
                stream.Close();

                FileData = ms.ToArray();
            }
        }
Exemplo n.º 2
0
        public static UTexture2D GetTextureFromUAsset(UassetFile uassetFile)
        {
            /*if (uassetFile.UE4Version != UE4Version.UE4__4_14)
             *  throw new NotSupportedException($"Texture extraction from {uassetFile.UE4Version.ToString()} uasset files is not supported.");*/

            TKContext.LogInner("INFO", $"Attempting to get a texture from file {uassetFile.Filename}");

            try
            {
                FObjectExport export       = uassetFile.ExportsTable[0];
                EPixelFormat  ePixelFormat = EPixelFormat.PF_Unknown;

                int pfOffset = 0x0;

                // TODO: Simplify this mess.
                for (int i = 0; i < uassetFile.NamesTable.Length; i++)
                {
                    if (uassetFile.NamesTable[i].Name.ToUpper().StartsWith("PF_"))
                    {
                        if (!Enum.TryParse(uassetFile.NamesTable[i].Name, out ePixelFormat))
                        {
                            TKContext.LogError("Pixel Format is not supported.");
                            return(null);
                        }
                    }
                }

                UTexture2D uTexture2D = new UTexture2D();
                //uTexture2D.USerializedData = uSerializedData;
                uTexture2D.UassetFile = uassetFile;
                TKContext.LogInner("INFO", $"Attempting to find {ePixelFormat.ToString()}");
                pfOffset = ArrayExtensions.IndexOfPattern(export.data, Encoding.ASCII.GetBytes(ePixelFormat.ToString()));
                TKContext.LogInner("INFO", $"Pixel Format offset is 0x{pfOffset:X8}");

                if (pfOffset == int.MaxValue)
                {
                    TKContext.LogError("No texture was found.");
                    return(null);
                }

                uTexture2D.PFOffset = pfOffset;

                uTexture2D.PixelFormat  = ePixelFormat;
                uTexture2D.Height       = BitConverter.ToInt32(ArrayExtensions.GetBytesFromByteArray(export.data, pfOffset - UASSET_RELATIVE_PF_HEIGHT, 4), 0);
                uTexture2D.Width        = BitConverter.ToInt32(ArrayExtensions.GetBytesFromByteArray(export.data, pfOffset - UASSET_RELATIVE_PF_WIDTH, 4), 0);
                uTexture2D.UnknownValue = BitConverter.ToInt32(ArrayExtensions.GetBytesFromByteArray(export.data, pfOffset + 0x8, 4), 0);

                TKContext.LogInner("INFO", $"Texture resolution is {uTexture2D.Width}x{uTexture2D.Height}");

                int[] offsets = ArrayExtensions.Locate(export.data, BitConverter.GetBytes(PF_SEPERATOR));

                uTexture2D.MipMapCount = BitConverter.ToInt32(ArrayExtensions.GetBytesFromByteArray(export.data, offsets[0] - 0x4, 4), 0);
                uTexture2D.Mipmaps     = new List <FTexture2DMipMap>();

                TKContext.LogInner("INFO", $"Texture has {uTexture2D.MipMapCount} mipmaps");

                uTexture2D.FirstSeperatorOffset = offsets[0];

                for (int i = 0; i < uTexture2D.MipMapCount; i++)
                {
                    FTexture2DMipMap fTexture2DMipMap = new FTexture2DMipMap();

                    fTexture2DMipMap.UncompressedSize    = BitConverter.ToInt32(ArrayExtensions.GetBytesFromByteArray(export.data, offsets[i] + SEPERATOR_UNCOMPRESSED_SIZE_OFFSET, 4), 0);
                    fTexture2DMipMap.TextureUassetOffset = BitConverter.ToInt32(ArrayExtensions.GetBytesFromByteArray(export.data, offsets[i] + SEPERATOR_TEXTURE_START_OFFSET_OFFSET, 4), 0);
                    fTexture2DMipMap.UnknownValue        = BitConverter.ToInt32(ArrayExtensions.GetBytesFromByteArray(export.data, offsets[i] + SEPERATOR_UNKNOWN_OFFSET, 4), 0);
                    fTexture2DMipMap.Texture             = ArrayExtensions.GetBytesFromByteArray(export.data, offsets[i] + SEPERATOR_TEXTURE_DATA, fTexture2DMipMap.UncompressedSize);
                    fTexture2DMipMap.Width  = BitConverter.ToInt32(ArrayExtensions.GetBytesFromByteArray(export.data, offsets[i] + SEPERATOR_TEXTURE_DATA + fTexture2DMipMap.UncompressedSize, 4), 0);
                    fTexture2DMipMap.Height = BitConverter.ToInt32(ArrayExtensions.GetBytesFromByteArray(export.data, offsets[i] + SEPERATOR_TEXTURE_DATA + fTexture2DMipMap.UncompressedSize + 0x4, 4), 0);

                    uTexture2D.Mipmaps.Add(fTexture2DMipMap);

                    TKContext.LogInner("INFO", fTexture2DMipMap.ToString());
                }

                return(uTexture2D);
            }
            catch (Exception ex)
            {
                TKContext.LogException(ex.ToString());
                return(null);
            }
        }
Exemplo n.º 3
0
        public bool Read()
        {
            try
            {
                using (FileStream fs = new FileStream(FullPath, FileMode.Open, FileAccess.Read))
                {
                    using (BinaryReader br = new BinaryReader(fs))
                    {
                        // Go to 0x2C from the end of the file.
                        br.BaseStream.Seek(-END_FOOTER_POS, SeekOrigin.End);

                        var magic = br.ReadUInt32();

                        // Read the file's magic number and see if it's valid.
                        if (magic != FOOTER_MAGIC && !IgnoreMagicNumber)
                        {
                            // The + operator is for nice code readiblity so don't get upset.
                            TKContext.LogError($"The package: {FileName} contains an invalid magic number." +
                                               " Set IgnoreMagicNumber to false if you want the stream reader to ignore it.");

                            return(false);
                        }

                        PackageFooter footer = new PackageFooter();
                        footer.magic       = magic;
                        footer.version     = br.ReadUInt32();
                        footer.indexOffset = br.ReadUInt64();
                        footer.indexLength = br.ReadUInt64();
                        footer.indexHash   = br.ReadBytes(20);

                        br.BaseStream.Seek((long)footer.indexOffset, SeekOrigin.Begin);
                        var skipbytes = br.ReadUInt32();
                        br.BaseStream.Seek(skipbytes, SeekOrigin.Current);
                        FileCount = br.ReadUInt32();

                        FileEntries = new PackageFileEntry[FileCount];

                        for (int i = 0; i < FileEntries.Length; i++)
                        {
                            PackageFileEntry packageFileEntry = new PackageFileEntry();

                            packageFileEntry.fileNameLength = br.ReadUInt32();
                            packageFileEntry.fileName       = new string(br.ReadChars((int)(packageFileEntry.fileNameLength - 1)));

                            br.BaseStream.Seek(1, SeekOrigin.Current);

                            packageFileEntry.offset = br.ReadUInt64();
                            packageFileEntry.size1  = br.ReadUInt64();
                            packageFileEntry.size2  = br.ReadUInt64();
                            packageFileEntry.pad    = br.ReadUInt32();
                            packageFileEntry.sha1   = br.ReadBytes(20);
                            packageFileEntry.pad2   = br.ReadBytes(5);

#if DEBUG
                            TKContext.Log("PackFileEntry", i.ToString(), $"File name: {packageFileEntry.fileName} Offset: 0x{packageFileEntry.offset:X8} " +
                                          $"Size1: 0x{packageFileEntry.size1:X8} Size2: 0x{packageFileEntry.size2:X8} SHA1: {packageFileEntry.sha1.ToString()}", TKContext.LOG_TYPE_DEBUG, ConsoleColor.DarkCyan);
#endif

                            FileEntries[i] = packageFileEntry;
                        }

                        Footer = footer;
                    }
                }
                TKContext.LogInner("INFO", $"Loaded package {FileName}", ConsoleColor.Yellow);
                Array.Sort(FileEntries, (x, y) =>
                {
                    var lengthComp = Comparer <int> .Default.Compare((int)y.fileNameLength, (int)x.fileNameLength);
                    if (lengthComp == 0)
                    {
                        return(string.Compare(y.fileName, x.fileName));
                    }
                    return(lengthComp);
                });
                return(true);
            }
            catch (Exception ex)
            {
                TKContext.LogException(ex.ToString());
                return(false);
            }
        }