예제 #1
0
        public void Load(BinaryReader r, BlenderFile file)
        {
            IsParsable = (
                Count > 0 && Size > 0 && Size == Count * file.SDNA.Structures[SDNAIndex].Size &&
                !Code.Equals("DNA1", StringComparison.Ordinal) &&
                !Code.Equals("ENDB", StringComparison.Ordinal)
                );

            OriginalData = r.ReadBytes(Size);             // original data is needed to resolve multidimensional pointers later

            if (!IsParsable)
            {
                GameDebugger.Log(LogLevel.VerboseDebug, "LOADING BYTES ONLY {0} size={1} addr=0x{2:X16} SDNA={3} count={4}", Code, Size, OldMemoryAddress, SDNAIndex, Count);
                return;
            }

            r.BaseStream.Position = DataPosition;
            ulong addr = OldMemoryAddress;

            Data = new BlenderFileObject[Count];
            GameDebugger.Log(LogLevel.VerboseDebug, "LOADING STRUCT {0} size={1} addr=0x{2:X16} SDNA={3} count={4}", Code, Size, OldMemoryAddress, SDNAIndex, Count);
            for (int i = 0; i < Count; i++)
            {
                Data[i] = new BlenderFileObject(r, file, addr, SDNAIndex);
                addr   += (ulong)file.SDNA.Structures[SDNAIndex].Size;
            }
        }
예제 #2
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="field"></param>
        /// <param name="file"></param>
        public void ResolvePointerField(BlenderFileObjectField field, BlenderFile file)
        {
            // TODO: add support for array of pointers
            BlenderPointer ptr = (BlenderPointer)field.Value;

            if (ptr.State == BlenderPointerState.Resolved)
            {
                field.Value = ptr.Value;
                return;
            }
            if (ptr.State == BlenderPointerState.Resolving || ptr.State == BlenderPointerState.Failed)
            {
                field.Value = null;
                return;
            }

            // This is needed to avoid infinite loops
            ptr.State   = BlenderPointerState.Resolving;
            field.Value = ptr;

            dynamic resolvedValue = null;

            // TODO: resolve the pointer

            field.Value = resolvedValue;
        }
예제 #3
0
 public BlenderFileBlock(BinaryReader r, BlenderFile file)
 {
     Code             = r.ReadFixedSizeString(4, Encoding.ASCII);
     Size             = r.ReadInt32(file.Header.Endianness);
     OldMemoryAddress = (file.Header.PointerSize == BlenderPointerSize.Ptr32) ? (ulong)r.ReadUInt32(file.Header.Endianness) : r.ReadUInt64(file.Header.Endianness);
     SDNAIndex        = r.ReadInt32(file.Header.Endianness);
     Count            = r.ReadInt32(file.Header.Endianness);
     DataPosition     = r.BaseStream.Position;
 }
예제 #4
0
 /// <summary>
 /// Processes pointers in loaded data
 /// </summary>
 /// <param name="r"></param>
 /// <param name="file"></param>
 public void Process(BlenderFile file)
 {
     if (!IsParsable)
     {
         return;
     }
     foreach (BlenderFileObject data in Data)
     {
         data.ResolvePointers(file);
     }
 }
예제 #5
0
        public void ResolvePointers(BlenderFile file)
        {
            WalkFields(true, (name, field) => {
                if (!field.IsPointer)
                {
                    return(true);
                }

                // ResolvePointerField(field, file);
                return(true);
            });
        }
