-
Notifications
You must be signed in to change notification settings - Fork 63
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Field is set to the wrong value after serialize to file #171
Comments
The serializer does not support non-trivial getters and setters so the body of your setter will not be used during deserialization. Maybe that's the problem? |
But the TerminatedString flag should append a 00 byte at serialization time right? So far i have this working by using a byte array instead: /// <summary>
/// Gets the size of the printer model
/// </summary>
[FieldOrder(3)]
[FieldEndianness(Endianness.Big)]
public uint PrinterModelSize { get; set; } = 6;
[FieldOrder(4)]
[FieldLength(nameof(PrinterModelSize))]
public byte[] PrinterModelArray { get; set; } = { 0x43, 0x4C, 0x2D, 0x38, 0x39, 0x0 };
[Ignore]
public string PrinterModel
{
get => Encoding.ASCII.GetString(PrinterModelArray).TrimEnd(char.MinValue);
set
{
PrinterModelArray = Encoding.ASCII.GetBytes(value + char.MinValue);
PrinterModelSize = (uint) PrinterModelArray.Length;
}
} |
I have a similar usage case that a string is null-terminated at the same time prefixed with FieldLength. I looked up at the source code it seems when FieldLength is there, then null-termination won't apply. Similarly I have resorted to using a custom class. |
Can you share your custom class to fix this? |
Mine is not a lot better than yours indeed.
One concern is that you would always want to interact via I didn't do benchmark on which is more performant. The main reason of why I didn't widely use it in my codebase is that this requires to new the MyString class everywhere. I say I can easily make use of code generator to assist me defining my binary classes but I yet to come up effective solution to seamlessly use ordinary string. |
Ah, i tought you created some sort of custom flag attribute to deal with this strings, for example: |
All these adds up to more level of indirections in order to more seamlessly to use primitives:
Usage:
Along with that it is also less likely for the remaining part of code to accidentally use the |
Sorry, just getting back to this. Have either of you tried a ValueConverter to solve this? |
Today i step again with a field of this type, so i tried to use a ValueConverter on FieldLength, it output the right length to the file field but the string would not respect the size and not output a extra 00 byte in the end of the string. Maybe i'm doing this wrong but i can't find a way to manipulate the string value on serialization time Class: public class NullTerminatedLengthConverter : IValueConverter
{
// Read
public object Convert(object value, object converterParameter, BinarySerializationContext context)
{
return value;
}
// Write
public object ConvertBack(object value, object converterParameter, BinarySerializationContext context)
{
return System.Convert.ToUInt32(value) + 1;
}
}
public sealed class SlicerInfoV3
{
[FieldOrder(0)] [FieldEndianness(Endianness.Big)] public uint SoftwareNameSize { get; set; } = (uint)About.SoftwareWithVersion.Length + 1;
[FieldOrder(1)]
[FieldLength(nameof(SoftwareNameSize), ConverterType = typeof(NullTerminatedLengthConverter))]
[SerializeAs(SerializedType.TerminatedString)]
public string SoftwareName { get; set; } = About.SoftwareWithVersion;
[FieldOrder(2)] [FieldEndianness(Endianness.Big)] public uint MaterialNameSize { get; set; }
[FieldOrder(3)]
[FieldLength(nameof(MaterialNameSize), ConverterType = typeof(NullTerminatedLengthConverter))]
[SerializeAs(SerializedType.TerminatedString)]
public string MaterialName { get; set; }
[FieldOrder(4)] public uint Unknown1 { get; set; }
[FieldOrder(5)] public uint Unknown2 { get; set; }
[FieldOrder(6)] public uint Unknown3 { get; set; }
[FieldOrder(7)] public uint Unknown4 { get; set; }
[FieldOrder(8)] public byte Unknown5 { get; set; } = 1;
[FieldOrder(9)] public byte LightPWM { get; set; } = byte.MaxValue;
[FieldOrder(10)] public ushort Unknown6 { get; set; } = 2;
[FieldOrder(11)] public PageBreak PageBreak { get; set; } = new();
} Note that the SoftwareNameSize is correct now (16), and text is 15 length but there is a missing 0x00 byte on the end of the string. So i get 00 00 00 1A but i should get 00 00 00 00 1A just after the string We need a simple way to keep this null terminated strings intact on both read and write time... |
Have you tried this as below? /// <summary>
/// Gets the size of the printer model
/// </summary>
[FieldOrder(3)]
[FieldEndianness(Endianness.Big)]
public uint PrinterModelSize;
/// <summary>
/// Gets the printer model
/// </summary>
[FieldOrder(4)]
[FieldLength(nameof(PrinterModelSize))]
[SerializeAs(SerializedType.TerminatedString)]
public string? PrinterModel; I think the nullability of the PrinterModel is important here, to provide the PrinterModelSize=0 option. It's possible that this won't actually work. But I'd argue in this situation it would be a bug in the BinarySerializer. |
@bevanweiss the main problem is that
I solved that by implementing a custom class NullTerminatedUintStringBigEndian which also uses nullable value |
Ahh yes, I think I do recall this when I was looking into the Graph logic I wasn't a fan of how it did this. [FieldLength(4)]
[SerializeAs(SerializeType.TerminatedString]]
public string LongString = "This string here"; it should result in a Serialized output of Likewise if it's [FieldLength(4)]
[SerializeAs(SerializeType.TerminatedString]]
public string LongString = "T"; it should result in a Serialized output of @jefffhaynes Is there a particular reason for the current behaviour (where FieldLength removed the TerminatedString type)? |
I think I agree with your reasoning here. Probably just an oversight on my part when I first wrote it. Changing it would be a breaking change but probably not a significant one? 🤞 |
I'll put together a PR for this (maybe this week.. maybe into next week). |
This allows to keep the existing TerminatedString behaviour when a field length constraint is applied, where it essentially becomes a SizedString. Whilst also allowing new behaviour that would keep the terminated string aspect, but truncate / pad the terminated string around the length constraint Test case shows non-standard terminator (\n or 0x0A), and non-standard padding byte 0x0D just to prove that these work as expected also. Possibly fixes jefffhaynes#171 (confirmation required) Signed-off-by: Bevan Weiss <[email protected]>
I'm having a problem where i set a field to be 6 and on file is written with 5
Here's the defenition:
I place a breakpoint on both PrinterModelSize = string.IsNullOrEmpty(value) ? 0 : (uint)value.Length+1; and public uint PrinterModelSize { get; set; } = 6; Both shows 6 with a value of "CL-89" which is correct since it have a null terminated char (00)
When the file got written that field turn into 5. Does it redefine the value when serializing due the link with [FieldLength(nameof(PrinterModelSize))] ? If so is there a way to overcome this?
EDIT 1:
I added to attribute
[FieldLength(nameof(PrinterModelSize), BindingMode = BindingMode.OneWay)]
, that way the size become 6 but string still not null terminated (no zero appended)The text was updated successfully, but these errors were encountered: