Example #1
0
        public static T ReadFromMiloObjectBytes <T>(this MiloSerializer serializer, MiloObjectBytes entry) where T : ISerializable, new()
        {
            using (var ms = new MemoryStream(entry.Data))
            {
                var obj = serializer.ReadFromStream <T>(ms);
                (obj as MiloObject).Name = entry.Name;

                return(obj);
            }
        }
        protected MiloObject ParseDirEntryAsBlob(AwesomeReader ar, MiloObjectDir dir, string dirType)
        {
            // Reads data as a byte array
            var entrySize  = GuessEntrySize(ar);
            var entryBytes = new MiloObjectBytes(dirType)
            {
                Name = dir.Name
            };

            entryBytes.Data = ar.ReadBytes((int)entrySize);

            ar.BaseStream.Position += 4;
            return(entryBytes);
        }
        public override void ReadFromStream(AwesomeReader ar, ISerializable data)
        {
            var    dir = data as MiloObjectDir;
            int    version = ReadMagic(ar, data);
            string dirType = null, dirName = null;

            dir.Extras.Clear(); // Clears for good measure

            if (version >= 24)
            {
                // Parses directory type/name
                dirType = ar.ReadString();
                dirName = FileHelper.SanitizePath(ar.ReadString());

                // Skip string hash related values (re-calculated during repack)
                ar.BaseStream.Position += 8;
            }

            int entryCount = ar.ReadInt32();
            var entries    = Enumerable.Range(0, entryCount).Select(x => new
            {
                Type = ar.ReadString(),
                Name = SanitizeFileName(FileHelper.SanitizePath(ar.ReadString()))
            }).ToArray();

            var is360Gh2 = Is360GH2();

            if (version == 10)
            {
                // Parses external resource paths?
                entryCount = ar.ReadInt32();

                // Note: Entry can be empty
                var external = Enumerable.Range(0, entryCount)
                               .Select(x => ar.ReadString())
                               .ToList();

                dir.Extras.Add("ExternalResources", external);
            }
            else if (version == 25 && !is360Gh2)
            {
                var        startOffset = ar.BaseStream.Position;
                MiloObject dirEntry;

                try
                {
                    dirEntry = dirType switch
                    {
                        "ObjectDir" => ParseObjectDir(ar, dir),
                        "WorldDir" => ParseWorldDir(ar, dir),
                        "RndDir" => ParseRndDir(ar, dir),
                        "SynthDir" => ParseSynthDir(ar, dir),
                        _ => ParseDirEntryAsBlob(ar, dir, dirType)
                    };
                }
                catch
                {
                    ar.BaseStream.Seek(startOffset, SeekOrigin.Begin);
                    dirEntry = ParseDirEntryAsBlob(ar, dir, dirType);
                }

                dirEntry.Name = dirName;
                dir.Extras.Add("DirectoryEntry", dirEntry);
            }
            else if (version >= 24)
            {
                // GH2 and above
                var dirEntry = ParseDirEntryAsBlob(ar, dir, dirType);

                dirEntry.Name = dirName;
                dir.Extras.Add("DirectoryEntry", dirEntry);
            }


            foreach (var entry in entries)
            {
                var entryOffset = ar.BaseStream.Position;
                // TODO: De-serialize entries

                //try
                //{
                //    var miloEntry = ReadFromStream(ar.BaseStream, entry.Type);
                //    miloEntry.Name = entry.Name;

                //    dir.Entries.Add(miloEntry);
                //    ar.BaseStream.Position += 4; // Skips padding
                //    continue;
                //}
                //catch (Exception ex)
                //{
                //    // Catch exception and log?
                //    ar.Basestream.Position = entryOffset; // Return to start
                //}

                // Reads data as a byte array
                var entrySize  = GuessEntrySize(ar);
                var entryBytes = new MiloObjectBytes(entry.Type)
                {
                    Name = entry.Name
                };
                entryBytes.Data = ar.ReadBytes((int)entrySize);

                dir.Entries.Add(entryBytes);
                ar.BaseStream.Position += 4;
            }
        }
        public override void ReadFromStream(AwesomeReader ar, ISerializable data)
        {
            var    dir = data as MiloObjectDir;
            int    version = ReadMagic(ar, data);
            string dirType = null, dirName = null;

            dir.Extras.Clear(); // Clears for good measure

            if (version >= 24)
            {
                // Parses directory type/name
                dirType = ar.ReadString();
                dirName = FileHelper.SanitizePath(ar.ReadString());

                //ar.BaseStream.Position += 8; // Skips string count + total length
                dir.Extras.Add("Num1", ar.ReadInt32());
                dir.Extras.Add("Num2", ar.ReadInt32());
            }

            int entryCount = ar.ReadInt32();
            var entries    = Enumerable.Range(0, entryCount).Select(x => new
            {
                Type = ar.ReadString(),
                Name = FileHelper.SanitizePath(ar.ReadString())
            }).ToArray();

            if (version == 10)
            {
                // Parses external resource paths?
                entryCount = ar.ReadInt32();

                // Note: Entry can be empty
                var external = Enumerable.Range(0, entryCount)
                               .Select(x => ar.ReadString())
                               .ToList();

                dir.Extras.Add("ExternalResources", external);
            }
            else if (version == 25 && dirType == "ObjectDir")
            {
                // Hack for project 9
                var dirEntry = new MiloObjectDirEntry()
                {
                    Name = dirName
                };
                dirEntry.Version     = ar.ReadInt32();
                dirEntry.SubVersion  = ar.ReadInt32();
                dirEntry.ProjectName = ar.ReadString();

                // Skip matrices + constants
                var matCount = ar.ReadInt32(); // Usually 7
                ar.BaseStream.Position += (matCount * 48) + 9;

                // Read imported milos
                var importedMiloCount = ar.ReadInt32();
                dirEntry.ImportedMiloPaths = Enumerable.Range(0, importedMiloCount)
                                             .Select(x => ar.ReadString())
                                             .ToArray();

                // Boolean, true when sub directory?
                ar.ReadBoolean();

                // Sub directory names seem to be in reverse order of serialization...
                var subDirCount = ar.ReadInt32();
                var subDirNames = Enumerable.Range(0, subDirCount)
                                  .Select(x => ar.ReadString())
                                  .ToArray();

                // Read subdirectories
                foreach (var _ in subDirNames.Reverse())
                {
                    var subDir = new MiloObjectDir();
                    ReadFromStream(ar, subDir);

                    dirEntry.SubDirectories.Add(subDir);
                }

                dir.Extras.Add("DirectoryEntry", dirEntry);
                ar.BaseStream.Position += 17; // 0'd data + ADDE
            }
            else if (version == 25 && (dirType == "WorldDir"))
            {
                // Read past unknown stuff, big hack
                int    unk1 = ar.ReadInt32();
                int    unk2 = ar.ReadInt32();
                float  unk3 = ar.ReadSingle();
                string unk4 = ar.ReadString();
                int    unk5 = ar.ReadInt32();
                int    unk6 = ar.ReadInt32();

                // Hack for project 9
                var dirEntry = new MiloObjectDirEntry()
                {
                    Name = dirName
                };
                dirEntry.Version     = ar.ReadInt32();
                dirEntry.SubVersion  = ar.ReadInt32();
                dirEntry.ProjectName = ar.ReadString();

                // Skip matrices + constants
                var matCount = ar.ReadInt32(); // Usually 7
                ar.BaseStream.Position += (matCount * 48) + 9;

                // Read imported milos
                var importedMiloCount = ar.ReadInt32();
                dirEntry.ImportedMiloPaths = Enumerable.Range(0, importedMiloCount)
                                             .Select(x => ar.ReadString())
                                             .ToArray();

                // Boolean, true when sub directory?
                ar.ReadBoolean();

                // Sub directory names seem to be in reverse order of serialization...
                var subDirCount = ar.ReadInt32();
                var subDirNames = Enumerable.Range(0, subDirCount)
                                  .Select(x => ar.ReadString())
                                  .ToArray();

                // Read subdirectories
                foreach (var _ in subDirNames.Reverse())
                {
                    var subDir = new MiloObjectDir();
                    ReadFromStream(ar, subDir);

                    dirEntry.SubDirectories.Add(subDir);
                }

                dir.Extras.Add("DirectoryEntry", dirEntry);
                ar.BaseStream.Position += 17; // 0'd data + ADDE
            }
            else if (version == 25 && (dirType == "RndDir" || dirType == "SynthDir"))
            {
                // Read past unknown stuff, big hack
                int unk1 = ar.ReadInt32();

                // Hack for project 9
                var dirEntry = new MiloObjectDirEntry()
                {
                    Name = dirName
                };
                dirEntry.Version     = ar.ReadInt32();
                dirEntry.SubVersion  = ar.ReadInt32();
                dirEntry.ProjectName = ar.ReadString();

                // Skip matrices + constants
                var matCount = ar.ReadInt32(); // Usually 7
                ar.BaseStream.Position += (matCount * 48) + 9;

                // Read imported milos
                var importedMiloCount = ar.ReadInt32();
                dirEntry.ImportedMiloPaths = Enumerable.Range(0, importedMiloCount)
                                             .Select(x => ar.ReadString())
                                             .ToArray();

                // Boolean, true when sub directory?
                ar.ReadBoolean();

                // Sub directory names seem to be in reverse order of serialization...
                var subDirCount = ar.ReadInt32();
                var subDirNames = Enumerable.Range(0, subDirCount)
                                  .Select(x => ar.ReadString())
                                  .ToArray();

                // Read subdirectories
                foreach (var _ in subDirNames.Reverse())
                {
                    var subDir = new MiloObjectDir();
                    ReadFromStream(ar, subDir);

                    dirEntry.SubDirectories.Add(subDir);
                }

                dir.Extras.Add("DirectoryEntry", dirEntry);
                ar.BaseStream.Position += 17; // 0'd data + ADDE
            }
            else if (version == 25 && (dirType == "PanelDir" || dirType == "VocalTrackDir" || dirType == "UILabelDir" || dirType == "UILabelDir" || dirType == "UIListDir" || dirType == "PitchArrowDir" || dirType == "Character"))
            {
                // Read past unknown stuff, big hack
                int unk1 = ar.ReadInt32();
                int unk2 = ar.ReadInt32();

                // Hack for project 9
                var dirEntry = new MiloObjectDirEntry()
                {
                    Name = dirName
                };
                dirEntry.Version     = ar.ReadInt32();
                dirEntry.SubVersion  = ar.ReadInt32();
                dirEntry.ProjectName = ar.ReadString();

                // Skip matrices + constants
                var matCount = ar.ReadInt32(); // Usually 7
                ar.BaseStream.Position += (matCount * 48) + 9;

                // Read imported milos
                var importedMiloCount = ar.ReadInt32();
                dirEntry.ImportedMiloPaths = Enumerable.Range(0, importedMiloCount)
                                             .Select(x => ar.ReadString())
                                             .ToArray();

                // Boolean, true when sub directory?
                ar.ReadBoolean();

                // Sub directory names seem to be in reverse order of serialization...
                var subDirCount = ar.ReadInt32();
                var subDirNames = Enumerable.Range(0, subDirCount)
                                  .Select(x => ar.ReadString())
                                  .ToArray();

                // Read subdirectories
                foreach (var _ in subDirNames.Reverse())
                {
                    var subDir = new MiloObjectDir();
                    ReadFromStream(ar, subDir);

                    dirEntry.SubDirectories.Add(subDir);
                }

                dir.Extras.Add("DirectoryEntry", dirEntry);
                ar.BaseStream.Position += 17; // 0'd data + ADDE
            }
            else if (version == 25 && (dirType == "BackgroundDir" || dirType == "WorldInstance"))
            {
                // Read past unknown stuff, big hack
                int unk1 = ar.ReadInt32();
                int unk2 = ar.ReadInt32();
                int unk3 = ar.ReadInt32();

                // Hack for project 9
                var dirEntry = new MiloObjectDirEntry()
                {
                    Name = dirName
                };
                dirEntry.Version     = ar.ReadInt32();
                dirEntry.SubVersion  = ar.ReadInt32();
                dirEntry.ProjectName = ar.ReadString();

                // Skip matrices + constants
                var matCount = ar.ReadInt32(); // Usually 7
                ar.BaseStream.Position += (matCount * 48) + 9;

                // Read imported milos
                var importedMiloCount = ar.ReadInt32();
                dirEntry.ImportedMiloPaths = Enumerable.Range(0, importedMiloCount)
                                             .Select(x => ar.ReadString())
                                             .ToArray();

                // Boolean, true when sub directory?
                ar.ReadBoolean();

                // Sub directory names seem to be in reverse order of serialization...
                var subDirCount = ar.ReadInt32();
                var subDirNames = Enumerable.Range(0, subDirCount)
                                  .Select(x => ar.ReadString())
                                  .ToArray();

                // Read subdirectories
                foreach (var _ in subDirNames.Reverse())
                {
                    var subDir = new MiloObjectDir();
                    ReadFromStream(ar, subDir);

                    dirEntry.SubDirectories.Add(subDir);
                }

                dir.Extras.Add("DirectoryEntry", dirEntry);
                ar.BaseStream.Position += 17; // 0'd data + ADDE
            }
            else if (version == 25 && (dirType == "TrackPanelDir" || dirType == "H2HTrackPanelDir"))
            {
                // Read past unknown stuff, big hack
                int unk1 = ar.ReadInt32();
                int unk2 = ar.ReadInt32();
                int unk3 = ar.ReadInt32();
                int unk4 = ar.ReadInt32();

                // Hack for project 9
                var dirEntry = new MiloObjectDirEntry()
                {
                    Name = dirName
                };
                dirEntry.Version     = ar.ReadInt32();
                dirEntry.SubVersion  = ar.ReadInt32();
                dirEntry.ProjectName = ar.ReadString();

                // Skip matrices + constants
                var matCount = ar.ReadInt32(); // Usually 7
                ar.BaseStream.Position += (matCount * 48) + 9;

                // Read imported milos
                var importedMiloCount = ar.ReadInt32();
                dirEntry.ImportedMiloPaths = Enumerable.Range(0, importedMiloCount)
                                             .Select(x => ar.ReadString())
                                             .ToArray();

                // Boolean, true when sub directory?
                ar.ReadBoolean();

                // Sub directory names seem to be in reverse order of serialization...
                var subDirCount = ar.ReadInt32();
                var subDirNames = Enumerable.Range(0, subDirCount)
                                  .Select(x => ar.ReadString())
                                  .ToArray();

                // Read subdirectories
                foreach (var _ in subDirNames.Reverse())
                {
                    var subDir = new MiloObjectDir();
                    ReadFromStream(ar, subDir);

                    dirEntry.SubDirectories.Add(subDir);
                }

                dir.Extras.Add("DirectoryEntry", dirEntry);
                ar.BaseStream.Position += 17; // 0'd data + ADDE
            }
            else if (version >= 24)
            {
                // GH2 and above

                // Reads data as a byte array
                var entrySize  = GuessEntrySize(ar);
                var entryBytes = new MiloObjectBytes(dirType)
                {
                    Name = dirName
                };
                entryBytes.Data = ar.ReadBytes((int)entrySize);

                dir.Extras.Add("DirectoryEntry", entryBytes);
                ar.BaseStream.Position += 4;
            }


            foreach (var entry in entries)
            {
                var entryOffset = ar.BaseStream.Position;
                // TODO: De-serialize entries

                //try
                //{
                //    var miloEntry = ReadFromStream(ar.BaseStream, entry.Type);
                //    miloEntry.Name = entry.Name;

                //    dir.Entries.Add(miloEntry);
                //    ar.BaseStream.Position += 4; // Skips padding
                //    continue;
                //}
                //catch (Exception ex)
                //{
                //    // Catch exception and log?
                //    ar.Basestream.Position = entryOffset; // Return to start
                //}

                // Reads data as a byte array
                var entrySize  = GuessEntrySize(ar);
                var entryBytes = new MiloObjectBytes(entry.Type)
                {
                    Name = entry.Name
                };
                entryBytes.Data = ar.ReadBytes((int)entrySize);

                dir.Entries.Add(entryBytes);
                ar.BaseStream.Position += 4;
            }
        }