예제 #6
0
        protected dynamic ReadFieldValue(BinaryReader r, BlenderFile file, BlenderInternalType loadType, string typeName, ulong address, int stringLength, int pointerDimensions, out int readSize)
        {
            if (pointerDimensions > 0)
            {
                readSize = (file.Header.PointerSize == BlenderPointerSize.Ptr64) ? 8 : 4;
                return(new BlenderPointer((file.Header.PointerSize == BlenderPointerSize.Ptr64) ? r.ReadUInt64() : (ulong)r.ReadUInt32(), pointerDimensions));
            }
            switch (loadType)
            {
            // case InternalType.Char: readSize = 1; return Encoding.ASCII.GetChars(r.ReadBytes(1))[0];
            case BlenderInternalType.Char: readSize = 1; return(r.ReadSByte());

            case BlenderInternalType.Byte: readSize = 1; return(r.ReadByte());

            case BlenderInternalType.Int16: readSize = 2; return(r.ReadInt16(file.Header.Endianness));

            case BlenderInternalType.UInt16: readSize = 2; return(r.ReadUInt16(file.Header.Endianness));

            case BlenderInternalType.Int32: readSize = 4; return(r.ReadInt32(file.Header.Endianness));

            case BlenderInternalType.UInt32: readSize = 4; return(r.ReadUInt32(file.Header.Endianness));

            case BlenderInternalType.Int64: readSize = 8; return(r.ReadInt64(file.Header.Endianness));

            case BlenderInternalType.UInt64: readSize = 8; return(r.ReadUInt64(file.Header.Endianness));

            case BlenderInternalType.Single: readSize = 4; return(r.ReadSingle(file.Header.Endianness));

            case BlenderInternalType.Double: readSize = 8; return(r.ReadDouble(file.Header.Endianness));

            case BlenderInternalType.String: readSize = stringLength; return(r.ReadFixedSizeString(stringLength, Encoding.ASCII));

            case BlenderInternalType.Method:
                readSize = (file.Header.PointerSize == BlenderPointerSize.Ptr64) ? 8 : 4;
                return((file.Header.PointerSize == BlenderPointerSize.Ptr64) ? r.ReadUInt64() : (ulong)r.ReadUInt32());

            case BlenderInternalType.Object:
                readSize = file.SDNA.StructureIndex[typeName].Size;
                return(new BlenderFileObject(r, file, address, typeName));
            }
            throw new Exception("Unexpected value type");
        }
