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;
                }
            }
        }
Example #2
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);
            }
        }