// Block Layout: // 000-001 U16 Index // 002-002 U8 Type // 003-003 U8 List Icon ID (e.g. 40-47 for the elemental-colored dots) // 004-005 U16 MP Cost // 006-007 U16 Unknown (used to be the cooldown time) // 008-009 U16 Valid Targets // 00a-029 TXT Name // 02a-129 TXT Description (exact length unknown) // 12a-3fe U8 Padding (NULs) // 3ff-3ff U8 End marker (0xff) public bool Read(BinaryReader BR) { this.Clear(); try { byte[] Bytes = BR.ReadBytes(0x400); if (Bytes[0x3ff] != 0xff || Bytes[9] != 0x00 || !FFXIEncryption.DecodeDataBlock(Bytes)) { return(false); } FFXIEncoding E = new FFXIEncoding(); BR = new BinaryReader(new MemoryStream(Bytes, false)); this.ID_ = BR.ReadUInt16(); this.Type_ = (AbilityType)BR.ReadByte(); this.ListIconID_ = BR.ReadByte(); this.MPCost_ = BR.ReadUInt16(); this.Unknown1_ = BR.ReadUInt16(); this.ValidTargets_ = (ValidTarget)BR.ReadUInt16(); this.Name_ = E.GetString(BR.ReadBytes(32)).TrimEnd('\0'); this.Description_ = E.GetString(BR.ReadBytes(256)).TrimEnd('\0'); BR.Close(); return(true); } catch { return(false); } }
public override ThingList Load(BinaryReader BR, ProgressCallback ProgressCallback) { ThingList TL = new ThingList(); if (ProgressCallback != null) ProgressCallback(I18N.GetText("FTM:CheckingFile"), 0); if (BR.BaseStream.Length < 0x40 || BR.BaseStream.Position != 0) return TL; FFXIEncoding E = new FFXIEncoding(); if (E.GetString(BR.ReadBytes(8)) != "d_msg".PadRight(8, '\0')) return TL; ushort Flag1 = BR.ReadUInt16(); if (Flag1 != 0 && Flag1 != 1) return TL; ushort Flag2 = BR.ReadUInt16(); if (Flag2 != 0 && Flag2 != 1) return TL; if (BR.ReadUInt32() != 3 || BR.ReadUInt32() != 3) return TL; uint FileSize = BR.ReadUInt32(); if (FileSize != BR.BaseStream.Length) return TL; uint HeaderBytes = BR.ReadUInt32(); if (HeaderBytes != 0x40) return TL; if (BR.ReadUInt32() != 0) return TL; int BytesPerEntry = BR.ReadInt32(); if (BytesPerEntry < 0) return TL; uint DataBytes = BR.ReadUInt32(); if (FileSize != (HeaderBytes + DataBytes) || (DataBytes % BytesPerEntry) != 0) return TL; uint EntryCount = BR.ReadUInt32(); if (EntryCount * BytesPerEntry != DataBytes) return TL; if (BR.ReadUInt32() != 1 || BR.ReadUInt64() != 0 || BR.ReadUInt64() != 0) return TL; if (ProgressCallback != null) ProgressCallback(I18N.GetText("FTM:LoadingData"), 0); for (uint i = 0; i < EntryCount; ++i) { BinaryReader EntryBR = new BinaryReader(new MemoryStream(BR.ReadBytes(BytesPerEntry))); EntryBR.BaseStream.Position = 0; bool ItemAdded = false; { Things.DMSGStringBlock SB = new Things.DMSGStringBlock(); if (SB.Read(EntryBR, E, i)) { TL.Add(SB); ItemAdded = true; } } EntryBR.Close(); if (!ItemAdded) { TL.Clear(); break; } if (ProgressCallback != null) ProgressCallback(null, (double) (i + 1) / EntryCount); } return TL; }
public override ThingList Load(BinaryReader BR, ProgressCallback ProgressCallback) { ThingList TL = new ThingList(); if (ProgressCallback != null) { ProgressCallback(I18N.GetText("FTM:CheckingFile"), 0); } if (BR.BaseStream.Length < 0x38 || BR.BaseStream.Position != 0) { return TL; } FFXIEncoding E = new FFXIEncoding(); // Read past the marker (32 bytes) if ((E.GetString(BR.ReadBytes(10)) != "XISTRING".PadRight(10, '\0')) || BR.ReadUInt16() != 2) { return TL; } foreach (byte B in BR.ReadBytes(20)) { if (B != 0) { return TL; } } // Read The Header uint FileSize = BR.ReadUInt32(); if (FileSize != BR.BaseStream.Length) { return TL; } uint EntryCount = BR.ReadUInt32(); uint EntryBytes = BR.ReadUInt32(); uint DataBytes = BR.ReadUInt32(); BR.ReadUInt32(); // Unknown BR.ReadUInt32(); // Unknown if (EntryBytes != EntryCount * 12 || FileSize != 0x38 + EntryBytes + DataBytes) { return TL; } if (ProgressCallback != null) { ProgressCallback(I18N.GetText("FTM:LoadingData"), 0); } for (uint i = 0; i < EntryCount; ++i) { Things.XIStringTableEntry XSTE = new Things.XIStringTableEntry(); if (!XSTE.Read(BR, E, i, EntryBytes, DataBytes)) { TL.Clear(); break; } if (ProgressCallback != null) { ProgressCallback(null, (double)(i + 1) / EntryCount); } TL.Add(XSTE); } return TL; }
public override ThingList Load(BinaryReader BR, ProgressCallback ProgressCallback) { ThingList TL = new ThingList(); if (ProgressCallback != null) ProgressCallback(I18N.GetText("FTM:CheckingFile"), 0); if (BR.BaseStream.Length < 0x40 || BR.BaseStream.Position != 0) return TL; FFXIEncoding E = new FFXIEncoding(); // Skip (presumably) fixed portion of the header if ((E.GetString(BR.ReadBytes(8)) != "d_msg".PadRight(8, '\0')) || BR.ReadUInt16() != 1 || BR.ReadUInt16() != 1 || BR.ReadUInt32() != 3 || BR.ReadUInt32() != 3) return TL; // Read the useful header fields uint FileSize = BR.ReadUInt32(); if (FileSize != BR.BaseStream.Length) return TL; uint HeaderBytes = BR.ReadUInt32(); if (HeaderBytes != 0x40) return TL; uint EntryBytes = BR.ReadUInt32(); if (BR.ReadUInt32() != 0) return TL; uint DataBytes = BR.ReadUInt32(); if (FileSize != HeaderBytes + EntryBytes + DataBytes) return TL; uint EntryCount = BR.ReadUInt32(); if (EntryBytes != EntryCount * 8) return TL; if (BR.ReadUInt32() != 1 || BR.ReadUInt64() != 0 || BR.ReadUInt64() != 0) return TL; if (ProgressCallback != null) ProgressCallback(I18N.GetText("FTM:LoadingData"), 0); for (uint i = 0; i < EntryCount; ++i) { BR.BaseStream.Position = HeaderBytes + i * 8; int Offset = ~BR.ReadInt32(); int Length = ~BR.ReadInt32(); if (Length < 0 || Offset < 0 || Offset + Length > DataBytes) { TL.Clear(); break; } BR.BaseStream.Position = HeaderBytes + EntryBytes + Offset; BinaryReader EntryBR = new BinaryReader(new MemoryStream(BR.ReadBytes(Length))); bool ItemAdded = false; { Things.DMSGStringBlock SB = new Things.DMSGStringBlock(); if (SB.Read(EntryBR, E, i)) { TL.Add(SB); ItemAdded = true; } } EntryBR.Close(); if (!ItemAdded) { TL.Clear(); break; } if (ProgressCallback != null) ProgressCallback(null, (double) (i + 1) / EntryCount); } return TL; }
// Block Layout: // 000-003 U32 Index // 004-007 U32 Unknown // 008-00b U32 Unknown // 00c-00f U32 Unknown // 010-013 U32 Unknown // 014-02b Unknown // 02c-0ab TXT Description // 0ac-27f Unknown // 280-281 U16 Icon Size // 282-bff IMG Icon (+ padding) public bool Read(BinaryReader BR) { this.Clear(); try { byte[] Bytes = BR.ReadBytes(0x280); byte[] IconBytes = BR.ReadBytes(0x980); if (!FFXIEncryption.DecodeDataBlock(Bytes)) { return(false); } if (IconBytes[0x97f] != 0xff) { return(false); } { // Verify that the icon info is valid Graphic StatusIcon = new Graphic(); BinaryReader IconBR = new BinaryReader(new MemoryStream(IconBytes, false)); int IconSize = IconBR.ReadInt32(); if (IconSize > 0 && IconSize <= 0x97b) { if (!StatusIcon.Read(IconBR) || IconBR.BaseStream.Position != 4 + IconSize) { IconBR.Close(); return(false); } } IconBR.Close(); if (StatusIcon == null) { return(false); } this.Icon_ = StatusIcon; } BR = new BinaryReader(new MemoryStream(Bytes, false)); } catch { return(false); } FFXIEncoding E = new FFXIEncoding(); this.ID_ = BR.ReadUInt16(); this.Unknown1_ = BR.ReadUInt16(); this.Unknown2_ = BR.ReadUInt32(); this.Unknown3_ = BR.ReadUInt32(); this.Unknown4_ = BR.ReadUInt32(); this.Unknown4_ = BR.ReadUInt32(); BR.ReadBytes(0x18); this.Description_ = E.GetString(BR.ReadBytes(128)).TrimEnd('\0'); BR.Close(); return(true); }
public bool Read(BinaryReader BR) { this.Clear(); try { FFXIEncoding E = new FFXIEncoding(); this.Name_ = E.GetString(BR.ReadBytes(0x1C)).TrimEnd('\0'); this.ID_ = BR.ReadUInt32(); // ID seems to be 010 + zone id + mob id (=> there's a hard max of 0xFFF (= 4095) mobs per zone, which seems plenty :)) // Special 'instanced' zones like MMM or Meebles use 013 + 'zone id' + mob id. if ((this.ID_ != 0 && (this.ID_ & 0xFFF00000) != 0x01000000) && (this.ID_ != 0 && (this.ID_ & 0xFFF00000) != 0x01300000) && (this.ID_ != 0 && (this.ID_ & 0xFFF00000) != 0x01100000)) { return(false); } return(true); } catch { return(false); } }
public override ThingList Load(BinaryReader BR, ProgressCallback ProgressCallback) { ThingList TL = new ThingList(); if (ProgressCallback != null) ProgressCallback(I18N.GetText("FTM:CheckingFile"), 0); if (BR.BaseStream.Length < 0x38 || BR.BaseStream.Position != 0) return TL; FFXIEncoding E = new FFXIEncoding(); // Skip (presumably) fixed portion of the header if ((E.GetString(BR.ReadBytes(8)) != "d_msg".PadRight(8, '\0')) || BR.ReadUInt16() != 1 || BR.ReadUInt32() != 0 || BR.ReadUInt16() != 2 || BR.ReadUInt32() != 3) return TL; // Read the useful header fields uint EntryCount = BR.ReadUInt32(); if (BR.ReadUInt32() != 1) return TL; uint FileSize = BR.ReadUInt32(); if (FileSize != BR.BaseStream.Length) return TL; uint HeaderSize = BR.ReadUInt32(); if (HeaderSize != 0x38) return TL; uint EntryBytes = BR.ReadUInt32(); if (EntryBytes != EntryCount * 36) return TL; uint DataBytes = BR.ReadUInt32(); if (FileSize != 0x38 + EntryBytes + DataBytes) return TL; // 12 NUL bytes if (BR.ReadUInt32() != 0 || BR.ReadUInt32() != 0 || BR.ReadUInt32() != 0) return TL; if (ProgressCallback != null) ProgressCallback(I18N.GetText("FTM:LoadingData"), 0); for (uint i = 0; i < EntryCount; ++i) { Things.DMSGStringTableEntry DSTE = new Things.DMSGStringTableEntry(); if (!DSTE.Read(BR, E, i, EntryBytes, DataBytes)) { TL.Clear(); break; } if (ProgressCallback != null) ProgressCallback(null, (double) (i + 1) / EntryCount); TL.Add(DSTE); } return TL; }
public bool Read(BinaryReader BR) { this.Clear(); try { FFXIEncoding E = new FFXIEncoding(); this.Name_ = E.GetString(BR.ReadBytes(0x1C)).TrimEnd('\0'); this.ID_ = BR.ReadUInt32(); // ID seems to be 010 + zone id + mob id (=> there's a hard max of 0xFFF (= 4095) mobs per zone, which seems plenty :)) // Special 'instanced' zones like MMM or Meebles use 013 + 'zone id' + mob id. if ((this.ID_ != 0 && (this.ID_ & 0xFFF00000) != 0x01000000) && (this.ID_ != 0 && (this.ID_ & 0xFFF00000) != 0x01300000) && (this.ID_ != 0 && (this.ID_ & 0xFFF00000) != 0x01100000)) { return false; } return true; } catch { return false; } }
public bool Read(BinaryReader BR) { this.Clear(); try { this.ID_ = BR.ReadUInt32(); // Read entry byte[] TextBytes = BR.ReadBytes(0x3b); this.Text_ = String.Empty; // Trim trailing NULs int ByteCount = 0x3b; while (TextBytes[ByteCount - 1] == 0x00) { --ByteCount; } // Process the message FFXIEncoding E = new FFXIEncoding(); int LastPos = 0; for (int i = 0; i < ByteCount; ++i) { if (TextBytes[i] == 0x07) // Line Break { if (LastPos < i) { this.Text_ += E.GetString(TextBytes, LastPos, i - LastPos); } this.Text_ += "\r\n"; LastPos = i + 1; } else if (TextBytes[i] == 0x08) // Character Name (You) { if (LastPos < i) { this.Text_ += E.GetString(TextBytes, LastPos, i - LastPos); } this.Text_ += String.Format("{0}Player Name{1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd); LastPos = i + 1; } else if (TextBytes[i] == 0x09) // Character Name (They) { if (LastPos < i) { this.Text_ += E.GetString(TextBytes, LastPos, i - LastPos); } this.Text_ += String.Format("{0}Speaker Name{1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd); LastPos = i + 1; } else if (TextBytes[i] == 0x0a && i + 1 < TextBytes.Length) { if (LastPos < i) { this.Text_ += E.GetString(TextBytes, LastPos, i - LastPos); } this.Text_ += String.Format("{0}Numeric Parameter {2}{1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd, TextBytes[i + 1]); LastPos = i + 2; ++i; } else if (TextBytes[i] == 0x0b) // Indicates that the lines after this are in a prompt window { if (LastPos < i) { this.Text_ += E.GetString(TextBytes, LastPos, i - LastPos); } this.Text_ += String.Format("{0}Selection Dialog{1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd); LastPos = i + 1; } else if (TextBytes[i] == 0x0c && i + 1 < TextBytes.Length) { if (LastPos < i) { this.Text_ += E.GetString(TextBytes, LastPos, i - LastPos); } this.Text_ += String.Format("{0}Multiple Choice (Parameter {2}){1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd, TextBytes[i + 1]); LastPos = i + 2; ++i; } else if (TextBytes[i] == 0x19 && i + 1 < TextBytes.Length) { if (LastPos < i) { this.Text_ += E.GetString(TextBytes, LastPos, i - LastPos); } this.Text_ += String.Format("{0}Item Parameter {2}{1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd, TextBytes[i + 1]); LastPos = i + 2; ++i; } else if (TextBytes[i] == 0x1a && i + 1 < TextBytes.Length) { if (LastPos < i) { this.Text_ += E.GetString(TextBytes, LastPos, i - LastPos); } this.Text_ += String.Format("{0}Key Item Parameter {2}{1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd, TextBytes[i + 1]); LastPos = i + 2; ++i; } else if (TextBytes[i] == 0x1c && i + 1 < TextBytes.Length) // Chocobo Name { if (LastPos < i) { this.Text_ += E.GetString(TextBytes, LastPos, i - LastPos); } this.Text_ += String.Format("{0}Player/Chocobo Parameter {2}{1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd, TextBytes[i + 1]); LastPos = i + 2; ++i; } else if (TextBytes[i] == 0x1e && i + 1 < TextBytes.Length) { if (LastPos < i) { this.Text_ += E.GetString(TextBytes, LastPos, i - LastPos); } this.Text_ += String.Format("{0}Set Color #{2}{1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd, TextBytes[i + 1]); LastPos = i + 2; ++i; } else if (TextBytes[i] == 0x7f && i + 1 < TextBytes.Length) // Various stuff { if (LastPos < i) { this.Text_ += E.GetString(TextBytes, LastPos, i - LastPos); } if (TextBytes[i + 1] == 0x31 && i + 2 < TextBytes.Length) // Unknown, but seems to indicate user needs to hit RET { if (TextBytes[i + 2] != 0) { this.Text_ += String.Format("{0}{2}-Second Delay + Prompt{1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd, TextBytes[i + 2]); } else { this.Text_ += String.Format("{0}Prompt{1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd); } ++LastPos; ++i; } else if (TextBytes[i + 1] == 0x85) // Multiple Choice: Player Gender { this.Text_ += String.Format("{0}Multiple Choice (Player Gender){1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd); } else if (TextBytes[i + 1] == 0x8D && i + 2 < TextBytes.Length) { this.Text_ += String.Format("{0}Weather Event Parameter {2}{1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd, TextBytes[i + 2]); ++LastPos; ++i; } else if (TextBytes[i + 1] == 0x8E && i + 2 < TextBytes.Length) { this.Text_ += String.Format("{0}Weather Type Parameter {2}{1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd, TextBytes[i + 2]); ++LastPos; ++i; } else if (TextBytes[i + 1] == 0x92 && i + 2 < TextBytes.Length) { this.Text_ += String.Format("{0}Singular/Plural Choice (Parameter {2}){1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd, TextBytes[i + 2]); ++LastPos; ++i; } else if (TextBytes[i + 1] == 0xB1 && i + 2 < TextBytes.Length) // Usually found before an item name or key item name { this.Text_ += String.Format("{0}Title Parameter {2}{1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd, TextBytes[i + 2]); ++LastPos; ++i; } else if (i + 2 < TextBytes.Length) { this.Text_ += String.Format("{0}Unknown Parameter (Type: {2:X2}) {3}{1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd, TextBytes[i + 1], TextBytes[i + 2]); ++LastPos; ++i; } else { this.Text_ += String.Format("{0}Unknown Marker Type: {2:X2}{1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd, TextBytes[i + 1]); } LastPos = i + 2; ++i; } else if (TextBytes[i] == 0x7f || TextBytes[i] < 0x20) { if (LastPos < i) { this.Text_ += E.GetString(TextBytes, LastPos, i - LastPos); } this.Text_ += String.Format("{0}Possible Special Code: {2:X2}{1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd, TextBytes[i]); LastPos = i + 1; } } if (LastPos < ByteCount) { this.Text_ += E.GetString(TextBytes, LastPos, ByteCount - LastPos); } return(BR.ReadByte() == 0xff); } catch { return(false); } }
public override ThingList Load(BinaryReader BR, ProgressCallback ProgressCallback) { ThingList TL = new ThingList(); if (ProgressCallback != null) { ProgressCallback(I18N.GetText("FTM:CheckingFile"), 0); } if (BR.BaseStream.Length < 0x40 || BR.BaseStream.Position != 0) { return(TL); } FFXIEncoding E = new FFXIEncoding(); // Skip (presumably) fixed portion of the header if ((E.GetString(BR.ReadBytes(8)) != "d_msg".PadRight(8, '\0')) || BR.ReadUInt16() != 1 || BR.ReadUInt16() != 1 || BR.ReadUInt32() != 3 || BR.ReadUInt32() != 3) { return(TL); } // Read the useful header fields uint FileSize = BR.ReadUInt32(); if (FileSize != BR.BaseStream.Length) { return(TL); } uint HeaderBytes = BR.ReadUInt32(); if (HeaderBytes != 0x40) { return(TL); } uint EntryBytes = BR.ReadUInt32(); if (BR.ReadUInt32() != 0) { return(TL); } uint DataBytes = BR.ReadUInt32(); if (FileSize != HeaderBytes + EntryBytes + DataBytes) { return(TL); } uint EntryCount = BR.ReadUInt32(); if (EntryBytes != EntryCount * 8) { return(TL); } if (BR.ReadUInt32() != 1 || BR.ReadUInt64() != 0 || BR.ReadUInt64() != 0) { return(TL); } if (ProgressCallback != null) { ProgressCallback(I18N.GetText("FTM:LoadingData"), 0); } for (uint i = 0; i < EntryCount; ++i) { BR.BaseStream.Position = HeaderBytes + i * 8; int Offset = ~BR.ReadInt32(); int Length = ~BR.ReadInt32(); if (Length < 0 || Offset < 0 || Offset + Length > DataBytes) { TL.Clear(); break; } BR.BaseStream.Position = HeaderBytes + EntryBytes + Offset; BinaryReader EntryBR = new BinaryReader(new MemoryStream(BR.ReadBytes(Length))); bool ItemAdded = false; { Things.DMSGStringBlock SB = new Things.DMSGStringBlock(); if (SB.Read(EntryBR, E, i)) { TL.Add(SB); ItemAdded = true; } } EntryBR.Close(); if (!ItemAdded) { TL.Clear(); break; } if (ProgressCallback != null) { ProgressCallback(null, (double)(i + 1) / EntryCount); } } return(TL); }
private void TranslateAutoTranslatorFile(int JPFileNumber, int ENFileNumber) { if (!this.BackupFile(JPFileNumber)) return; try { string JFileName = FFXI.GetFilePath(JPFileNumber); string EFileName = FFXI.GetFilePath(ENFileNumber); this.AddLogEntry(String.Format(I18N.GetText("TranslatingAutoTrans"), JFileName)); this.AddLogEntry(String.Format(I18N.GetText("UsingEnglishFile"), EFileName)); FileStream ATStream = new FileStream(JFileName, FileMode.Open, FileAccess.ReadWrite, FileShare.None); MemoryStream NewStream = new MemoryStream(); BinaryReader JBR = new BinaryReader(ATStream); BinaryWriter JBW = new BinaryWriter(NewStream); BinaryReader EBR = new BinaryReader(new FileStream(EFileName, FileMode.Open, FileAccess.Read)); FFXIEncoding E = new FFXIEncoding(); while (ATStream.Position != ATStream.Length) { { // Validate & Copy ID uint JID = JBR.ReadUInt32(); uint EID = EBR.ReadUInt32(); if ((JID & 0xffff) != 0x102) { this.AddLogEntry(String.Format(I18N.GetText("ATBadJPID"), JID)); goto TranslationDone; } if ((EID & 0xffff) != 0x202) { this.AddLogEntry(String.Format(I18N.GetText("ATBadENID"), EID)); goto TranslationDone; } if ((EID & 0xffff0000) != (JID & 0xffff0000)) { this.AddLogEntry(String.Format(I18N.GetText("ATIDMismatch"), JID, EID)); goto TranslationDone; } JBW.Write(JID); } // Group name -> use English JBW.Write(EBR.ReadBytes(32)); JBR.BaseStream.Position += 32; // Completion Text -> based on config if (this.mnuPreserveJapaneseATCompletion.Checked) { JBW.Write(JBR.ReadBytes(32)); EBR.BaseStream.Position += 32; } else { byte[] EnglishCompletion = E.GetBytes(E.GetString(EBR.ReadBytes(32)).ToLowerInvariant()); // we want it lowercase if (EnglishCompletion.Length != 32) { this.AddLogEntry(String.Format(I18N.GetText("ATLowercaseProblem"), EnglishCompletion.Length)); goto TranslationDone; } JBW.Write(EnglishCompletion); JBR.BaseStream.Position += 32; } uint JEntryCount = JBR.ReadUInt32(); uint EEntryCount = EBR.ReadUInt32(); if (JEntryCount != EEntryCount) { this.AddLogEntry(String.Format(I18N.GetText("ATCountMismatch"), JEntryCount, EEntryCount)); goto TranslationDone; } JBW.Write(JEntryCount); long EntryBytesPos = JBW.BaseStream.Position; JBW.Write((uint) 0); JBR.BaseStream.Position += 4; EBR.BaseStream.Position += 4; for (uint i = 0; i < JEntryCount; ++i) { // Validate & Copy ID uint JID = JBR.ReadUInt32(); uint EID = EBR.ReadUInt32(); if ((JID & 0xffff) != 0x102) { this.AddLogEntry(String.Format(I18N.GetText("ATBadJPID"), JID)); goto TranslationDone; } if ((EID & 0xffff) != 0x202) { this.AddLogEntry(String.Format(I18N.GetText("ATBadENID"), EID)); goto TranslationDone; } if ((EID & 0xffff0000) != (JID & 0xffff0000)) { this.AddLogEntry(String.Format(I18N.GetText("ATIDMismatch"), JID, EID)); goto TranslationDone; } JBW.Write(JID); // Display text -> use English byte[] EnglishText = EBR.ReadBytes(EBR.ReadByte()); JBW.Write((byte) EnglishText.Length); JBW.Write(EnglishText); JBR.BaseStream.Position += 1 + JBR.ReadByte(); // Completion Text -> based on config if (this.mnuPreserveJapaneseATCompletion.Checked) { byte[] JapaneseText = JBR.ReadBytes(JBR.ReadByte()); JBW.Write((byte) JapaneseText.Length); JBW.Write(JapaneseText); } else { byte[] LowerEnglishText = E.GetBytes(E.GetString(EnglishText).ToLowerInvariant()); JBW.Write((byte) LowerEnglishText.Length); JBW.Write(LowerEnglishText); JBR.BaseStream.Position += 1 + JBR.ReadByte(); } } long EndOfGroupPos = JBW.BaseStream.Position; JBW.BaseStream.Position = EntryBytesPos; JBW.Write((uint) (EndOfGroupPos - EntryBytesPos - 4)); JBW.BaseStream.Position = EndOfGroupPos; } ATStream.Seek(0, SeekOrigin.Begin); ATStream.Write(NewStream.ToArray(), 0, (int) NewStream.Length); ATStream.SetLength(NewStream.Length); TranslationDone: ATStream.Close(); NewStream.Close(); EBR.Close(); } catch { this.LogFailure("TranslateAutoTranslator"); } }
public override ThingList Load(BinaryReader BR, ProgressCallback ProgressCallback) { ThingList TL = new ThingList(); if (ProgressCallback != null) { ProgressCallback(I18N.GetText("FTM:CheckingFile"), 0); } if (BR.BaseStream.Length < 0x38 || BR.BaseStream.Position != 0) { return(TL); } FFXIEncoding E = new FFXIEncoding(); // Skip (presumably) fixed portion of the header if ((E.GetString(BR.ReadBytes(8)) != "d_msg".PadRight(8, '\0')) || BR.ReadUInt16() != 1 || BR.ReadUInt32() != 0 || BR.ReadUInt16() != 2 || BR.ReadUInt32() != 3) { return(TL); } // Read the useful header fields uint EntryCount = BR.ReadUInt32(); if (BR.ReadUInt32() != 1) { return(TL); } uint FileSize = BR.ReadUInt32(); if (FileSize != BR.BaseStream.Length) { return(TL); } uint HeaderSize = BR.ReadUInt32(); if (HeaderSize != 0x38) { return(TL); } uint EntryBytes = BR.ReadUInt32(); if (EntryBytes != EntryCount * 36) { return(TL); } uint DataBytes = BR.ReadUInt32(); if (FileSize != 0x38 + EntryBytes + DataBytes) { return(TL); } // 12 NUL bytes if (BR.ReadUInt32() != 0 || BR.ReadUInt32() != 0 || BR.ReadUInt32() != 0) { return(TL); } if (ProgressCallback != null) { ProgressCallback(I18N.GetText("FTM:LoadingData"), 0); } for (uint i = 0; i < EntryCount; ++i) { Things.DMSGStringTableEntry DSTE = new Things.DMSGStringTableEntry(); if (!DSTE.Read(BR, E, i, EntryBytes, DataBytes)) { TL.Clear(); break; } if (ProgressCallback != null) { ProgressCallback(null, (double)(i + 1) / EntryCount); } TL.Add(DSTE); } return(TL); }
// Block Layout: // 000-003 U32 Index // 004-007 U32 Unknown // 008-00b U32 Unknown // 00c-00f U32 Unknown // 010-013 U32 Unknown // 014-02b Unknown // 02c-0ab TXT Description // 0ac-27f Unknown // 280-281 U16 Icon Size // 282-bff IMG Icon (+ padding) public bool Read(BinaryReader BR) { this.Clear(); try { byte[] Bytes = BR.ReadBytes(0x280); byte[] IconBytes = BR.ReadBytes(0x980); if (!FFXIEncryption.DecodeDataBlock(Bytes)) { return false; } if (IconBytes[0x97f] != 0xff) { return false; } { // Verify that the icon info is valid Graphic StatusIcon = new Graphic(); BinaryReader IconBR = new BinaryReader(new MemoryStream(IconBytes, false)); int IconSize = IconBR.ReadInt32(); if (IconSize > 0 && IconSize <= 0x97b) { if (!StatusIcon.Read(IconBR) || IconBR.BaseStream.Position != 4 + IconSize) { IconBR.Close(); return false; } } IconBR.Close(); if (StatusIcon == null) { return false; } this.Icon_ = StatusIcon; } BR = new BinaryReader(new MemoryStream(Bytes, false)); } catch { return false; } FFXIEncoding E = new FFXIEncoding(); this.ID_ = BR.ReadUInt16(); this.Unknown1_ = BR.ReadUInt16(); this.Unknown2_ = BR.ReadUInt32(); this.Unknown3_ = BR.ReadUInt32(); this.Unknown4_ = BR.ReadUInt32(); this.Unknown4_ = BR.ReadUInt32(); BR.ReadBytes(0x18); this.Description_ = E.GetString(BR.ReadBytes(128)).TrimEnd('\0'); BR.Close(); return true; }
public bool Read(BinaryReader BR, uint?Index, long EntryStart, long EntryEnd) { this.Clear(); this.Index_ = Index; try { BR.BaseStream.Seek(4 + EntryStart, SeekOrigin.Begin); byte[] TextBytes = BR.ReadBytes((int)(EntryEnd - EntryStart)); for (int i = 0; i < TextBytes.Length; ++i) { TextBytes[i] ^= 0x80; // <= Evil encryption-breaking! } this.Text_ = String.Empty; FFXIEncoding E = new FFXIEncoding(); int LastPos = 0; for (int i = 0; i < TextBytes.Length; ++i) { if (TextBytes[i] == 0x07) // Line Break { if (LastPos < i) { this.Text_ += E.GetString(TextBytes, LastPos, i - LastPos); } this.Text_ += "\r\n"; LastPos = i + 1; } else if (TextBytes[i] == 0x08) // Character Name (You) { if (LastPos < i) { this.Text_ += E.GetString(TextBytes, LastPos, i - LastPos); } this.Text_ += String.Format("{0}Player Name{1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd); LastPos = i + 1; } else if (TextBytes[i] == 0x09) // Character Name (They) { if (LastPos < i) { this.Text_ += E.GetString(TextBytes, LastPos, i - LastPos); } this.Text_ += String.Format("{0}Speaker Name{1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd); LastPos = i + 1; } else if (TextBytes[i] == 0x0a && i + 1 < TextBytes.Length) { if (LastPos < i) { this.Text_ += E.GetString(TextBytes, LastPos, i - LastPos); } this.Text_ += String.Format("{0}Numeric Parameter {2}{1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd, TextBytes[i + 1]); LastPos = i + 2; ++i; } else if (TextBytes[i] == 0x0b) // Indicates that the lines after this are in a prompt window { if (LastPos < i) { this.Text_ += E.GetString(TextBytes, LastPos, i - LastPos); } this.Text_ += String.Format("{0}Selection Dialog{1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd); LastPos = i + 1; } else if (TextBytes[i] == 0x0c && i + 1 < TextBytes.Length) { if (LastPos < i) { this.Text_ += E.GetString(TextBytes, LastPos, i - LastPos); } this.Text_ += String.Format("{0}Multiple Choice (Parameter {2}){1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd, TextBytes[i + 1]); LastPos = i + 2; ++i; } else if (TextBytes[i] == 0x19 && i + 1 < TextBytes.Length) { if (LastPos < i) { this.Text_ += E.GetString(TextBytes, LastPos, i - LastPos); } this.Text_ += String.Format("{0}Item Parameter {2}{1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd, TextBytes[i + 1]); LastPos = i + 2; ++i; } else if (TextBytes[i] == 0x1a && i + 1 < TextBytes.Length) { if (LastPos < i) { this.Text_ += E.GetString(TextBytes, LastPos, i - LastPos); } this.Text_ += String.Format("{0}Key Item Parameter {2}{1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd, TextBytes[i + 1]); LastPos = i + 2; ++i; } else if (TextBytes[i] == 0x1c && i + 1 < TextBytes.Length) // Chocobo Name { if (LastPos < i) { this.Text_ += E.GetString(TextBytes, LastPos, i - LastPos); } this.Text_ += String.Format("{0}Player/Chocobo Parameter {2}{1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd, TextBytes[i + 1]); LastPos = i + 2; ++i; } else if (TextBytes[i] == 0x1e && i + 1 < TextBytes.Length) { if (LastPos < i) { this.Text_ += E.GetString(TextBytes, LastPos, i - LastPos); } this.Text_ += String.Format("{0}Set Color #{2}{1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd, TextBytes[i + 1]); LastPos = i + 2; ++i; } else if (TextBytes[i] == 0x7f && i + 1 < TextBytes.Length) // Various stuff { if (LastPos < i) { this.Text_ += E.GetString(TextBytes, LastPos, i - LastPos); } if (TextBytes[i + 1] == 0x31 && i + 2 < TextBytes.Length) // Unknown, but seems to indicate user needs to hit RET { if (TextBytes[i + 2] != 0) { this.Text_ += String.Format("{0}{2}-Second Delay + Prompt{1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd, TextBytes[i + 2]); } else { this.Text_ += String.Format("{0}Prompt{1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd); } ++LastPos; ++i; } else if (TextBytes[i + 1] == 0x85) // Multiple Choice: Player Gender { this.Text_ += String.Format("{0}Multiple Choice (Player Gender){1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd); } else if (TextBytes[i + 1] == 0x8D && i + 2 < TextBytes.Length) { this.Text_ += String.Format("{0}Weather Event Parameter {2}{1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd, TextBytes[i + 2]); ++LastPos; ++i; } else if (TextBytes[i + 1] == 0x8E && i + 2 < TextBytes.Length) { this.Text_ += String.Format("{0}Weather Type Parameter {2}{1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd, TextBytes[i + 2]); ++LastPos; ++i; } else if (TextBytes[i + 1] == 0x92 && i + 2 < TextBytes.Length) { this.Text_ += String.Format("{0}Singular/Plural Choice (Parameter {2}){1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd, TextBytes[i + 2]); ++LastPos; ++i; } else if (TextBytes[i + 1] == 0xB1 && i + 2 < TextBytes.Length) // Usually found before an item name or key item name { this.Text_ += String.Format("{0}Title Parameter {2}{1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd, TextBytes[i + 2]); ++LastPos; ++i; } else if (i + 2 < TextBytes.Length) { this.Text_ += String.Format("{0}Unknown Parameter (Type: {2:X2}) {3}{1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd, TextBytes[i + 1], TextBytes[i + 2]); ++LastPos; ++i; } else { this.Text_ += String.Format("{0}Unknown Marker Type: {2:X2}{1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd, TextBytes[i + 1]); } LastPos = i + 2; ++i; } else if (TextBytes[i] == 0x7f || TextBytes[i] < 0x20) { if (LastPos < i) { this.Text_ += E.GetString(TextBytes, LastPos, i - LastPos); } this.Text_ += String.Format("{0}Possible Special Code: {2:X2}{1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd, TextBytes[i]); LastPos = i + 1; } } if (LastPos < TextBytes.Length) { this.Text_ += E.GetString(TextBytes, LastPos, TextBytes.Length - LastPos); } this.Text_ = this.Text_.TrimEnd('\0'); return(true); } catch { return(false); } }
public override ThingList Load(BinaryReader BR, ProgressCallback ProgressCallback) { ThingList TL = new ThingList(); if (ProgressCallback != null) { ProgressCallback(I18N.GetText("FTM:CheckingFile"), 0); } if (BR.BaseStream.Length < 0x40 || BR.BaseStream.Position != 0) { return(TL); } FFXIEncoding E = new FFXIEncoding(); if (E.GetString(BR.ReadBytes(8)) != "d_msg".PadRight(8, '\0')) { return(TL); } ushort Flag1 = BR.ReadUInt16(); if (Flag1 != 0 && Flag1 != 1) { return(TL); } ushort Flag2 = BR.ReadUInt16(); if (Flag2 != 0 && Flag2 != 1) { return(TL); } if (BR.ReadUInt32() != 3 || BR.ReadUInt32() != 3) { return(TL); } uint FileSize = BR.ReadUInt32(); if (FileSize != BR.BaseStream.Length) { return(TL); } uint HeaderBytes = BR.ReadUInt32(); if (HeaderBytes != 0x40) { return(TL); } if (BR.ReadUInt32() != 0) { return(TL); } int BytesPerEntry = BR.ReadInt32(); if (BytesPerEntry < 0) { return(TL); } uint DataBytes = BR.ReadUInt32(); if (FileSize != (HeaderBytes + DataBytes) || (DataBytes % BytesPerEntry) != 0) { return(TL); } uint EntryCount = BR.ReadUInt32(); if (EntryCount * BytesPerEntry != DataBytes) { return(TL); } if (BR.ReadUInt32() != 1 || BR.ReadUInt64() != 0 || BR.ReadUInt64() != 0) { return(TL); } if (ProgressCallback != null) { ProgressCallback(I18N.GetText("FTM:LoadingData"), 0); } for (uint i = 0; i < EntryCount; ++i) { BinaryReader EntryBR = new BinaryReader(new MemoryStream(BR.ReadBytes(BytesPerEntry))); EntryBR.BaseStream.Position = 0; bool ItemAdded = false; { Things.DMSGStringBlock SB = new Things.DMSGStringBlock(); if (SB.Read(EntryBR, E, i)) { TL.Add(SB); ItemAdded = true; } } EntryBR.Close(); if (!ItemAdded) { TL.Clear(); break; } if (ProgressCallback != null) { ProgressCallback(null, (double)(i + 1) / EntryCount); } } return(TL); }
public bool Read(BinaryReader BR) { this.Clear(); try { this.ID_ = BR.ReadUInt32(); // Read entry byte[] TextBytes = BR.ReadBytes(0x3b); this.Text_ = String.Empty; // Trim trailing NULs int ByteCount = 0x3b; while (TextBytes[ByteCount - 1] == 0x00) --ByteCount; // Process the message FFXIEncoding E = new FFXIEncoding(); int LastPos = 0; for (int i = 0; i < ByteCount; ++i) { if (TextBytes[i] == 0x07) { // Line Break if (LastPos < i) this.Text_ += E.GetString(TextBytes, LastPos, i - LastPos); this.Text_ += "\r\n"; LastPos = i + 1; } else if (TextBytes[i] == 0x08) { // Character Name (You) if (LastPos < i) this.Text_ += E.GetString(TextBytes, LastPos, i - LastPos); this.Text_ += String.Format("{0}Player Name{1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd); LastPos = i + 1; } else if (TextBytes[i] == 0x09) { // Character Name (They) if (LastPos < i) this.Text_ += E.GetString(TextBytes, LastPos, i - LastPos); this.Text_ += String.Format("{0}Speaker Name{1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd); LastPos = i + 1; } else if (TextBytes[i] == 0x0a && i + 1 < TextBytes.Length) { if (LastPos < i) this.Text_ += E.GetString(TextBytes, LastPos, i - LastPos); this.Text_ += String.Format("{0}Numeric Parameter {2}{1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd, TextBytes[i + 1]); LastPos = i + 2; ++i; } else if (TextBytes[i] == 0x0b) { // Indicates that the lines after this are in a prompt window if (LastPos < i) this.Text_ += E.GetString(TextBytes, LastPos, i - LastPos); this.Text_ += String.Format("{0}Selection Dialog{1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd); LastPos = i + 1; } else if (TextBytes[i] == 0x0c && i + 1 < TextBytes.Length) { if (LastPos < i) this.Text_ += E.GetString(TextBytes, LastPos, i - LastPos); this.Text_ += String.Format("{0}Multiple Choice (Parameter {2}){1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd, TextBytes[i + 1]); LastPos = i + 2; ++i; } else if (TextBytes[i] == 0x19 && i + 1 < TextBytes.Length) { if (LastPos < i) this.Text_ += E.GetString(TextBytes, LastPos, i - LastPos); this.Text_ += String.Format("{0}Item Parameter {2}{1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd, TextBytes[i + 1]); LastPos = i + 2; ++i; } else if (TextBytes[i] == 0x1a && i + 1 < TextBytes.Length) { if (LastPos < i) this.Text_ += E.GetString(TextBytes, LastPos, i - LastPos); this.Text_ += String.Format("{0}Key Item Parameter {2}{1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd, TextBytes[i + 1]); LastPos = i + 2; ++i; } else if (TextBytes[i] == 0x1c && i + 1 < TextBytes.Length) { // Chocobo Name if (LastPos < i) this.Text_ += E.GetString(TextBytes, LastPos, i - LastPos); this.Text_ += String.Format("{0}Player/Chocobo Parameter {2}{1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd, TextBytes[i + 1]); LastPos = i + 2; ++i; } else if (TextBytes[i] == 0x1e && i + 1 < TextBytes.Length) { if (LastPos < i) this.Text_ += E.GetString(TextBytes, LastPos, i - LastPos); this.Text_ += String.Format("{0}Set Color #{2}{1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd, TextBytes[i + 1]); LastPos = i + 2; ++i; } else if (TextBytes[i] == 0x7f && i + 1 < TextBytes.Length) { // Various stuff if (LastPos < i) this.Text_ += E.GetString(TextBytes, LastPos, i - LastPos); if (TextBytes[i + 1] == 0x31 && i + 2 < TextBytes.Length) { // Unknown, but seems to indicate user needs to hit RET if (TextBytes[i + 2] != 0) this.Text_ += String.Format("{0}{2}-Second Delay + Prompt{1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd, TextBytes[i + 2]); else this.Text_ += String.Format("{0}Prompt{1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd); ++LastPos; ++i; } else if (TextBytes[i + 1] == 0x85) // Multiple Choice: Player Gender this.Text_ += String.Format("{0}Multiple Choice (Player Gender){1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd); else if (TextBytes[i + 1] == 0x8D && i + 2 < TextBytes.Length) { this.Text_ += String.Format("{0}Weather Event Parameter {2}{1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd, TextBytes[i + 2]); ++LastPos; ++i; } else if (TextBytes[i + 1] == 0x8E && i + 2 < TextBytes.Length) { this.Text_ += String.Format("{0}Weather Type Parameter {2}{1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd, TextBytes[i + 2]); ++LastPos; ++i; } else if (TextBytes[i + 1] == 0x92 && i + 2 < TextBytes.Length) { this.Text_ += String.Format("{0}Singular/Plural Choice (Parameter {2}){1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd, TextBytes[i + 2]); ++LastPos; ++i; } else if (TextBytes[i + 1] == 0xB1 && i + 2 < TextBytes.Length) { // Usually found before an item name or key item name this.Text_ += String.Format("{0}Title Parameter {2}{1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd, TextBytes[i + 2]); ++LastPos; ++i; } else if (i + 2 < TextBytes.Length) { this.Text_ += String.Format("{0}Unknown Parameter (Type: {2:X2}) {3}{1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd, TextBytes[i + 1], TextBytes[i + 2]); ++LastPos; ++i; } else this.Text_ += String.Format("{0}Unknown Marker Type: {2:X2}{1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd, TextBytes[i + 1]); LastPos = i + 2; ++i; } else if (TextBytes[i] == 0x7f || TextBytes[i] < 0x20) { if (LastPos < i) this.Text_ += E.GetString(TextBytes, LastPos, i - LastPos); this.Text_ += String.Format("{0}Possible Special Code: {2:X2}{1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd, TextBytes[i]); LastPos = i + 1; } } if (LastPos < ByteCount) this.Text_ += E.GetString(TextBytes, LastPos, ByteCount - LastPos); return (BR.ReadByte() == 0xff); } catch { return false; } }
private void TranslateAutoTranslatorFile(int JPFileNumber, int ENFileNumber) { if (!this.BackupFile(JPFileNumber)) { return; } try { string JFileName = FFXI.GetFilePath(JPFileNumber); string EFileName = FFXI.GetFilePath(ENFileNumber); this.AddLogEntry(String.Format(I18N.GetText("TranslatingAutoTrans"), JFileName)); this.AddLogEntry(String.Format(I18N.GetText("UsingEnglishFile"), EFileName)); FileStream ATStream = new FileStream(JFileName, FileMode.Open, FileAccess.ReadWrite, FileShare.None); MemoryStream NewStream = new MemoryStream(); BinaryReader JBR = new BinaryReader(ATStream); BinaryWriter JBW = new BinaryWriter(NewStream); BinaryReader EBR = new BinaryReader(new FileStream(EFileName, FileMode.Open, FileAccess.Read)); FFXIEncoding E = new FFXIEncoding(); while (ATStream.Position != ATStream.Length) { { // Validate & Copy ID uint JID = JBR.ReadUInt32(); uint EID = EBR.ReadUInt32(); if ((JID & 0xffff) != 0x102) { this.AddLogEntry(String.Format(I18N.GetText("ATBadJPID"), JID)); goto TranslationDone; } if ((EID & 0xffff) != 0x202) { this.AddLogEntry(String.Format(I18N.GetText("ATBadENID"), EID)); goto TranslationDone; } if ((EID & 0xffff0000) != (JID & 0xffff0000)) { this.AddLogEntry(String.Format(I18N.GetText("ATIDMismatch"), JID, EID)); goto TranslationDone; } JBW.Write(JID); } // Group name -> use English JBW.Write(EBR.ReadBytes(32)); JBR.BaseStream.Position += 32; // Completion Text -> based on config if (this.mnuPreserveJapaneseATCompletion.Checked) { JBW.Write(JBR.ReadBytes(32)); EBR.BaseStream.Position += 32; } else { byte[] EnglishCompletion = E.GetBytes(E.GetString(EBR.ReadBytes(32)).ToLowerInvariant()); // we want it lowercase if (EnglishCompletion.Length != 32) { this.AddLogEntry(String.Format(I18N.GetText("ATLowercaseProblem"), EnglishCompletion.Length)); goto TranslationDone; } JBW.Write(EnglishCompletion); JBR.BaseStream.Position += 32; } uint JEntryCount = JBR.ReadUInt32(); uint EEntryCount = EBR.ReadUInt32(); if (JEntryCount != EEntryCount) { this.AddLogEntry(String.Format(I18N.GetText("ATCountMismatch"), JEntryCount, EEntryCount)); goto TranslationDone; } JBW.Write(JEntryCount); long EntryBytesPos = JBW.BaseStream.Position; JBW.Write((uint)0); JBR.BaseStream.Position += 4; EBR.BaseStream.Position += 4; for (uint i = 0; i < JEntryCount; ++i) { // Validate & Copy ID uint JID = JBR.ReadUInt32(); uint EID = EBR.ReadUInt32(); if ((JID & 0xffff) != 0x102) { this.AddLogEntry(String.Format(I18N.GetText("ATBadJPID"), JID)); goto TranslationDone; } if ((EID & 0xffff) != 0x202) { this.AddLogEntry(String.Format(I18N.GetText("ATBadENID"), EID)); goto TranslationDone; } if ((EID & 0xffff0000) != (JID & 0xffff0000)) { this.AddLogEntry(String.Format(I18N.GetText("ATIDMismatch"), JID, EID)); goto TranslationDone; } JBW.Write(JID); // Display text -> use English byte[] EnglishText = EBR.ReadBytes(EBR.ReadByte()); JBW.Write((byte)EnglishText.Length); JBW.Write(EnglishText); JBR.BaseStream.Position += 1 + JBR.ReadByte(); // Completion Text -> based on config if (this.mnuPreserveJapaneseATCompletion.Checked) { byte[] JapaneseText = JBR.ReadBytes(JBR.ReadByte()); JBW.Write((byte)JapaneseText.Length); JBW.Write(JapaneseText); } else { byte[] LowerEnglishText = E.GetBytes(E.GetString(EnglishText).ToLowerInvariant()); JBW.Write((byte)LowerEnglishText.Length); JBW.Write(LowerEnglishText); JBR.BaseStream.Position += 1 + JBR.ReadByte(); } } long EndOfGroupPos = JBW.BaseStream.Position; JBW.BaseStream.Position = EntryBytesPos; JBW.Write((uint)(EndOfGroupPos - EntryBytesPos - 4)); JBW.BaseStream.Position = EndOfGroupPos; } ATStream.Seek(0, SeekOrigin.Begin); ATStream.Write(NewStream.ToArray(), 0, (int)NewStream.Length); ATStream.SetLength(NewStream.Length); TranslationDone: ATStream.Close(); NewStream.Close(); EBR.Close(); } catch { this.LogFailure("TranslateAutoTranslator"); } }
public override ThingList Load(BinaryReader BR, ProgressCallback ProgressCallback) { ThingList TL = new ThingList(); if (ProgressCallback != null) { ProgressCallback(I18N.GetText("FTM:CheckingFile"), 0); } if (BR.BaseStream.Length < 0x38 || BR.BaseStream.Position != 0) { return(TL); } FFXIEncoding E = new FFXIEncoding(); // Read past the marker (32 bytes) if ((E.GetString(BR.ReadBytes(10)) != "XISTRING".PadRight(10, '\0')) || BR.ReadUInt16() != 2) { return(TL); } foreach (byte B in BR.ReadBytes(20)) { if (B != 0) { return(TL); } } // Read The Header uint FileSize = BR.ReadUInt32(); if (FileSize != BR.BaseStream.Length) { return(TL); } uint EntryCount = BR.ReadUInt32(); uint EntryBytes = BR.ReadUInt32(); uint DataBytes = BR.ReadUInt32(); BR.ReadUInt32(); // Unknown BR.ReadUInt32(); // Unknown if (EntryBytes != EntryCount * 12 || FileSize != 0x38 + EntryBytes + DataBytes) { return(TL); } if (ProgressCallback != null) { ProgressCallback(I18N.GetText("FTM:LoadingData"), 0); } for (uint i = 0; i < EntryCount; ++i) { Things.XIStringTableEntry XSTE = new Things.XIStringTableEntry(); if (!XSTE.Read(BR, E, i, EntryBytes, DataBytes)) { TL.Clear(); break; } if (ProgressCallback != null) { ProgressCallback(null, (double)(i + 1) / EntryCount); } TL.Add(XSTE); } return(TL); }
// Block Layout: // 000-001 U16 Index // 002-002 U8 Type // 003-003 U8 List Icon ID (e.g. 40-47 for the elemental-colored dots) // 004-005 U16 MP Cost // 006-007 U16 Unknown (used to be the cooldown time) // 008-009 U16 Valid Targets // 00a-029 TXT Name // 02a-129 TXT Description (exact length unknown) // 12a-3fe U8 Padding (NULs) // 3ff-3ff U8 End marker (0xff) public bool Read(BinaryReader BR) { this.Clear(); try { byte[] Bytes = BR.ReadBytes(0x400); if (Bytes[0x3ff] != 0xff || Bytes[9] != 0x00 || !FFXIEncryption.DecodeDataBlock(Bytes)) return false; FFXIEncoding E = new FFXIEncoding(); BR = new BinaryReader(new MemoryStream(Bytes, false)); this.ID_ = BR.ReadUInt16(); this.Type_ = (AbilityType) BR.ReadByte(); this.ListIconID_ = BR.ReadByte(); this.MPCost_ = BR.ReadUInt16(); this.Unknown1_ = BR.ReadUInt16(); this.ValidTargets_ = (ValidTarget) BR.ReadUInt16(); this.Name_ = E.GetString(BR.ReadBytes(32)).TrimEnd('\0'); this.Description_ = E.GetString(BR.ReadBytes(256)).TrimEnd('\0'); BR.Close(); return true; } catch { return false; } }
// Block Layout: // 000-001 U16 Index // 002-003 U16 Magic Type (1/2/3/4/5/6 - White/Black/Summon/Ninja/Bard/Blue) // 004-005 U16 Element // 006-007 U16 Valid Targets // 008-009 U16 Skill // 00a-00b U16 MP Cost // 00c-00c U8 Cast Time (1/4 second) // 00d-00d U8 Recast Delay (1/4 second) // 00e-025 U8 Level required (1 byte per job, 0xff if not learnable; first is for the NUL job, so always 0xff; only 24 slots despite 32 possible job flags) // 026-027 U16 ID (0 for "unused" spells; starts out equal to the index, but doesn't stay that way) // 028-028 U8 List Icon ID (not sure what this is an index of, but it seems to match differences in item icon) // 029-03c CHR Japanese Name (20 bytes) // 03d-051 CHR English Name (20 bytes) // 052-0d1 CHR Japanese Description (128 bytes) // 0d2-151 CHR English Description (128 bytes) // 152-3fe U8 Padding (NULs) // 3ff-3ff U8 End marker (0xff) public bool Read(BinaryReader BR) { this.Clear(); try { byte[] Bytes = BR.ReadBytes(0x400); if (Bytes[0x3] != 0x00 || Bytes[0x5] != 0x00 || Bytes[0x7] != 0x00 || Bytes[0x9] != 0x00 || Bytes[0xf] != 0xff || Bytes[0x3ff] != 0xff) return false; if (!FFXIEncryption.DecodeDataBlock(Bytes)) return false; BR = new BinaryReader(new MemoryStream(Bytes, false)); } catch { return false; } this.Index_ = BR.ReadUInt16(); this.MagicType_ = (MagicType) BR.ReadUInt16(); this.Element_ = (Element) BR.ReadUInt16(); this.ValidTargets_ = (ValidTarget) BR.ReadUInt16(); this.Skill_ = (Skill) BR.ReadUInt16(); this.MPCost_ = BR.ReadUInt16(); this.CastingTime_ = BR.ReadByte(); this.RecastDelay_ = BR.ReadByte(); this.LevelRequired_ = BR.ReadBytes(24); this.ID_ = BR.ReadUInt16(); this.ListIconID_ = BR.ReadByte(); FFXIEncoding E = new FFXIEncoding(); this.JapaneseName_ = E.GetString(BR.ReadBytes( 20)).TrimEnd('\0'); this.EnglishName_ = E.GetString(BR.ReadBytes( 20)).TrimEnd('\0'); this.JapaneseDescription_ = E.GetString(BR.ReadBytes(128)).TrimEnd('\0'); this.EnglishDescription_ = E.GetString(BR.ReadBytes(128)).TrimEnd('\0'); // A slightly newer revision of this format no longer has the names, so mark them unset when empty if (this.JapaneseName_ .Length == 0) this.JapaneseName_ = null; if (this.EnglishName_ .Length == 0) this.EnglishName_ = null; if (this.JapaneseDescription_.Length == 0) this.JapaneseDescription_ = null; if (this.EnglishDescription_ .Length == 0) this.EnglishDescription_ = null; #if DEBUG { // Read the next 64 bits, and report if it's not 0 (means there's new data to identify) ulong Next64 = BR.ReadUInt64(); if (Next64 != 0) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("Nonzero data after entry (Spell #{0}): {1:X16}", this.ID_, Next64); Console.ResetColor(); } } #endif BR.Close(); return true; }
// Block Layout: // 000-001 U16 Index // 002-003 U16 Magic Type (1/2/3/4/5/6 - White/Black/Summon/Ninja/Bard/Blue) // 004-005 U16 Element // 006-007 U16 Valid Targets // 008-009 U16 Skill // 00a-00b U16 MP Cost // 00c-00c U8 Cast Time (1/4 second) // 00d-00d U8 Recast Delay (1/4 second) // 00e-025 U8 Level required (1 byte per job, 0xff if not learnable; first is for the NUL job, so always 0xff; only 24 slots despite 32 possible job flags) // 026-027 U16 ID (0 for "unused" spells; starts out equal to the index, but doesn't stay that way) // 028-028 U8 List Icon ID (not sure what this is an index of, but it seems to match differences in item icon) // 029-03c CHR Japanese Name (20 bytes) // 03d-051 CHR English Name (20 bytes) // 052-0d1 CHR Japanese Description (128 bytes) // 0d2-151 CHR English Description (128 bytes) // 152-3fe U8 Padding (NULs) // 3ff-3ff U8 End marker (0xff) public bool Read(BinaryReader BR) { this.Clear(); try { byte[] Bytes = BR.ReadBytes(0x400); if (Bytes[0x3] != 0x00 || Bytes[0x5] != 0x00 || Bytes[0x7] != 0x00 || Bytes[0x9] != 0x00 || Bytes[0xf] != 0xff || Bytes[0x3ff] != 0xff) { return(false); } if (!FFXIEncryption.DecodeDataBlock(Bytes)) { return(false); } BR = new BinaryReader(new MemoryStream(Bytes, false)); } catch { return(false); } this.Index_ = BR.ReadUInt16(); this.MagicType_ = (MagicType)BR.ReadUInt16(); this.Element_ = (Element)BR.ReadUInt16(); this.ValidTargets_ = (ValidTarget)BR.ReadUInt16(); this.Skill_ = (Skill)BR.ReadUInt16(); this.MPCost_ = BR.ReadUInt16(); this.CastingTime_ = BR.ReadByte(); this.RecastDelay_ = BR.ReadByte(); this.LevelRequired_ = new int[0x18]; for (var i = 0; i < 0x18; ++i) { this.LevelRequired_[i] = BR.ReadInt16(); } this.ID_ = BR.ReadUInt16(); this.ListIconID_ = BR.ReadByte(); BR.ReadBytes(0x04); FFXIEncoding E = new FFXIEncoding(); this.JapaneseName_ = E.GetString(BR.ReadBytes(20)).TrimEnd('\0'); this.EnglishName_ = E.GetString(BR.ReadBytes(20)).TrimEnd('\0'); this.JapaneseDescription_ = E.GetString(BR.ReadBytes(128)).TrimEnd('\0'); this.EnglishDescription_ = E.GetString(BR.ReadBytes(128)).TrimEnd('\0'); // A slightly newer revision of this format no longer has the names, so mark them unset when empty if (this.JapaneseName_.Length == 0) { this.JapaneseName_ = null; } if (this.EnglishName_.Length == 0) { this.EnglishName_ = null; } if (this.JapaneseDescription_.Length == 0) { this.JapaneseDescription_ = null; } if (this.EnglishDescription_.Length == 0) { this.EnglishDescription_ = null; } #if DEBUG { // Read the next 64 bits, and report if it's not 0 (means there's new data to identify) ulong Next64 = BR.ReadUInt64(); if (Next64 != 0) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("Nonzero data after entry (Spell #{0}): {1:X16}", this.ID_, Next64); Console.ResetColor(); } } #endif BR.Close(); return(true); }
public bool Read(BinaryReader BR, uint? Index, long EntryStart, long EntryEnd) { this.Clear(); this.Index_ = Index; try { BR.BaseStream.Seek(4 + EntryStart, SeekOrigin.Begin); byte[] TextBytes = BR.ReadBytes((int) (EntryEnd - EntryStart)); for (int i = 0; i < TextBytes.Length; ++i) TextBytes[i] ^= 0x80; // <= Evil encryption-breaking! this.Text_ = String.Empty; FFXIEncoding E = new FFXIEncoding(); int LastPos = 0; for (int i = 0; i < TextBytes.Length; ++i) { if (TextBytes[i] == 0x07) { // Line Break if (LastPos < i) this.Text_ += E.GetString(TextBytes, LastPos, i - LastPos); this.Text_ += "\r\n"; LastPos = i + 1; } else if (TextBytes[i] == 0x08) { // Character Name (You) if (LastPos < i) this.Text_ += E.GetString(TextBytes, LastPos, i - LastPos); this.Text_ += String.Format("{0}Player Name{1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd); LastPos = i + 1; } else if (TextBytes[i] == 0x09) { // Character Name (They) if (LastPos < i) this.Text_ += E.GetString(TextBytes, LastPos, i - LastPos); this.Text_ += String.Format("{0}Speaker Name{1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd); LastPos = i + 1; } else if (TextBytes[i] == 0x0a && i + 1 < TextBytes.Length) { if (LastPos < i) this.Text_ += E.GetString(TextBytes, LastPos, i - LastPos); this.Text_ += String.Format("{0}Numeric Parameter {2}{1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd, TextBytes[i + 1]); LastPos = i + 2; ++i; } else if (TextBytes[i] == 0x0b) { // Indicates that the lines after this are in a prompt window if (LastPos < i) this.Text_ += E.GetString(TextBytes, LastPos, i - LastPos); this.Text_ += String.Format("{0}Selection Dialog{1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd); LastPos = i + 1; } else if (TextBytes[i] == 0x0c && i + 1 < TextBytes.Length) { if (LastPos < i) this.Text_ += E.GetString(TextBytes, LastPos, i - LastPos); this.Text_ += String.Format("{0}Multiple Choice (Parameter {2}){1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd, TextBytes[i + 1]); LastPos = i + 2; ++i; } else if (TextBytes[i] == 0x19 && i + 1 < TextBytes.Length) { if (LastPos < i) this.Text_ += E.GetString(TextBytes, LastPos, i - LastPos); this.Text_ += String.Format("{0}Item Parameter {2}{1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd, TextBytes[i + 1]); LastPos = i + 2; ++i; } else if (TextBytes[i] == 0x1a && i + 1 < TextBytes.Length) { if (LastPos < i) this.Text_ += E.GetString(TextBytes, LastPos, i - LastPos); this.Text_ += String.Format("{0}Key Item Parameter {2}{1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd, TextBytes[i + 1]); LastPos = i + 2; ++i; } else if (TextBytes[i] == 0x1c && i + 1 < TextBytes.Length) { // Chocobo Name if (LastPos < i) this.Text_ += E.GetString(TextBytes, LastPos, i - LastPos); this.Text_ += String.Format("{0}Player/Chocobo Parameter {2}{1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd, TextBytes[i + 1]); LastPos = i + 2; ++i; } else if (TextBytes[i] == 0x1e && i + 1 < TextBytes.Length) { if (LastPos < i) this.Text_ += E.GetString(TextBytes, LastPos, i - LastPos); this.Text_ += String.Format("{0}Set Color #{2}{1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd, TextBytes[i + 1]); LastPos = i + 2; ++i; } else if (TextBytes[i] == 0x7f && i + 1 < TextBytes.Length) { // Various stuff if (LastPos < i) this.Text_ += E.GetString(TextBytes, LastPos, i - LastPos); if (TextBytes[i + 1] == 0x31 && i + 2 < TextBytes.Length) { // Unknown, but seems to indicate user needs to hit RET if (TextBytes[i + 2] != 0) this.Text_ += String.Format("{0}{2}-Second Delay + Prompt{1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd, TextBytes[i + 2]); else this.Text_ += String.Format("{0}Prompt{1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd); ++LastPos; ++i; } else if (TextBytes[i + 1] == 0x85) // Multiple Choice: Player Gender this.Text_ += String.Format("{0}Multiple Choice (Player Gender){1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd); else if (TextBytes[i + 1] == 0x8D && i + 2 < TextBytes.Length) { this.Text_ += String.Format("{0}Weather Event Parameter {2}{1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd, TextBytes[i + 2]); ++LastPos; ++i; } else if (TextBytes[i + 1] == 0x8E && i + 2 < TextBytes.Length) { this.Text_ += String.Format("{0}Weather Type Parameter {2}{1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd, TextBytes[i + 2]); ++LastPos; ++i; } else if (TextBytes[i + 1] == 0x92 && i + 2 < TextBytes.Length) { this.Text_ += String.Format("{0}Singular/Plural Choice (Parameter {2}){1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd, TextBytes[i + 2]); ++LastPos; ++i; } else if (TextBytes[i + 1] == 0xB1 && i + 2 < TextBytes.Length) { // Usually found before an item name or key item name this.Text_ += String.Format("{0}Title Parameter {2}{1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd, TextBytes[i + 2]); ++LastPos; ++i; } else if (i + 2 < TextBytes.Length) { this.Text_ += String.Format("{0}Unknown Parameter (Type: {2:X2}) {3}{1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd, TextBytes[i + 1], TextBytes[i + 2]); ++LastPos; ++i; } else this.Text_ += String.Format("{0}Unknown Marker Type: {2:X2}{1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd, TextBytes[i + 1]); LastPos = i + 2; ++i; } else if (TextBytes[i] == 0x7f || TextBytes[i] < 0x20) { if (LastPos < i) this.Text_ += E.GetString(TextBytes, LastPos, i - LastPos); this.Text_ += String.Format("{0}Possible Special Code: {2:X2}{1}", FFXIEncoding.SpecialMarkerStart, FFXIEncoding.SpecialMarkerEnd, TextBytes[i]); LastPos = i + 1; } } if (LastPos < TextBytes.Length) this.Text_ += E.GetString(TextBytes, LastPos, TextBytes.Length - LastPos); this.Text_ = this.Text_.TrimEnd('\0'); return true; } catch { return false; } }