예제 #7
0
        public BlenderFileObject(BinaryReader r, BlenderFile file, ulong address, string typeName)
        {
            ulong fieldAddress = address, valAddress;
            BlenderFileStructure structInfo = file.SDNA.StructureIndex[typeName];
            string fieldName;
            BlenderInternalType loadType;
            int dimStartIndex, stringLength, readSize, totalReadSize, i;

            string[] dimensionSizesText;
            int[]    dimensionSizes;
            object[] dimensionSizesForReflection;
            dynamic  val, v;
            int      pointerDimensions;

            m_Address  = address;
            m_Size     = structInfo.Size;
            m_TypeName = structInfo.Name;
            foreach (BlenderFileField fieldInfo in structInfo.Fields)
            {
                fieldName         = fieldInfo.Name;
                dimensionSizes    = null;
                stringLength      = 0;
                pointerDimensions = 0;

                if (fieldName.EndsWith("]", StringComparison.InvariantCulture))
                {
                    dimStartIndex = fieldName.IndexOf('[');
                    if (dimStartIndex <= 0)
                    {
                        throw new Exception(String.Format("Invalid field name format: {0}", fieldName));
                    }
                    dimensionSizesText = fieldName.Substring(dimStartIndex + 1, fieldName.Length - dimStartIndex - 2).Split(new String[] { "][" }, StringSplitOptions.None);
                    dimensionSizes     = new int[dimensionSizesText.Length];
                    for (i = dimensionSizesText.Length - 1; i >= 0; i--)
                    {
                        dimensionSizes[i] = int.Parse(dimensionSizesText[i]);
                    }
                    fieldName = fieldName.Substring(0, dimStartIndex);
                }

                while (pointerDimensions < fieldName.Length && fieldName[pointerDimensions] == '*')
                {
                    pointerDimensions++;
                }
                if (pointerDimensions > 0)
                {
                    fieldName = fieldName.Substring(pointerDimensions);
                }

                switch (fieldInfo.Type)
                {
                case "char":
                    if (dimensionSizes != null)
                    {
                        stringLength = dimensionSizes[dimensionSizes.Length - 1];
                        int[] newDimSizes = (dimensionSizes.Length > 1) ? new int[dimensionSizes.Length - 1] : null;
                        if (newDimSizes != null)
                        {
                            for (i = dimensionSizes.Length - 2; i >= 0; i--)
                            {
                                newDimSizes[i] = dimensionSizes[i];
                            }
                        }
                        dimensionSizes = newDimSizes;
                        loadType       = BlenderInternalType.String;
                    }
                    else
                    {
                        loadType = BlenderInternalType.Char;
                    }
                    break;

                case "uchar": loadType = BlenderInternalType.Byte; break;

                case "short": loadType = BlenderInternalType.Int16; break;

                case "ushort": loadType = BlenderInternalType.UInt16; break;

                case "int": loadType = BlenderInternalType.Int32; break;

                case "uint": loadType = BlenderInternalType.UInt32; break;

                case "int64_t": goto case "long";

                case "long": loadType = BlenderInternalType.Int64; break;

                case "uint64_t": goto case "ulong";

                case "ulong": loadType = BlenderInternalType.UInt64; break;

                case "float": loadType = BlenderInternalType.Single; break;

                case "double": loadType = BlenderInternalType.Double; break;

                default:
                    if (fieldName.StartsWith("(*", StringComparison.InvariantCulture) && fieldName.EndsWith(")()", StringComparison.InvariantCulture))
                    {
                        fieldName = fieldName.Substring(2, fieldInfo.Name.Length - 5);
                        loadType  = BlenderInternalType.Method;
                    }
                    else if (pointerDimensions > 0 || !fieldInfo.Type.Equals("void", StringComparison.Ordinal))
                    {
                        loadType = BlenderInternalType.Object;
                    }
                    else
                    {
                        throw new Exception("Unexpected non-pointer void");
                    }
                    break;
                }

                if (dimensionSizes == null)
                {
                    val = ReadFieldValue(r, file, loadType, fieldInfo.Type, fieldAddress, stringLength, pointerDimensions, out readSize);

                    if (loadType == BlenderInternalType.Method)
                    {
                        AddField(fieldName, loadType, fieldInfo.Type, fieldAddress, readSize, pointerDimensions > 0, null);
                    }
                    else
                    {
                        AddField(fieldName, loadType, fieldInfo.Type, fieldAddress, readSize, pointerDimensions > 0, val);
                    }

                    fieldAddress += (ulong)readSize;
                }
                else
                {
                    val = null;

                    dimensionSizesForReflection = new object[dimensionSizes.Length];
                    for (i = dimensionSizes.Length - 1; i >= 0; i--)
                    {
                        dimensionSizesForReflection[i] = dimensionSizes[i];
                    }

                    val = Activator.CreateInstance(typeof(object).MakeArrayType(dimensionSizes.Length), dimensionSizesForReflection);

                    int[] idx = new int[dimensionSizes.Length];

                    valAddress    = fieldAddress;
                    totalReadSize = 0;

                    do
                    {
                        v = ReadFieldValue(r, file, loadType, fieldInfo.Type, valAddress, stringLength, pointerDimensions, out readSize);

                        totalReadSize += readSize;
                        valAddress    += (ulong)readSize;

                        val.SetValue(v, idx);

                        // go to next possible index in array of current indexes
                        for (i = idx.Length - 1; i >= 0 && ++idx[i] >= dimensionSizes[i]; i--)
                        {
                            idx[i] = 0;
                        }
                    } while(i >= 0);

                    AddField(fieldName, loadType, fieldInfo.Type, fieldAddress, totalReadSize, pointerDimensions > 0, val);

                    fieldAddress = valAddress;
                }
            }
        }
예제 #8
0
 public BlenderFileObject(BinaryReader r, BlenderFile file, ulong address, int sdnaIndex)
     : this(r, file, address, file.SDNA.Structures[sdnaIndex].Name)
 {
 }
