/// <summary> /// Scale result using the given fieldFormat /// </summary> /// <param name="fieldFormat"></param> /// <param name="result"></param> /// <returns></returns> private static decimal ScaleResult(FieldFormat fieldFormat, decimal result) { decimal returnedResult = result; if (fieldFormat.Decimal > 0 && fieldFormat.ImpliedDecimal) { returnedResult = returnedResult * (decimal)Math.Pow(10, -fieldFormat.Decimal); } return returnedResult; }
/// <summary> /// Custom constructor using FieldFormat and read data /// </summary> /// <param name="fieldFormat"></param> /// <param name="readData"></param> public FieldParsingException(FieldFormat fieldFormat, byte[] readData) : base(string.Format("Error while reading field {0} - read data: {1}", fieldFormat.Name, readData)) { _fieldFormat = fieldFormat; _readData = new byte[readData.Length]; readData.CopyTo(_readData, 0); }
/// <summary> /// Constructor for deserialization. /// </summary> /// <param name="info">the info holding the serialization data</param> /// <param name="context">the serialization context</param> public FieldParsingException(SerializationInfo info, StreamingContext context) : base(info, context) { _fieldFormat = (FieldFormat) info.GetValue("FieldFormat", typeof(FieldFormat)); _readData = (byte[]) info.GetValue("ReadData", typeof (byte[])); }
/// <summary> /// Construct a dedicated ValueTypeMismatchException based on given inputs /// </summary> /// <param name="field"></param> /// <param name="fieldFormat"></param> /// <param name="expectedType"></param> /// <returns>a dedicated ValueTypeMismatchException</returns> private ValueTypeMismatchException GetValueTypeMismatchException(object field, FieldFormat fieldFormat, string expectedType) { return new ValueTypeMismatchException(string.Format(ErrorMessage, fieldFormat.Name, expectedType, field.GetType().Name)); }
/// <summary> /// Encode object as text, using current encoding /// </summary> /// <param name="field"></param> /// <param name="fieldFormat"></param> /// <returns></returns> /// <exception cref="ValueTypeMismatchException"> </exception> private byte[] EncodeText(object field, FieldFormat fieldFormat) { var s = field as string; if (s != null) { string value = s; int size = fieldFormat.ByteSize; if (value.Length > size) { return _encoding.GetBytes(value.Substring(0, size)); } else if (value.Length < size) { StringBuilder sb = new StringBuilder(size); sb.Append(value); for (int i = 0; i < size - value.Length; i++) { sb.Append(' '); } return _encoding.GetBytes(sb.ToString()); } else { return _encoding.GetBytes(value); } } else { throw GetValueTypeMismatchException(field, fieldFormat, "string"); } }
/// <summary> /// Encode given object in a transparent way. Only applies to existing byte array having correct length. /// All other situations will lead to throwing a ValueTypeMismatchException. /// </summary> /// <param name="field"></param> /// <param name="fieldFormat"></param> /// <returns></returns> /// <exception cref="ValueTypeMismatchException"> </exception> private byte[] EncodeTransparent(object field, FieldFormat fieldFormat) { var bytes = field as byte[]; if (bytes != null) { if (bytes.Length == fieldFormat.ByteSize) { return bytes; } else { throw new ValueTypeMismatchException("Value size must be equal to field length."); } } else { throw GetValueTypeMismatchException(field, fieldFormat, "byte[]"); } }
/// <summary> /// Encode decimal to binary. Only accept decimal or throw ValueTypeMismatchException. /// </summary> /// <param name="field"></param> /// <param name="fieldFormat"></param> /// <returns></returns> /// <exception cref="ValueTypeMismatchException"> </exception> private byte[] EncodeBinary(object field, FieldFormat fieldFormat) { if (!(field is decimal)) { throw GetValueTypeMismatchException(field, fieldFormat, "decimal"); } decimal value = (decimal)field; if (fieldFormat.Decimal != GetScale(value)) { value = Math.Round(value, fieldFormat.Decimal); } byte[] bytes = GetUnscaledValueAsByteArray(value); if (bytes.Length == fieldFormat.ByteSize) { return bytes; } byte[] result = new byte[fieldFormat.ByteSize]; if (value < 0) { for (var i = 0; i < result.Length - bytes.Length; i++) { result[i] = 255; } } Buffer.BlockCopy(bytes, 0, result, result.Length - bytes.Length, bytes.Length); return result; }
/// <summary> /// Encode objet as packed number /// </summary> /// <param name="field"></param> /// <param name="fieldFormat"></param> /// <returns></returns> /// <exception cref="ValueTypeMismatchException"> </exception> private byte[] EncodePacked(object field, FieldFormat fieldFormat) { if (field is decimal) { return EncodePacked((decimal)field, fieldFormat.ByteSize, fieldFormat.Decimal, fieldFormat.Signed); } else { throw GetValueTypeMismatchException(field, fieldFormat, "decimal"); } }
/// <summary> /// Encode object as zoned number. /// </summary> /// <param name="field"></param> /// <param name="fieldFormat"></param> /// <returns></returns> /// <exception cref="ValueTypeMismatchException"> </exception> private byte[] EncodeZoned(object field, FieldFormat fieldFormat) { if (field is decimal) { return _encoding.GetBytes(EncodeZoned((decimal)field, fieldFormat.ByteSize, fieldFormat.Decimal, fieldFormat.Signed, fieldFormat.ImpliedDecimal)); } else { throw GetValueTypeMismatchException(field, fieldFormat, "decimal"); } }
/// <summary> /// Encodes a C# object to a byte array using EBCDIC format. /// Main method. /// </summary> /// <param name="field">the object to encode</param> /// <param name="fieldFormat">the format of the field</param> /// <returns>an array of byte with the encoded field value</returns> /// <exception cref="ValueTypeMismatchException"> if the object to encode is not of the expected type</exception> /// <exception cref="UnexpectedFieldTypeException"> if the type field is unknown or unsupported</exception> public byte[] Encode(object field, FieldFormat fieldFormat) { byte[] result; if (field == null) { result = new byte[fieldFormat.ByteSize]; for (int i = 0; i < fieldFormat.ByteSize; i++) { result[i] = _defaultValue; } return result; } char type = fieldFormat.Type[0]; switch (type) { case '9': result = EncodeZoned(field, fieldFormat); break; case '3': result = EncodePacked(field, fieldFormat); break; case 'B': result = EncodeBinary(field, fieldFormat); break; case 'T': result = EncodeTransparent(field, fieldFormat); break; case 'X': result = EncodeText(field, fieldFormat); break; default: throw new UnexpectedFieldTypeException(type); } return result; }
public void EbcdicTestsTest() { FieldFormat binary = new FieldFormat { Decimal = 0, Size = "6", Type = "B" }; EbcdicEncoder encoder = new EbcdicEncoder("ascii"); EbcdicDecoder decoder = new EbcdicDecoder("ascii"); decimal value1 = -1937m; decimal value2 = 1937m; Assert.AreEqual(value1, decoder.Decode(encoder.Encode(value1, binary), binary)); Assert.AreEqual(value2, decoder.Decode(encoder.Encode(value2, binary), binary)); }
/// <summary> /// Technical read byte array, given length and field format /// </summary> /// <param name="length"></param> /// <param name="fieldFormat"></param> /// <returns></returns> /// <exception cref="IOException"> </exception> /// <exception cref="EbcdicException"> </exception> private byte[] Read(int length, FieldFormat fieldFormat) { byte[] bytes = new byte[length]; int readBytes = _stream.Read(bytes); if (readBytes == 0) // note : -1 in java { throw new EndOfFileException(); } if (readBytes < length) { throw new FieldParsingException(fieldFormat, bytes); } return bytes; }
/// <summary> /// read a field /// </summary> /// <param name="fieldFormat"></param> /// <param name="readNumericValues"></param> /// <returns></returns> private object ReadField(FieldFormat fieldFormat, IDictionary<string, decimal> readNumericValues) { List<object> values = new List<object>(); int occurs; if (fieldFormat.HasDependencies()) { if (readNumericValues.ContainsKey(fieldFormat.DependingOn)) { occurs = Decimal.ToInt32(readNumericValues[fieldFormat.DependingOn]); } else { throw new System.Exception( string.Format("Check your copybook :[{0}] is not present, but field format says it has dependencies ...", fieldFormat.DependingOn)); } } else { occurs = fieldFormat.Occurs; } for (int i = 0; i < occurs; i++) { byte[] bytes = Read(fieldFormat.ByteSize, fieldFormat); object value = _decoder.Decode(bytes, fieldFormat); values.Add(value); if (value is decimal) { readNumericValues[fieldFormat.Name] = (decimal)value; } } if (fieldFormat.HasDependencies() || occurs > 1) { // if occurs is variable or greater than one, return results in a list return values; } else { // otherwise, just return the single item return values[0]; } }
/// <summary> /// Decode a byte array using the packed format /// </summary> /// <param name="bytes"></param> /// <param name="fieldFormat"></param> /// <returns></returns> private static decimal DecodePacked(byte[] bytes, FieldFormat fieldFormat) { decimal result = ParsePacked(bytes); result = ScaleResult(fieldFormat, result); return result; }
/// <summary> /// Decode a byte array using the zoned format /// </summary> /// <param name="bytes"></param> /// <param name="fieldFormat"></param> /// <returns></returns> private decimal DecodeZoned(byte[] bytes, FieldFormat fieldFormat) { var toParse = (_encoding.GetString(bytes)).Trim(); if (toParse == string.Empty) { return decimal.Zero; } decimal result = ParseZoned(toParse); result = ScaleResult(fieldFormat, result); return result; }
/// <summary> /// Main decode method. Switch based on the given FieldFormat /// </summary> /// <param name="bytes"></param> /// <param name="fieldFormat"></param> /// <returns></returns> /// <exception cref="UnexpectedFieldTypeException"> </exception> public object Decode(byte[] bytes, FieldFormat fieldFormat) { char type = fieldFormat.Type[0]; object result; switch (type) { case '9': result = DecodeZoned(bytes, fieldFormat); break; case '3': result = DecodePacked(bytes, fieldFormat); break; case 'B': Array.Reverse(bytes); // needed as C# does not use same endianness as java on biginteger construction result = ((decimal)new BigInteger(bytes) * (decimal)Math.Pow(10, -fieldFormat.Decimal)); break; case 'T': result = bytes; break; case 'H': result = DecodeHex(bytes); break; case 'X': result = _encoding.GetString(bytes); break; default: throw new UnexpectedFieldTypeException(type); } return result; }