public void WhenI2OSPIsPerformedWithAnOutputLengthAndOffsetThatIsSmallerThanNeededForTheGivenByteArray() { ExpectedException.ExpectedType = typeof(ArithmeticException); ExpectedException.MessageShouldContainText = "too large"; byte[] result = new byte[3]; Try(() => BigEndianUtils.ConvertIntegerToOrdinalStringPrimitive(944, 2, ref result, 2)); }
/// <inheritdoc /> /// <remarks> /// Base Mode Specification: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-voprf-06.txt#section-3.4.3.3 /// Input: /// ClientInput input /// Scalar blind /// SerializedElement evaluatedElement /// Output: /// opaque output[Nh] /// def Finalize(input, blind, evaluatedElement): /// unblindedElement = Unblind(blind, evaluatedElement) /// finalizeDST = "VOPRF06-Finalize-" || self.contextString /// hashInput = I2OSP(len(input), 2) || input || /// I2OSP(len(unblindedElement), 2) || unblindedElement || /// I2OSP(len(finalizeDST), 2) || finalizeDST /// return Hash(hashInput) /// </remarks> public byte[] Finalise(byte[] clientInput, byte[] blindScalar, byte[] serverEvaluatedGroupElement) { // unblindedElement = Unblind(blind, evaluatedElement) byte[] unblindedGroupElement = Unblind(blindScalar, serverEvaluatedGroupElement); // DST, a domain separation tag // as per https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-voprf-06.txt#section-5.1 // finalizeDST = "VOPRF06-Finalize-" || self.contextString byte[] finaliseDST = CipherSuite.CreateDomainSeparationTag("Finalize"); // hashInput = I2OSP(len(input), 2) || input || // I2OSP(len(unblindedElement), 2) || unblindedElement || // I2OSP(len(finalizeDST), 2) || finalizeDST byte[] hashInput = ByteArrayUtils.Concatenate(new List <byte[]> { BigEndianUtils.ConvertIntegerToOrdinalStringPrimitive(clientInput.Length, 2), clientInput, BigEndianUtils.ConvertIntegerToOrdinalStringPrimitive(unblindedGroupElement.Length, 2), unblindedGroupElement, BigEndianUtils.ConvertIntegerToOrdinalStringPrimitive(finaliseDST.Length, 2), finaliseDST }); // return Hash(hashInput) return(CipherSuite.HashFunction.HashData(hashInput)); }
public void WhenI2OSPIsPerformedWithMultipleUnsignedIntegersAtDifferentOffsetsInTheSameByteArray() { _actualBytes = new byte[5]; BigEndianUtils.ConvertIntegerToOrdinalStringPrimitive(944, 2, ref _actualBytes, 3); // offset 3 (positions 4 & 5) BigEndianUtils.ConvertIntegerToOrdinalStringPrimitive(257, 2, ref _actualBytes, 0); // offset 0 _expectedBytes = new byte[] { 1, 1, 0, 3, 176 }; // 257 then 0 then 944 in base 256 }
/* Load the contents of an existing TexturePAK */ public override PAKReturnType Load() { if (!File.Exists(FilePathPAK)) { return(PAKReturnType.FAIL_TRIED_TO_LOAD_VIRTUAL_ARCHIVE); } try { /* First, parse the BIN and pull ALL info from it */ BinaryReader ArchiveFileBin = new BinaryReader(File.OpenRead(FilePathBIN)); //Read the header info from the BIN VersionNumber_BIN = ArchiveFileBin.ReadInt32(); if (VersionNumber_BIN != 45) { return(PAKReturnType.FAIL_ARCHIVE_IS_NOT_EXCPETED_TYPE); } //BIN version number is 45 for textures NumberOfEntriesBIN = ArchiveFileBin.ReadInt32(); HeaderListBeginBIN = ArchiveFileBin.ReadInt32(); //Read all file names from BIN string ThisFileName = ""; for (int i = 0; i < NumberOfEntriesBIN; i++) { ThisFileName = ""; for (byte b; (b = ArchiveFileBin.ReadByte()) != 0x00;) { ThisFileName += (char)b; } if (Path.GetExtension(ThisFileName).ToUpper() != ".DDS") { ThisFileName += ".dds"; } //Create texture entry and add filename TEX4 TextureEntry = new TEX4(); TextureEntry.FileName = ThisFileName; TextureEntries.Add(TextureEntry); } //Read the texture headers from the BIN ArchiveFileBin.BaseStream.Position = HeaderListBeginBIN + 12; for (int i = 0; i < NumberOfEntriesBIN; i++) { TextureEntries[i].HeaderPos = (int)ArchiveFileBin.BaseStream.Position; for (int x = 0; x < 4; x++) { TextureEntries[i].Magic += ArchiveFileBin.ReadChar(); } TextureEntries[i].Format = (TextureFormat)ArchiveFileBin.ReadInt32(); TextureEntries[i].Length_V2 = ArchiveFileBin.ReadInt32(); TextureEntries[i].Length_V1 = ArchiveFileBin.ReadInt32(); TextureEntries[i].Texture_V1.Width = ArchiveFileBin.ReadInt16(); TextureEntries[i].Texture_V1.Height = ArchiveFileBin.ReadInt16(); TextureEntries[i].Unk_V1 = ArchiveFileBin.ReadInt16(); TextureEntries[i].Texture_V2.Width = ArchiveFileBin.ReadInt16(); TextureEntries[i].Texture_V2.Height = ArchiveFileBin.ReadInt16(); TextureEntries[i].Unk_V2 = ArchiveFileBin.ReadInt16(); TextureEntries[i].UnknownHeaderBytes = ArchiveFileBin.ReadBytes(20); } /* Second, parse the PAK and pull ONLY header info from it - we'll pull textures when requested (to save memory) */ ArchiveFileBin.Close(); BinaryReader ArchiveFile = new BinaryReader(File.OpenRead(FilePathPAK)); //Read the header info from the PAK BigEndianUtils BigEndian = new BigEndianUtils(); ArchiveFile.BaseStream.Position += 4; //Skip nulls VersionNumber_PAK = BigEndian.ReadInt32(ArchiveFile); if (BigEndian.ReadInt32(ArchiveFile) != VersionNumber_BIN) { throw new Exception("Archive version mismatch!"); } NumberOfEntriesPAK = BigEndian.ReadInt32(ArchiveFile); if (BigEndian.ReadInt32(ArchiveFile) != NumberOfEntriesPAK) { throw new Exception("PAK entry count mismatch!"); } ArchiveFile.BaseStream.Position += 12; //Skip unknowns (1,1,1) //Read the texture headers from the PAK int OffsetTracker = (NumberOfEntriesPAK * 48) + 32; for (int i = 0; i < NumberOfEntriesPAK; i++) { //Header indexes are out of order, so optimise replacements by saving position int HeaderPosition = (int)ArchiveFile.BaseStream.Position; //Pull the entry info byte[] UnknownHeaderLead = ArchiveFile.ReadBytes(8); int PartLength = BigEndian.ReadInt32(ArchiveFile); if (PartLength != BigEndian.ReadInt32(ArchiveFile)) { continue; } byte[] UnknownHeaderTrail_1 = ArchiveFile.ReadBytes(18); //Find the entry TEX4 TextureEntry = TextureEntries[BigEndian.ReadInt16(ArchiveFile)]; TEX4_Part TexturePart = (!TextureEntry.Texture_V1.Saved) ? TextureEntry.Texture_V1 : TextureEntry.Texture_V2; //Write out the info TexturePart.HeaderPos = HeaderPosition; TexturePart.StartPos = OffsetTracker; TexturePart.UnknownHeaderLead = UnknownHeaderLead; TexturePart.Length = PartLength; TexturePart.Saved = true; TexturePart.UnknownHeaderTrail_1 = UnknownHeaderTrail_1; TexturePart.UnknownHeaderTrail_2 = ArchiveFile.ReadBytes(12); //Keep file offset updated OffsetTracker += TexturePart.Length; } HeaderListEndPAK = (int)ArchiveFile.BaseStream.Position; //Close PAK ArchiveFile.Close(); return(PAKReturnType.SUCCESS); } catch (IOException) { return(PAKReturnType.FAIL_COULD_NOT_ACCESS_FILE); } catch (Exception) { return(PAKReturnType.FAIL_UNKNOWN); } }
/* Replace an existing file in the TexturePAK archive */ public override PAKReturnType ReplaceFile(string PathToNewFile, string FileName) { try { //Get the texture entry & parse new DDS int EntryIndex = GetFileIndex(FileName); if (EntryIndex == -1) { return(PAKReturnType.FAIL_GENERAL_LOGIC_ERROR); //CHANGED FOR OPENCAGE } TEX4 TextureEntry = TextureEntries[EntryIndex]; DDSReader NewTexture = new DDSReader(PathToNewFile); //Currently we only apply the new texture to the "biggest", some have lower mips that we don't edit (TODO) TEX4_Part BiggestPart = TextureEntry.Texture_V2; if (BiggestPart.HeaderPos == -1 || !BiggestPart.Saved) { BiggestPart = TextureEntry.Texture_V1; } if (BiggestPart.HeaderPos == -1 || !BiggestPart.Saved) { return(PAKReturnType.FAIL_REQUEST_IS_UNSUPPORTED); //Shouldn't reach this. } //CATHODE seems to ignore texture header information regarding size, so as default, resize any imported textures to the original size. //An option is provided in the toolkit to write size information to the header (done above) however, so don't resize if that's the case. //More work needs to be done to figure out why CATHODE doesn't honour the header's size value. int OriginalLength = BiggestPart.Length; Array.Resize(ref NewTexture.DataBlock, OriginalLength); //Update our internal knowledge of the textures BiggestPart.Length = (int)NewTexture.DataBlock.Length; BiggestPart.Width = (Int16)NewTexture.Width; BiggestPart.Height = (Int16)NewTexture.Height; TextureEntry.Format = NewTexture.Format; //TODO: Update smallest here too if it exists! //Will need to be written into the PAK at "Pull PAK sections before/after V2" too - headers are handled already. //Load the BIN and write out updated BIN texture header BinaryWriter ArchiveFileBinWriter = new BinaryWriter(File.OpenWrite(FilePathBIN)); ExtraBinaryUtils BinaryUtils = new ExtraBinaryUtils(); ArchiveFileBinWriter.BaseStream.Position = TextureEntry.HeaderPos; BinaryUtils.WriteString(TextureEntry.Magic, ArchiveFileBinWriter); ArchiveFileBinWriter.Write(BitConverter.GetBytes((int)TextureEntry.Format)); ArchiveFileBinWriter.Write((TextureEntry.Texture_V2.Length == -1) ? 0 : TextureEntry.Texture_V2.Length); ArchiveFileBinWriter.Write(TextureEntry.Texture_V1.Length); ArchiveFileBinWriter.Write(TextureEntry.Texture_V1.Width); ArchiveFileBinWriter.Write(TextureEntry.Texture_V1.Height); ArchiveFileBinWriter.Write(TextureEntry.Unk_V1); ArchiveFileBinWriter.Write(TextureEntry.Texture_V2.Width); ArchiveFileBinWriter.Write(TextureEntry.Texture_V2.Height); ArchiveFileBinWriter.Write(TextureEntry.Unk_V2); ArchiveFileBinWriter.Write(TextureEntry.UnknownHeaderBytes); ArchiveFileBinWriter.Close(); //Update headers for V1+2 in PAK if they exist BinaryWriter ArchiveFileWriter = new BinaryWriter(File.OpenWrite(FilePathPAK)); BigEndianUtils BigEndian = new BigEndianUtils(); if (TextureEntry.Texture_V1.HeaderPos != -1) { ArchiveFileWriter.BaseStream.Position = TextureEntry.Texture_V1.HeaderPos; ArchiveFileWriter.Write(TextureEntry.Texture_V1.UnknownHeaderLead); ArchiveFileWriter.Write(BigEndian.FlipEndian(BitConverter.GetBytes(TextureEntry.Texture_V1.Length))); ArchiveFileWriter.Write(BigEndian.FlipEndian(BitConverter.GetBytes(TextureEntry.Texture_V1.Length))); ArchiveFileWriter.Write(TextureEntry.Texture_V1.UnknownHeaderTrail_1); ArchiveFileWriter.Write(BigEndian.FlipEndian(BitConverter.GetBytes((Int16)EntryIndex))); ArchiveFileWriter.Write(TextureEntry.Texture_V1.UnknownHeaderTrail_2); } if (TextureEntry.Texture_V2.HeaderPos != -1) { ArchiveFileWriter.BaseStream.Position = TextureEntry.Texture_V2.HeaderPos; ArchiveFileWriter.Write(TextureEntry.Texture_V2.UnknownHeaderLead); ArchiveFileWriter.Write(BigEndian.FlipEndian(BitConverter.GetBytes(TextureEntry.Texture_V2.Length))); ArchiveFileWriter.Write(BigEndian.FlipEndian(BitConverter.GetBytes(TextureEntry.Texture_V2.Length))); ArchiveFileWriter.Write(TextureEntry.Texture_V2.UnknownHeaderTrail_1); ArchiveFileWriter.Write(BigEndian.FlipEndian(BitConverter.GetBytes((Int16)EntryIndex))); ArchiveFileWriter.Write(TextureEntry.Texture_V2.UnknownHeaderTrail_2); } ArchiveFileWriter.Close(); //Pull PAK sections before/after V2 BinaryReader ArchiveFile = new BinaryReader(File.OpenRead(FilePathPAK)); byte[] PAK_Pt1 = ArchiveFile.ReadBytes(BiggestPart.StartPos); ArchiveFile.BaseStream.Position += OriginalLength; byte[] PAK_Pt2 = ArchiveFile.ReadBytes((int)ArchiveFile.BaseStream.Length - (int)ArchiveFile.BaseStream.Position); ArchiveFile.Close(); //Write the PAK back out with new content ArchiveFileWriter = new BinaryWriter(File.OpenWrite(FilePathPAK)); ArchiveFileWriter.BaseStream.SetLength(0); ArchiveFileWriter.Write(PAK_Pt1); ArchiveFileWriter.Write(NewTexture.DataBlock); ArchiveFileWriter.Write(PAK_Pt2); ArchiveFileWriter.Close(); return(PAKReturnType.SUCCESS); } catch (IOException) { return(PAKReturnType.FAIL_COULD_NOT_ACCESS_FILE); } catch (Exception) { return(PAKReturnType.FAIL_UNKNOWN); } }
/* Load the contents of an existing ModelPAK */ public override PAKReturnType Load() { if (!File.Exists(FilePathPAK)) { return(PAKReturnType.FAIL_TRIED_TO_LOAD_VIRTUAL_ARCHIVE); } /* TODO: Verify the PAK loading is a ModelPAK by BIN version number */ try { //First, parse the MTL file to find material info string PathToMTL = FilePathPAK.Substring(0, FilePathPAK.Length - 3) + "MTL"; BinaryReader ArchiveFileMtl = new BinaryReader(File.OpenRead(PathToMTL)); //Header ArchiveFileMtl.BaseStream.Position += 40; //There are some knowns here, just not required for us yet int MaterialEntryCount = ArchiveFileMtl.ReadInt16(); ArchiveFileMtl.BaseStream.Position += 2; //Skip unknown //Strings - more work will be done on materials eventually, //but taking their names for now is good enough for model export List <string> MaterialEntries = new List <string>(); string ThisMaterialString = ""; for (int i = 0; i < MaterialEntryCount; i++) { while (true) { byte ThisByte = ArchiveFileMtl.ReadByte(); if (ThisByte == 0x00) { MaterialEntries.Add(ThisMaterialString); ThisMaterialString = ""; break; } ThisMaterialString += (char)ThisByte; } } ArchiveFileMtl.Close(); //Read the header info from BIN BinaryReader ArchiveFileBin = new BinaryReader(File.OpenRead(FilePathBIN)); ArchiveFileBin.BaseStream.Position += 4; //Skip magic TableCountPt2 = ArchiveFileBin.ReadInt32(); ArchiveFileBin.BaseStream.Position += 4; //Skip unknown TableCountPt1 = ArchiveFileBin.ReadInt32(); //Skip past table 1 for (int i = 0; i < TableCountPt1; i++) { byte ThisByte = 0x00; while (ThisByte != 0xFF) { ThisByte = ArchiveFileBin.ReadByte(); } } ArchiveFileBin.BaseStream.Position += 23; //Read file list info FilenameListEnd = ArchiveFileBin.ReadInt32(); int FilenameListStart = (int)ArchiveFileBin.BaseStream.Position; //Read all file names (bytes) byte[] filename_bytes = ArchiveFileBin.ReadBytes(FilenameListEnd); //Read table 2 (skipping all unknowns for now) ExtraBinaryUtils BinaryUtils = new ExtraBinaryUtils(); for (int i = 0; i < TableCountPt2; i++) { CS2 new_entry = new CS2(); new_entry.FilenameOffset = ArchiveFileBin.ReadInt32(); new_entry.Filename = BinaryUtils.GetStringFromByteArray(filename_bytes, new_entry.FilenameOffset); ArchiveFileBin.BaseStream.Position += 4; new_entry.ModelPartNameOffset = ArchiveFileBin.ReadInt32(); new_entry.ModelPartName = BinaryUtils.GetStringFromByteArray(filename_bytes, new_entry.ModelPartNameOffset); ArchiveFileBin.BaseStream.Position += 44; new_entry.MaterialLibaryIndex = ArchiveFileBin.ReadInt32(); new_entry.MaterialName = MaterialEntries[new_entry.MaterialLibaryIndex]; ArchiveFileBin.BaseStream.Position += 8; new_entry.BlockSize = ArchiveFileBin.ReadInt32(); ArchiveFileBin.BaseStream.Position += 14; new_entry.ScaleFactor = ArchiveFileBin.ReadInt16(); //Maybe? ArchiveFileBin.BaseStream.Position += 2; new_entry.VertCount = ArchiveFileBin.ReadInt16(); new_entry.FaceCount = ArchiveFileBin.ReadInt16(); new_entry.BoneCount = ArchiveFileBin.ReadInt16(); ModelEntries.Add(new_entry); } ArchiveFileBin.Close(); //Get extra info from each header in the PAK BinaryReader ArchiveFile = new BinaryReader(File.OpenRead(FilePathPAK)); BigEndianUtils BigEndian = new BigEndianUtils(); ArchiveFile.BaseStream.Position += 32; //Skip header for (int i = 0; i < TableCountPt2; i++) { ArchiveFile.BaseStream.Position += 8; //Skip unknowns int ThisPakSize = BigEndian.ReadInt32(ArchiveFile); if (ThisPakSize != BigEndian.ReadInt32(ArchiveFile)) { //Dud entry... handle this somehow? } int ThisPakOffset = BigEndian.ReadInt32(ArchiveFile); ArchiveFile.BaseStream.Position += 14; int ThisIndex = BigEndian.ReadInt16(ArchiveFile); ArchiveFile.BaseStream.Position += 12; if (ThisIndex == -1) { continue; //Again, dud entry. Need to look into this! } //Push it into the correct entry ModelEntries[ThisIndex].PakSize = ThisPakSize; ModelEntries[ThisIndex].PakOffset = ThisPakOffset; } HeaderListEnd = (int)ArchiveFile.BaseStream.Position; //Done! ArchiveFile.Close(); return(PAKReturnType.SUCCESS); } catch (IOException) { return(PAKReturnType.FAIL_COULD_NOT_ACCESS_FILE); } catch (Exception) { return(PAKReturnType.FAIL_UNKNOWN); } }
public void WhenOS2IPIsPerformedWithAByteArrayForTheMaxSizeOfAnUnsignedInteger() { byte[] bytes = { 255, 255, 255, 255 }; // max in base 256 _expectedInt = uint.MaxValue; _actualInt = BigEndianUtils.ConvertOrdinalStringToIntegerPrimitive(bytes); }
public void WhenOS2IPIsPerformedWithAByteArrayThatIsNotPaddedWithZeros() { byte[] bytes = { 3, 176 }; // 944 in base 256 _expectedInt = 944; _actualInt = BigEndianUtils.ConvertOrdinalStringToIntegerPrimitive(bytes); }
public void WhenI2OSPIsPerformedWithAnOutputLengthThatIsSmallerThanNeeded() { ExpectedException.ExpectedType = typeof(ArithmeticException); ExpectedException.MessageShouldContainText = "too large"; Try(() => BigEndianUtils.ConvertIntegerToOrdinalStringPrimitive(944, 1)); }
public void WhenI2OSPIsPerformedWithAnExactlyCorrectOutputLength() { _actualBytes = BigEndianUtils.ConvertIntegerToOrdinalStringPrimitive(944, 2).ToArray(); _expectedBytes = new byte[] { 3, 176 }; // 944 in base 256 }
public void WhenI2OSPIsPerformedWithALargerOutputLengthThanIsNeeded() { _actualBytes = BigEndianUtils.ConvertIntegerToOrdinalStringPrimitive(944, 3).ToArray(); _expectedBytes = new byte[] { 0, 3, 176 }; // 944 in base 256 }