예제 #9
0
        public BlenderSDNAFileBlock(BinaryReader r, BlenderFile file)
        {
            int    i, j, idx, nameCount, typeCount, structCount, fieldCount;
            string id;
            long   basePos, pos;

            int[]                typeSizes;
            string[]             names, typeNames;
            BlenderFileStructure st;
            BlenderFileField     fld;

            Encoding ascii = Encoding.ASCII;

            basePos = r.BaseStream.Position;

            id = r.ReadFixedSizeString(4, ascii);
            if (!id.Equals("SDNA", StringComparison.Ordinal))
            {
                throw new Exception("SDNA block identifier expected");
            }

            id = r.ReadFixedSizeString(4, Encoding.ASCII);
            if (!id.Equals("NAME", StringComparison.Ordinal))
            {
                throw new Exception("NAME block identifier expected");
            }

            nameCount = r.ReadInt32(file.Header.Endianness);
            names     = new string[nameCount];

            for (i = 0; i < nameCount; i++)
            {
                names[i] = r.ReadZeroTerminatedString(ascii);
                GameDebugger.Log(LogLevel.VerboseDebug, "names[{0}]={1}", i, names[i]);
            }

            // align to 4 bytes
            pos = r.BaseStream.Position;
            if (((pos - basePos) & 3) != 0)
            {
                r.BaseStream.Position = basePos + ((pos - basePos) / 4 + 1) * 4;
            }

            id = r.ReadFixedSizeString(4, Encoding.ASCII);
            if (!id.Equals("TYPE", StringComparison.Ordinal))
            {
                throw new Exception("TYPE block identifier expected");
            }

            typeCount = r.ReadInt32(file.Header.Endianness);
            typeNames = new string[typeCount];
            typeSizes = new int[typeCount];

            for (i = 0; i < typeCount; i++)
            {
                typeNames[i] = r.ReadZeroTerminatedString(ascii);
                GameDebugger.Log(LogLevel.VerboseDebug, "typeNames[{0}]={1}", i, typeNames[i]);
            }

            // align to 4 bytes
            pos = r.BaseStream.Position;
            if (((pos - basePos) & 3) != 0)
            {
                r.BaseStream.Position = basePos + ((pos - basePos) / 4 + 1) * 4;
            }

            id = r.ReadFixedSizeString(4, Encoding.ASCII);
            if (!id.Equals("TLEN", StringComparison.Ordinal))
            {
                throw new Exception("TLEN block identifier expected");
            }

            for (i = 0; i < typeCount; i++)
            {
                typeSizes[i] = r.ReadInt16(file.Header.Endianness);
                GameDebugger.Log(LogLevel.VerboseDebug, "typeSizes[{0}]={1}", i, typeSizes[i]);
            }

            // align to 4 bytes
            pos = r.BaseStream.Position;
            if (((pos - basePos) & 3) != 0)
            {
                r.BaseStream.Position = basePos + ((pos - basePos) / 4 + 1) * 4;
            }

            id = r.ReadFixedSizeString(4, Encoding.ASCII);
            if (!id.Equals("STRC", StringComparison.Ordinal))
            {
                throw new Exception("STRC block identifier expected");
            }

            structCount    = r.ReadInt32(file.Header.Endianness);
            Structures     = new BlenderFileStructure[structCount];
            StructureIndex = new Dictionary <string, BlenderFileStructure>();
            for (i = 0; i < structCount; i++)
            {
                st       = new BlenderFileStructure();
                idx      = r.ReadInt16(file.Header.Endianness);
                st.Index = i;
                st.Name  = typeNames[idx];
                st.Size  = typeSizes[idx];

                fieldCount = r.ReadInt16(file.Header.Endianness);
                st.Fields  = new BlenderFileField[fieldCount];

                GameDebugger.Log(LogLevel.VerboseDebug, "struct #{0} {1} (size={2}, fields={3})", st.Index, st.Name, st.Size, fieldCount);

                for (j = 0; j < fieldCount; j++)
                {
                    fld          = new BlenderFileField();
                    idx          = r.ReadInt16(file.Header.Endianness);
                    fld.Type     = typeNames[idx];
                    fld.Size     = typeSizes[idx];
                    fld.Name     = names[r.ReadInt16(file.Header.Endianness)];
                    st.Fields[j] = fld;
                    GameDebugger.Log(LogLevel.VerboseDebug, "    {0} {1} (size={2})", fld.Type, fld.Name, fld.Size);
                }
                Structures[i] = st;
                StructureIndex.Add(st.Name, st);
            }
        }