/// <summary> /// Parses a decimal from a protobuf stream /// </summary> public static decimal ReadDecimal(ProtoReader reader) { ulong low = 0; uint high = 0; uint signScale = 0; int fieldNumber; SubItemToken token = ProtoReader.StartSubItem(reader); while ((fieldNumber = reader.ReadFieldHeader()) > 0) { switch (fieldNumber) { case FieldDecimalLow: low = reader.ReadUInt64(); break; case FieldDecimalHigh: high = reader.ReadUInt32(); break; case FieldDecimalSignScale: signScale = reader.ReadUInt32(); break; default: reader.SkipField(); break; } } ProtoReader.EndSubItem(token, reader); if (low == 0 && high == 0) { return(decimal.Zero); } int lo = (int)(low & 0xFFFFFFFFL), mid = (int)((low >> 32) & 0xFFFFFFFFL), hi = (int)high; bool isNeg = (signScale & 0x0001) == 0x0001; byte scale = (byte)((signScale & 0x01FE) >> 1); return(new decimal(lo, mid, hi, isNeg, scale)); }
private static void WriteTimeSpanImpl(TimeSpan timeSpan, ProtoWriter dest, DateTimeKind kind) { if (dest == null) { throw new ArgumentNullException(nameof(dest)); } switch (dest.WireType) { case WireType.String: case WireType.StartGroup: TimeSpanScale scale; long value = timeSpan.Ticks; if (timeSpan == TimeSpan.MaxValue) { value = 1; scale = TimeSpanScale.MinMax; } else if (timeSpan == TimeSpan.MinValue) { value = -1; scale = TimeSpanScale.MinMax; } else if (value % TimeSpan.TicksPerDay == 0) { scale = TimeSpanScale.Days; value /= TimeSpan.TicksPerDay; } else if (value % TimeSpan.TicksPerHour == 0) { scale = TimeSpanScale.Hours; value /= TimeSpan.TicksPerHour; } else if (value % TimeSpan.TicksPerMinute == 0) { scale = TimeSpanScale.Minutes; value /= TimeSpan.TicksPerMinute; } else if (value % TimeSpan.TicksPerSecond == 0) { scale = TimeSpanScale.Seconds; value /= TimeSpan.TicksPerSecond; } else if (value % TimeSpan.TicksPerMillisecond == 0) { scale = TimeSpanScale.Milliseconds; value /= TimeSpan.TicksPerMillisecond; } else { scale = TimeSpanScale.Ticks; } SubItemToken token = ProtoWriter.StartSubItemWithoutWritingHeader(null, dest); if (value != 0) { ProtoWriter.WriteFieldHeader(FieldTimeSpanValue, WireType.SignedVariant, dest); ProtoWriter.WriteInt64(value, dest); } if (scale != TimeSpanScale.Days) { ProtoWriter.WriteFieldHeader(FieldTimeSpanScale, WireType.Variant, dest); ProtoWriter.WriteInt32((int)scale, dest); } if (kind != DateTimeKind.Unspecified) { ProtoWriter.WriteFieldHeader(FieldTimeSpanKind, WireType.Variant, dest); ProtoWriter.WriteInt32((int)kind, dest); } ProtoWriter.EndSubItem(token, dest); break; case WireType.Fixed64: ProtoWriter.WriteInt64(timeSpan.Ticks, dest); break; default: throw new ProtoException("Unexpected wire-type: " + dest.WireType.ToString()); } }
private static long ReadTimeSpanTicks(ProtoReader source, out DateTimeKind kind) { kind = DateTimeKind.Unspecified; switch (source.WireType) { case WireType.String: case WireType.StartGroup: SubItemToken token = ProtoReader.StartSubItem(source); int fieldNumber; TimeSpanScale scale = TimeSpanScale.Days; long value = 0; while ((fieldNumber = source.ReadFieldHeader()) > 0) { switch (fieldNumber) { case FieldTimeSpanScale: scale = (TimeSpanScale)source.ReadInt32(); break; case FieldTimeSpanValue: source.Assert(WireType.SignedVariant); value = source.ReadInt64(); break; case FieldTimeSpanKind: kind = (DateTimeKind)source.ReadInt32(); switch (kind) { case DateTimeKind.Unspecified: case DateTimeKind.Utc: case DateTimeKind.Local: break; // fine default: throw new ProtoException("Invalid date/time kind: " + kind.ToString()); } break; default: source.SkipField(); break; } } ProtoReader.EndSubItem(token, source); switch (scale) { case TimeSpanScale.Days: return(value * TimeSpan.TicksPerDay); case TimeSpanScale.Hours: return(value * TimeSpan.TicksPerHour); case TimeSpanScale.Minutes: return(value * TimeSpan.TicksPerMinute); case TimeSpanScale.Seconds: return(value * TimeSpan.TicksPerSecond); case TimeSpanScale.Milliseconds: return(value * TimeSpan.TicksPerMillisecond); case TimeSpanScale.Ticks: return(value); case TimeSpanScale.MinMax: switch (value) { case 1: return(long.MaxValue); case -1: return(long.MinValue); default: throw new ProtoException("Unknown min/max value: " + value.ToString()); } default: throw new ProtoException("Unknown timescale: " + scale.ToString()); } case WireType.Fixed64: return(source.ReadInt64()); default: throw new ProtoException("Unexpected wire-type: " + source.WireType.ToString()); } }
/// <summary> /// Writes an *implementation specific* bundled .NET object, including (as options) type-metadata, identity/re-use, etc. /// </summary> public static SubItemToken WriteNetObject_Start(object value, ProtoWriter dest, BclHelpers.NetObjectOptions options, out int dynamicTypeKey, out bool writeObject) { #if FEAT_IKVM throw new NotSupportedException(); #else if (dest == null) { throw new ArgumentNullException(nameof(dest)); } dynamicTypeKey = -1; // length not prefixed to not move data in buffer twice just because of NetObject (will be another nested inside) SubItemToken token = ProtoWriter.StartSubItem(null, false, dest); if (value == null) { // null handling writeObject = false; return(token); } // even root object can be wrapped with collection // so it's not true root writeObject = true; if ((options & BclHelpers.NetObjectOptions.AsReference) != 0) { bool existing; int objectKey = dest.NetCache.AddObjectKey(value, out existing); ProtoWriter.WriteFieldHeader(existing ? FieldExistingObjectKey : FieldNewObjectKey, WireType.Variant, dest); ProtoWriter.WriteInt32(objectKey, dest); if (existing) { writeObject = false; } } if (writeObject) { if ((options & BclHelpers.NetObjectOptions.DynamicType) != 0) { bool existing; Type type = value.GetType(); dynamicTypeKey = dest.GetTypeKey(ref type); int typeRefKey = dest.NetCache.AddObjectKey(type, out existing); ProtoWriter.WriteFieldHeader(existing ? FieldExistingTypeKey : FieldNewTypeKey, WireType.Variant, dest); ProtoWriter.WriteInt32(typeRefKey, dest); if (!existing) { ProtoWriter.WriteFieldHeader(FieldTypeName, WireType.String, dest); ProtoWriter.WriteString(dest.SerializeType(type), dest); } } // do nothing, write will be outside ProtoWriter.WriteFieldHeaderBegin((options & BclHelpers.NetObjectOptions.WriteAsLateReference) != 0 ? FieldLateReferenceObject : FieldObject, dest); } return(token); #endif }
// this method is split because we need to insert our implementation inside and it's hard to deal with delegates in emit public static void ReadNetObject_EndWithNoteNewObject(object value, ProtoReader source, object oldValue, Type type, int newObjectKey, int newTypeRefKey, BclHelpers.NetObjectOptions options, SubItemToken token) { ReadNetObject_NoteNewObject(value, source, oldValue, type, newObjectKey, newTypeRefKey, options); ProtoReader.EndSubItem(token, source); }
/// <summary> /// Reads an *implementation specific* bundled .NET object, including (as options) type-metadata, identity/re-use, etc. /// </summary> public static SubItemToken ReadNetObject_Start(ref object value, ProtoReader source, ref Type type, BclHelpers.NetObjectOptions options, out bool isDynamic, out bool isLateReference, ref int typeKey, out int newObjectKey, out int newTypeRefKey, out bool shouldEnd) { #if FEAT_IKVM throw new NotSupportedException(); #else shouldEnd = false; newObjectKey = -1; newTypeRefKey = -1; isDynamic = false; isLateReference = false; SubItemToken token = ProtoReader.StartSubItem(source); int fieldNumber; if ((fieldNumber = source.ReadFieldHeader()) == 0) { // null handling value = null; return(token); } do { int tmp; switch (fieldNumber) { case FieldExistingObjectKey: tmp = source.ReadInt32(); value = source.NetCache.GetKeyedObject(tmp); break; case FieldNewObjectKey: newObjectKey = source.ReadInt32(); break; case FieldExistingTypeKey: tmp = source.ReadInt32(); type = (Type)source.NetCache.GetKeyedObject(tmp); typeKey = source.GetTypeKey(ref type); break; case FieldNewTypeKey: newTypeRefKey = source.ReadInt32(); break; case FieldTypeName: string typeName = source.ReadString(); type = source.DeserializeType(typeName); if (type == null) { throw new ProtoException("Unable to resolve type: " + typeName + " (you can use the TypeModel.DynamicTypeFormatting event to provide a custom mapping)"); } typeKey = source.GetTypeKey(ref type); isDynamic = true; break; case FieldLateReferenceObject: case FieldObject: if (fieldNumber == FieldLateReferenceObject) { isLateReference = true; } shouldEnd = true; bool wasNull = value == null; bool lateSet = wasNull && ((options & BclHelpers.NetObjectOptions.LateSet) != 0); if (newObjectKey >= 0 && !lateSet) { if (value == null) { source.TrapNextObject(newObjectKey); } else { source.NetCache.SetKeyedObject(newObjectKey, value); } if (newTypeRefKey >= 0) { source.NetCache.SetKeyedObject(newTypeRefKey, type); } } return(token); default: source.SkipField(); break; } } while ((fieldNumber = source.ReadFieldHeader()) > 0); return(token); #endif }