public NintendoWad(string sourceFile) { // check magic bytes if (NintendoWad.IsWadFile(sourceFile)) { // read header using (FileStream fs = File.OpenRead(sourceFile)) { // set source file this.SourceFileName = sourceFile; // parse header this.HeaderSize = ParseFile.ReadUintBE(fs, 0); this.WadType = ParseFile.ReadUintBE(fs, 4); this.CertificateChainSize = ParseFile.ReadUintBE(fs, 8); this.Reserved = ParseFile.ReadUintBE(fs, 0xC); this.TicketSize = ParseFile.ReadUintBE(fs, 0x10); this.TitleMetaDataSize = ParseFile.ReadUintBE(fs, 0x14); this.DataSize = ParseFile.ReadUintBE(fs, 0x18); this.FooterSize = ParseFile.ReadUintBE(fs, 0x1C); // offsets this.CertificateChainOffset = (uint)this.PadValue(this.HeaderSize, "Certificate Chain Offset"); this.TicketOffset = (uint)this.PadValue(this.CertificateChainOffset + this.CertificateChainSize, "Ticket Offset"); this.TitleMetaDataOffset = (uint)this.PadValue(this.TicketOffset + this.TicketSize, "Title Meta Data Offset"); this.DataOffset = (uint)this.PadValue(this.TitleMetaDataOffset + this.TitleMetaDataSize, "Data Offset"); this.FooterOffset = (uint)this.PadValue(this.DataOffset + this.DataSize, "Footer Offset"); // get important values this.TicketId = ParseFile.ReadUlongBE(fs, this.TicketOffset + 0x1D0); this.TitleId = ParseFile.ReadUlongBE(fs, this.TicketOffset + 0x1DC); this.TitleIdBytes = ParseFile.ParseSimpleOffset(fs, this.TicketOffset + 0x1DC, 8); this.EncryptedTitleKey = ParseFile.ParseSimpleOffset(fs, this.TicketOffset + 0x1BF, 0x10); this.CommonKeyIndex = ParseFile.ReadByte(fs, this.TicketOffset + 0x1F1); // decrypt title key this.DecryptTitleKey(); // get TMD content entries this.NumberOfContents = ParseFile.ReadUshortBE(fs, this.TitleMetaDataOffset + 0x1DE); this.ParseTmdContentEntries(fs); } // using (FileStream fs = File.OpenRead(sourceFile)) } else { throw new FormatException("Nintendo WAD magic bytes not found at offset 0x03."); } }
/// <summary> /// Parse the Content Entries in the Title Meta Data section. /// </summary> /// <param name="fs">File Stream of WAD.</param> private void ParseTmdContentEntries(FileStream fs) { ulong nextOffset = this.DataOffset; TmdContentStruct contentEntry; ArrayList contentEntryList = new ArrayList(); for (ushort i = 0; i < this.NumberOfContents; i++) { contentEntry = new TmdContentStruct(); contentEntry.ContentId = ParseFile.ReadUintBE(fs, this.TitleMetaDataOffset + 0x1E4 + (i * 0x24) + 0); contentEntry.ContentIndex = ParseFile.ReadUshortBE(fs, this.TitleMetaDataOffset + 0x1E4 + (i * 0x24) + 4); contentEntry.ContentType = ParseFile.ReadUshortBE(fs, this.TitleMetaDataOffset + 0x1E4 + (i * 0x24) + 6); contentEntry.ContentSize = ParseFile.ReadUlongBE(fs, this.TitleMetaDataOffset + 0x1E4 + (i * 0x24) + 8); contentEntry.Sha1Hash = ParseFile.ParseSimpleOffset(fs, (this.TitleMetaDataOffset + 0x1E4 + (i * 0x24) + 0x10), 20); contentEntry.ContentOffset = nextOffset; contentEntryList.Add(contentEntry); nextOffset = this.PadValue((contentEntry.ContentOffset + contentEntry.ContentSize), String.Format("Next Offset for ContentId: 0x{0}", contentEntry.ContentId.ToString("X8"))); } this.TmdContentEntries = (TmdContentStruct[])contentEntryList.ToArray(typeof(TmdContentStruct)); }
private void initializeUtfSchema(FileStream SourceFs, FileStream UtfTableFs, long schemaOffset) { long nameOffset; long constantOffset; long dataOffset; long dataSize; long rowDataOffset; long rowDataSize; long currentOffset = schemaOffset; long currentRowBase; long currentRowOffset = 0; CriField field; for (uint i = 0; i < this.NumberOfRows; i++) { //if (i == 0x1a2a) //{ // int yuuuu = 1; //} //try //{ currentOffset = schemaOffset; currentRowBase = this.RowOffset + (this.RowSize * i); currentRowOffset = 0; this.Rows[i] = new Dictionary <string, CriField>(); // parse fields for (ushort j = 0; j < this.NumberOfFields; j++) { field = new CriField(); field.Type = ParseFile.ReadByte(UtfTableFs, currentOffset); nameOffset = ParseFile.ReadUintBE(UtfTableFs, currentOffset + 1); field.Name = ParseFile.ReadAsciiString(UtfTableFs, this.StringTableOffset + nameOffset); // each row will have a constant if (((field.Type & COLUMN_STORAGE_MASK) == COLUMN_STORAGE_CONSTANT) || ((field.Type & COLUMN_STORAGE_MASK) == COLUMN_STORAGE_CONSTANT2)) { // capture offset of constant constantOffset = currentOffset + 5; // read the constant depending on the type switch (field.Type & COLUMN_TYPE_MASK) { case COLUMN_TYPE_STRING: dataOffset = ParseFile.ReadUintBE(UtfTableFs, constantOffset); field.Value = ParseFile.ReadAsciiString(UtfTableFs, this.StringTableOffset + dataOffset); currentOffset += 4; break; case COLUMN_TYPE_8BYTE: field.Value = ParseFile.ReadUlongBE(UtfTableFs, constantOffset); currentOffset += 8; break; case COLUMN_TYPE_DATA: dataOffset = ParseFile.ReadUintBE(UtfTableFs, constantOffset); dataSize = ParseFile.ReadUintBE(UtfTableFs, constantOffset + 4); field.Offset = (ulong)(this.BaseOffset + this.DataOffset + dataOffset); field.Size = (ulong)dataSize; // don't think this is encrypted, need to check field.Value = ParseFile.ParseSimpleOffset(SourceFs, (long)field.Offset, (int)dataSize); currentOffset += 8; break; case COLUMN_TYPE_FLOAT: field.Value = ParseFile.ReadFloatBE(UtfTableFs, constantOffset); currentOffset += 4; break; case COLUMN_TYPE_4BYTE2: field.Value = ParseFile.ReadInt32BE(UtfTableFs, constantOffset); currentOffset += 4; break; case COLUMN_TYPE_4BYTE: field.Value = ParseFile.ReadUintBE(UtfTableFs, constantOffset); currentOffset += 4; break; case COLUMN_TYPE_2BYTE2: field.Value = ParseFile.ReadInt16BE(UtfTableFs, constantOffset); currentOffset += 2; break; case COLUMN_TYPE_2BYTE: field.Value = ParseFile.ReadUshortBE(UtfTableFs, constantOffset); currentOffset += 2; break; case COLUMN_TYPE_1BYTE2: field.Value = ParseFile.ReadSByte(UtfTableFs, constantOffset); currentOffset += 1; break; case COLUMN_TYPE_1BYTE: field.Value = ParseFile.ReadByte(UtfTableFs, constantOffset); currentOffset += 1; break; default: throw new FormatException(String.Format("Unknown COLUMN TYPE at offset: 0x{0}", currentOffset.ToString("X8"))); } // switch (field.Type & COLUMN_TYPE_MASK) } else if ((field.Type & COLUMN_STORAGE_MASK) == COLUMN_STORAGE_PERROW) { // read the constant depending on the type switch (field.Type & COLUMN_TYPE_MASK) { case COLUMN_TYPE_STRING: rowDataOffset = ParseFile.ReadUintBE(UtfTableFs, currentRowBase + currentRowOffset); field.Value = ParseFile.ReadAsciiString(UtfTableFs, this.StringTableOffset + rowDataOffset); currentRowOffset += 4; break; case COLUMN_TYPE_8BYTE: field.Value = ParseFile.ReadUlongBE(UtfTableFs, currentRowBase + currentRowOffset); currentRowOffset += 8; break; case COLUMN_TYPE_DATA: rowDataOffset = ParseFile.ReadUintBE(UtfTableFs, currentRowBase + currentRowOffset); rowDataSize = ParseFile.ReadUintBE(UtfTableFs, currentRowBase + currentRowOffset + 4); field.Offset = (ulong)(this.BaseOffset + this.DataOffset + rowDataOffset); field.Size = (ulong)rowDataSize; // don't think this is encrypted field.Value = ParseFile.ParseSimpleOffset(SourceFs, (long)field.Offset, (int)rowDataSize); currentRowOffset += 8; break; case COLUMN_TYPE_FLOAT: field.Value = ParseFile.ReadFloatBE(UtfTableFs, currentRowBase + currentRowOffset); currentRowOffset += 4; break; case COLUMN_TYPE_4BYTE2: field.Value = ParseFile.ReadInt32BE(UtfTableFs, currentRowBase + currentRowOffset); currentRowOffset += 4; break; case COLUMN_TYPE_4BYTE: field.Value = ParseFile.ReadUintBE(UtfTableFs, currentRowBase + currentRowOffset); currentRowOffset += 4; break; case COLUMN_TYPE_2BYTE2: field.Value = ParseFile.ReadInt16BE(UtfTableFs, currentRowBase + currentRowOffset); currentRowOffset += 2; break; case COLUMN_TYPE_2BYTE: field.Value = ParseFile.ReadUshortBE(UtfTableFs, currentRowBase + currentRowOffset); currentRowOffset += 2; break; case COLUMN_TYPE_1BYTE2: field.Value = ParseFile.ReadSByte(UtfTableFs, currentRowBase + currentRowOffset); currentRowOffset += 1; break; case COLUMN_TYPE_1BYTE: field.Value = ParseFile.ReadByte(UtfTableFs, currentRowBase + currentRowOffset); currentRowOffset += 1; break; default: throw new FormatException(String.Format("Unknown COLUMN TYPE at offset: 0x{0}", currentOffset.ToString("X8"))); } // switch (field.Type & COLUMN_TYPE_MASK) } // if ((fields[i].Type & COLUMN_STORAGE_MASK) == COLUMN_STORAGE_CONSTANT) // add field to dictionary this.Rows[i].Add(field.Name, field); // move to next field currentOffset += 5; // sizeof(CriField.Type + CriField.NameOffset) } // for (ushort j = 0; j < this.NumberOfFields; j++) //} //catch (Exception ex) //{ // int xxxx = 1; //} } // for (uint i = 0; i < this.NumberOfRows; i++) }