public static STF_VOLUME_DESCRIPTOR Default() { var descriptor = new STF_VOLUME_DESCRIPTOR(); descriptor.DescriptorLength = 0x24; descriptor.Version = 0; descriptor.Flags = 0; descriptor.DirectoryAllocationBlocks = 1; descriptor.DirectoryFirstBlockNumber0 = descriptor.DirectoryFirstBlockNumber1 = descriptor.DirectoryFirstBlockNumber2 = 0; descriptor.RootHash = new byte[0x14]; descriptor.NumberOfTotalBlocks = 1; descriptor.NumberOfFreeBlocks = 0; return(descriptor); }
public void StfsInit() { if (Position == 0) { Position = Stream.Position; } // Read in XContent/PEC header if the volume descriptor isn't already set: if (StfsVolumeDescriptor.DescriptorLength != 0x24) { Stream.Position = Position; PecHeader = Stream.ReadStruct <PEC_HEADER>(); PecHeader.EndianSwap(); if (PecHeader.ConsoleSignature.IsStructureValid) { IsXContent = false; IsConsoleSigned = true; ConsoleSignature = PecHeader.ConsoleSignature; StfsVolumeDescriptor = PecHeader.StfsVolumeDescriptor; } else { IsXContent = true; Stream.Seek(0, SeekOrigin.Begin); Header = Stream.ReadStruct <XCONTENT_HEADER>(); Header.EndianSwap(); if (Header.SignatureType != XCONTENT_HEADER.kSignatureTypeConBE && Header.SignatureType != XCONTENT_HEADER.kSignatureTypeLiveBE && Header.SignatureType != XCONTENT_HEADER.kSignatureTypePirsBE) { throw new FileSystemParseException("File has invalid header magic"); } if (Header.SizeOfHeaders == 0) { throw new FileSystemParseException("Package doesn't contain STFS filesystem"); } if (Header.SignatureType == XCONTENT_HEADER.kSignatureTypeConBE) { IsConsoleSigned = true; ConsoleSignature = Header.ConsoleSignature; } byte[] headerRaw = new byte[0x118]; Stream.Position = 0x22C; Stream.Read(headerRaw, 0, 0x118); headerSha1 = Sha1.ComputeHash(headerRaw); var metadataEnd = (int)(Utility.RoundToPages(Header.SizeOfHeaders, kSectorSize) * kSectorSize); byte[] metadataRaw = new byte[metadataEnd - 0x344]; Stream.Position = 0x344; Stream.Read(metadataRaw, 0, metadataEnd - 0x344); contentIdValid = Sha1.ComputeHash(metadataRaw).BytesMatch(Header.ContentId); Stream.Position = 0x344; Metadata = Stream.ReadStruct <XCONTENT_METADATA>(); Metadata.EndianSwap(); if (Header.SizeOfHeaders > 0x971A) { Stream.Position = 0x971A; InstallerMetadata = Stream.ReadStruct <XCONTENT_METADATA_INSTALLER>(); InstallerMetadata.EndianSwap(); } if (Metadata.VolumeType != 0) { throw new FileSystemParseException("Package contains unsupported SVOD filesystem"); } StfsVolumeDescriptor = Metadata.StfsVolumeDescriptor; } if (StfsVolumeDescriptor.DescriptorLength != 0x24) { throw new FileSystemParseException("File has invalid descriptor length"); } } StfsInitValues(); // Read in our directory entries... int directoryBlock = StfsVolumeDescriptor.DirectoryFirstBlockNumber; var entries = new List <FileEntry>(); for (int i = 0; i < StfsVolumeDescriptor.DirectoryAllocationBlocks; i++) { if (directoryBlock == 0xFFFFFF) { Console.WriteLine("Premature directory exit 1!!!"); break; } var directoryOffset = StfsDataBlockToOffset(directoryBlock); Stream.Position = directoryOffset; bool noMoreEntries = false; for (int ent = 0; ent < (0x1000 / 0x40); ent++) { var entry = new FileEntry(this); if (!entry.Read(Stream)) { noMoreEntries = true; break; } entry.DirectoryOffset = directoryOffset; if (entry.CreationTime < CreationTime) { CreationTime = entry.CreationTime; } if (!entry.IsDirectory) { BytesInUse += entry.DirEntry.FileSize; } entries.Add(entry); } // Find next directory block... var blockHashEntry = StfsGetLevel0HashEntry(directoryBlock); directoryBlock = blockHashEntry.Level0NextBlock; if (noMoreEntries) { if (i + 1 < StfsVolumeDescriptor.DirectoryAllocationBlocks) { Console.WriteLine("Premature directory exit 2!!!"); } break; } } // Create metadata.ini/metadata_thumbnail/etc.. MetadataString = InitMetadataFiles(); // Connect entries up with their parents/children var rootEntries = new List <FileEntry>(); for (int i = 0; i < entries.Count; i++) { var ent = entries[i]; if (ent.DirEntry.DirectoryIndex == -1) { rootEntries.Add(ent); } if (!ent.IsDirectory) { continue; } var children = new List <FileEntry>(); foreach (var ent2 in entries) { if (ent2.DirEntry.DirectoryIndex == i) { children.Add(ent2); ent2.Parent = ent; } } children.Sort((x, y) => x.Name.CompareTo(y.Name)); ent.Children = children; } // Make sure to sort so that ReadDirectoryEntry doesn't make windows loop forever... rootEntries.Sort((x, y) => x.Name.CompareTo(y.Name)); Children = entries.ToArray(); }