internal void ReadCells(BinaryReaderEx br, PARAMDEF paramdef) { // In case someone decides to add new rows before applying the paramdef (please don't do that) if (DataOffset == 0) { return; } Def = paramdef; br.Position = DataOffset; var cells = new Cell[paramdef.Fields.Count]; int bitOffset = -1; PARAMDEF.DefType bitType = PARAMDEF.DefType.u8; uint bitValue = 0; for (int i = 0; i < paramdef.Fields.Count; i++) { PARAMDEF.Field field = paramdef.Fields[i]; object value = null; PARAMDEF.DefType type = field.DisplayType; if (type == PARAMDEF.DefType.s8) { value = br.ReadSByte(); } else if (type == PARAMDEF.DefType.s16) { value = br.ReadInt16(); } else if (type == PARAMDEF.DefType.s32) { value = br.ReadInt32(); } else if (type == PARAMDEF.DefType.f32) { value = br.ReadSingle(); } else if (type == PARAMDEF.DefType.fixstr) { value = br.ReadFixStr(field.ArrayLength); } else if (type == PARAMDEF.DefType.fixstrW) { value = br.ReadFixStrW(field.ArrayLength * 2); } else if (ParamUtil.IsBitType(type)) { if (field.BitSize == -1) { if (type == PARAMDEF.DefType.u8) { value = br.ReadByte(); } else if (type == PARAMDEF.DefType.u16) { value = br.ReadUInt16(); } else if (type == PARAMDEF.DefType.u32) { value = br.ReadUInt32(); } else if (type == PARAMDEF.DefType.dummy8) { value = br.ReadBytes(field.ArrayLength); } } } else { throw new NotImplementedException($"Unsupported field type: {type}"); } if (value != null) { bitOffset = -1; } else { PARAMDEF.DefType newBitType = type == PARAMDEF.DefType.dummy8 ? PARAMDEF.DefType.u8 : type; int bitLimit = ParamUtil.GetBitLimit(newBitType); if (field.BitSize == 0) { throw new NotImplementedException($"Bit size 0 is not supported."); } if (field.BitSize > bitLimit) { throw new InvalidDataException($"Bit size {field.BitSize} is too large to fit in type {newBitType}."); } if (bitOffset == -1 || newBitType != bitType || bitOffset + field.BitSize > bitLimit) { bitOffset = 0; bitType = newBitType; if (bitType == PARAMDEF.DefType.u8) { bitValue = br.ReadByte(); } else if (bitType == PARAMDEF.DefType.u16) { bitValue = br.ReadUInt16(); } else if (bitType == PARAMDEF.DefType.u32) { bitValue = br.ReadUInt32(); } } uint shifted = bitValue << (32 - field.BitSize - bitOffset) >> (32 - field.BitSize); bitOffset += field.BitSize; if (bitType == PARAMDEF.DefType.u8) { value = (byte)shifted; } else if (bitType == PARAMDEF.DefType.u16) { value = (ushort)shifted; } else if (bitType == PARAMDEF.DefType.u32) { value = shifted; } } cells[i] = new Cell(field, value); } Cells = cells; }
internal void WriteCells(BinaryWriterEx bw, byte format2D, int index) { if ((format2D & 0x7F) < 4) { bw.FillUInt32($"RowOffset{index}", (uint)bw.Position); } else { bw.FillInt64($"RowOffset{index}", bw.Position); } int bitOffset = -1; PARAMDEF.DefType bitType = PARAMDEF.DefType.u8; uint bitValue = 0; for (int i = 0; i < Cells.Count; i++) { Cell cell = Cells[i]; object value = cell.Value; PARAMDEF.Field field = cell.Def; PARAMDEF.DefType type = field.DisplayType; if (type == PARAMDEF.DefType.s8) { bw.WriteSByte((sbyte)value); } else if (type == PARAMDEF.DefType.s16) { bw.WriteInt16((short)value); } else if (type == PARAMDEF.DefType.s32) { bw.WriteInt32((int)value); } else if (type == PARAMDEF.DefType.f32) { bw.WriteSingle((float)value); } else if (type == PARAMDEF.DefType.fixstr) { bw.WriteFixStr((string)value, field.ArrayLength); } else if (type == PARAMDEF.DefType.fixstrW) { bw.WriteFixStrW((string)value, field.ArrayLength * 2); } else if (ParamUtil.IsBitType(type)) { if (field.BitSize == -1) { if (type == PARAMDEF.DefType.u8) { bw.WriteByte((byte)value); } else if (type == PARAMDEF.DefType.u16) { bw.WriteUInt16((ushort)value); } else if (type == PARAMDEF.DefType.u32) { bw.WriteUInt32((uint)value); } else if (type == PARAMDEF.DefType.dummy8) { bw.WriteBytes((byte[])value); } } else { if (bitOffset == -1) { bitOffset = 0; bitType = type == PARAMDEF.DefType.dummy8 ? PARAMDEF.DefType.u8 : type; bitValue = 0; } uint shifted = 0; if (bitType == PARAMDEF.DefType.u8) { shifted = (byte)value; } else if (bitType == PARAMDEF.DefType.u16) { shifted = (ushort)value; } else if (bitType == PARAMDEF.DefType.u32) { shifted = (uint)value; } // Shift left first to clear any out-of-range bits shifted = shifted << (32 - field.BitSize) >> (32 - field.BitSize - bitOffset); bitValue |= shifted; bitOffset += field.BitSize; bool write = false; if (i == Cells.Count - 1) { write = true; } else { PARAMDEF.Field nextField = Cells[i + 1].Def; PARAMDEF.DefType nextType = nextField.DisplayType; int bitLimit = ParamUtil.GetBitLimit(bitType); if (!ParamUtil.IsBitType(nextType) || nextField.BitSize == -1 || bitOffset + nextField.BitSize > bitLimit || (nextType == PARAMDEF.DefType.dummy8 ? PARAMDEF.DefType.u8 : nextType) != bitType) { write = true; } } if (write) { bitOffset = -1; if (bitType == PARAMDEF.DefType.u8) { bw.WriteByte((byte)bitValue); } else if (bitType == PARAMDEF.DefType.u16) { bw.WriteUInt16((ushort)bitValue); } else if (bitType == PARAMDEF.DefType.u32) { bw.WriteUInt32(bitValue); } } } } else { throw new NotImplementedException($"Unsupported field type: {type}"); } } }
private static int WriteMemoryCell(PARAM.Cell cell, IntPtr CellDataPtr, ref int bitFieldPos, ref BitArray bits, SoulsMemoryHandler memoryHandler) { PARAMDEF.DefType displayType = cell.Def.DisplayType; // If this can be simplified, that would be ideal. Currently we have to reconcile DefType, a numerical size in bits, and the Type used for the bitField array if (cell.Def.BitSize != -1) { if (displayType == SoulsFormats.PARAMDEF.DefType.u8) { if (bitFieldPos == 0) { bits = new BitArray(8); } bits.Set(bitFieldPos, Convert.ToBoolean(cell.Value)); bitFieldPos++; if (bitFieldPos == 8) { byte valueRead = 0; memoryHandler.ReadProcessMemory(CellDataPtr, ref valueRead); byte[] bitField = new byte[1]; bits.CopyTo(bitField, 0); bitFieldPos = 0; byte bitbuffer = bitField[0]; if (valueRead != bitbuffer) { memoryHandler.WriteProcessMemory(CellDataPtr, ref bitbuffer); } return(sizeof(byte)); } return(0); } else if (displayType == SoulsFormats.PARAMDEF.DefType.u16) { if (bitFieldPos == 0) { bits = new BitArray(16); } bits.Set(bitFieldPos, Convert.ToBoolean(cell.Value)); bitFieldPos++; if (bitFieldPos == 16) { ushort valueRead = 0; memoryHandler.ReadProcessMemory(CellDataPtr, ref valueRead); ushort[] bitField = new ushort[1]; bits.CopyTo(bitField, 0); bitFieldPos = 0; ushort bitbuffer = bitField[0]; if (valueRead != bitbuffer) { memoryHandler.WriteProcessMemory(CellDataPtr, ref bitbuffer); } return(sizeof(UInt16)); } return(0); } else if (displayType == SoulsFormats.PARAMDEF.DefType.u32) { if (bitFieldPos == 0) { bits = new BitArray(32); } bits.Set(bitFieldPos, Convert.ToBoolean(cell.Value)); bitFieldPos++; if (bitFieldPos == 32) { uint valueRead = 0; memoryHandler.ReadProcessMemory(CellDataPtr, ref valueRead); uint[] bitField = new uint[1]; bits.CopyTo(bitField, 0); bitFieldPos = 0; uint bitbuffer = bitField[0]; if (valueRead != bitbuffer) { memoryHandler.WriteProcessMemory(CellDataPtr, ref bitbuffer); } return(sizeof(UInt32)); } return(0); } } if (displayType == SoulsFormats.PARAMDEF.DefType.f32) { float valueRead = 0f; memoryHandler.ReadProcessMemory(CellDataPtr, ref valueRead); float value = Convert.ToSingle(cell.Value); if (valueRead != value) { memoryHandler.WriteProcessMemory(CellDataPtr, ref value); } return(sizeof(float)); } else if (displayType == SoulsFormats.PARAMDEF.DefType.s32) { int valueRead = 0; memoryHandler.ReadProcessMemory(CellDataPtr, ref valueRead); int value = Convert.ToInt32(cell.Value); if (valueRead != value) { memoryHandler.WriteProcessMemory(CellDataPtr, ref value); } return(sizeof(Int32)); } else if (displayType == SoulsFormats.PARAMDEF.DefType.s16) { short valueRead = 0; memoryHandler.ReadProcessMemory(CellDataPtr, ref valueRead); short value = Convert.ToInt16(cell.Value); if (valueRead != value) { memoryHandler.WriteProcessMemory(CellDataPtr, ref value); } return(sizeof(Int16)); } else if (displayType == SoulsFormats.PARAMDEF.DefType.s8) { sbyte valueRead = 0; memoryHandler.ReadProcessMemory(CellDataPtr, ref valueRead); sbyte value = Convert.ToSByte(cell.Value); if (valueRead != value) { memoryHandler.WriteProcessMemory(CellDataPtr, ref value); } return(sizeof(sbyte)); } else if (displayType == SoulsFormats.PARAMDEF.DefType.u32) { uint valueRead = 0; memoryHandler.ReadProcessMemory(CellDataPtr, ref valueRead); uint value = Convert.ToUInt32(cell.Value); if (valueRead != value) { memoryHandler.WriteProcessMemory(CellDataPtr, ref value); } return(sizeof(UInt32)); } else if (displayType == SoulsFormats.PARAMDEF.DefType.u16) { ushort valueRead = 0; memoryHandler.ReadProcessMemory(CellDataPtr, ref valueRead); ushort value = Convert.ToUInt16(cell.Value); if (valueRead != value) { memoryHandler.WriteProcessMemory(CellDataPtr, ref value); } return(sizeof(UInt16)); } else if (displayType == SoulsFormats.PARAMDEF.DefType.u8) { byte valueRead = 0; memoryHandler.ReadProcessMemory(CellDataPtr, ref valueRead); byte value = Convert.ToByte(cell.Value); if (valueRead != value) { memoryHandler.WriteProcessMemory(CellDataPtr, ref value); } return(sizeof(byte)); } else if (displayType == SoulsFormats.PARAMDEF.DefType.dummy8 || displayType == SoulsFormats.PARAMDEF.DefType.fixstr || displayType == SoulsFormats.PARAMDEF.DefType.fixstrW) { return(cell.Def.ArrayLength); } else { throw new Exception("Unexpected Field Type"); } }