无法打开包装" COMP-3" .NET中的数据

时间:2015-10-16 17:58:40

标签: .net bcd comp-3

从我们的供应商提供给我们的文件中解包包含数字和日期数据的COMP-3字段时,我们遇到了一些困难。

文件规范提供以下信息:

0066-0070 DATE-OPENED S9(9) COMP-3

规范表明日期将扩展为MMDDYYYY格式。

当我从文件中检索这个数据块时,我可以将它加载到内存中,看看我检索了5个字节的数据。 (在文件中,每个字符有一个字节。)检索的字节如下:

0: 10
1:  0
2: 18
3:  0
4:  2

没有任何迹象超过最重要的数字(它总是出现的地方),因此这里不是问题。这些位扩展为以下半字节:

0 1 0 0 1 2 0 0 0 2

这里有几个问题:

  1. 01001200极不可能代表MMDDYYYY格式的有效日期,但这似乎是数据打包到字段中的方式。

  2. 解压缩COMP-3字段时,模板指定它应扩展为9个字符,但如果展开COMP-3,则其大小将始终 double(生成一个具有偶数个字符的字符串)。因此,预期大小与未打包大小之间存在不匹配。

  3. 我在网上找不到的算法似乎无法解压缩这些数据。似乎没有什么能够在源文件中为任何(假设的)BCD值提供可识别的日期。

  4. 此时我怀疑我们可能没有处理真正的BCD格式。但是,请记住,我应该总是怀疑自己而不是工具,我正在寻找建议,因为我对COMP-3格式的理解以及我所看到的数据的性质都可能出错。

    我对格式的理解来自以下来源:

    值得注意的是,在尝试打开包装之前,我曾尝试将数据从EBCDIC转换为ASCII,反之亦然;既没有产生任何可理解的结果。我尝试过在互联网上找到的每一种算法,但它们似乎都没有产生任何有用的结果。

    我想,最后,我的问题是:我实际上是在处理BCD或COMP-3数据吗?

    更新

    回答一些问题:

    1. 一旦我确定该值包含一个符号半字节,我就清除了那个半字节。
    2. 我已经包含了所有可以使用的代码,以便您可以清楚地看到我正在做的事情。该类旨在提供大量诊断信息(如字节和半字节属性),以便您在解析值后可以看到它的结果。
    3. 我们手头有原始和未解析的文件作为参考资料。我期待回来的日期与06152008的情况类似(这是我头脑中的一个,但你得到了主旨)。 I' m计算的值是 nothing

      根据请求,个别小吃:

      0 1 0 0 1 2 0 0 0 2

      对于那些对我如何做这件事感兴趣的人来说,正在拆包的课程:

      using System.Collections.Generic;
      using System.Linq;
      using System.Text;
      
      internal class PackedDecimal
      {
          #region Fields
          private bool _isPositive;
          private bool _isNegative;
          private bool _isUnsigned = true;
      
          #endregion
      
          #region Constructor
          /// <summary>
          /// Initializes a new instance of the <see cref="PackedDecimal"/> class.
          /// </summary>
          public PackedDecimal()
          {
          }
      
          /// <summary>
          /// Initializes a new instance of the <see cref="PackedDecimal"/> class.
          /// </summary>
          /// <param name="compressedDecimal">The compressed decimal.</param>
          public PackedDecimal(string compressedDecimal)
          {
              this.ParsedValue = this.Parse(compressedDecimal);
          }
          #endregion
      
          #region Properties
          /// <summary>
          /// Gets the bytes.
          /// </summary>
          public IEnumerable<byte> Bytes { get; private set; } 
      
          /// <summary>
          /// Gets the hexadecimal values.
          /// </summary>
          public IEnumerable<string> HexValues { get; private set; }
      
          /// <summary>
          /// Gets or sets a value indicating whether this instance is positive.
          /// </summary>
          /// <value>
          /// <c>true</c> if this instance is positive; otherwise, <c>false</c>.
          /// </value>
          public bool IsPositive
          {
              get { return this._isPositive; }
              set
              {
                  this._isNegative = !this.IsPositive;
                  this._isUnsigned = false;
              }
          }
      
          /// <summary>
          /// Gets or sets a value indicating whether this instance is negative.
          /// </summary>
          /// <value>
          /// <c>true</c> if this instance is negative; otherwise, <c>false</c>.
          /// </value>
          public bool IsNegative
          {
              get { return this._isNegative; }
              set
              {
                  this._isNegative = value;
                  this._isPositive = !value;
                  this._isUnsigned = false;
              }
          }
      
          /// <summary>
          /// Gets a value indicating whether this instance is unsigned.
          /// </summary>
          /// <value>
          /// <c>true</c> if this instance is unsigned; otherwise, <c>false</c>.
          /// </value>
          public bool IsUnsigned { get { return this._isUnsigned; } }
      
          /// <summary>
          /// Gets the nibbles.
          /// </summary>
          public IEnumerable<int> Nibbles { get; private set; }
      
          /// <summary>
          /// Gets the parsed value.
          /// </summary>
          public string ParsedValue { get; private set; }
          #endregion
      
          /// <summary>
          /// Parses the specified value.
          /// </summary>
          /// <param name="value">The value.</param>
          /// <returns></returns>
          public string Parse(string value, SourceEncoding sourceEncoding = SourceEncoding.Ascii, int decimalPlaces = 0)
          {
              var localValue = value; // Encoding.Convert(Encoding.ASCII, Encoding.GetEncoding("IBM037"), value.ToByteArray()).FromByteArray();
              var sign = this.GetSign(localValue, out localValue);
              var bytes = localValue.ToByteArray();
              var nibbles = new List<int>();
      
              var buffer = new StringBuilder();
      
              foreach (var b in bytes)
              {
                  var hi = (int)b.HiNibble();
                  var lo = (int)b.LoNibble();
                  nibbles.Add(hi);
                  nibbles.Add(lo);
      
                  buffer.AppendFormat("{0}{1}", hi, lo);
              }
      
              this.Bytes = bytes;
              this.Nibbles = nibbles;
              this.HexValues = nibbles.Select(v => v.ToString("X"));
      
              switch (sign)
              {
                  case Sign.Unsigned:
                      this.ParsedValue = buffer.ToString();
                      break;
      
                  case Sign.Positive:
                      this.ParsedValue = "+" + buffer;
                      break;
      
                  case Sign.Negative:
                      this.ParsedValue = "-" + buffer;
                      break;
              }
      
              this.IsPositive = sign == Sign.Positive;
              this.IsNegative = sign == Sign.Negative;
      
              return this.ParsedValue;
          }
      
          #region GetSign Method
          /// <summary>
          /// Gets the sign for the packed decimal represented by this instance.
          /// </summary>
          /// <param name="value">The value to analyze.</param>
          /// <param name="buffer">Receives <paramref name="value"/>, less the sign digit if it is present.</param>
          /// <returns>The sign for the packed decimal represented by this instance.</returns>
          /// <remarks>If the value provided does not include a sign digit, it is assumed to be unsigned.</remarks>
          private Sign GetSign(string value, out string buffer)
          {
              var lastDigit = value.ToByteArray().Last();
              var loNibble = lastDigit.LoNibble();
              var hiNibble = lastDigit.HiNibble();
      
              var result = Sign.Unsigned;
      
              var hasSignDigit = true;
      
              switch (hiNibble)
              {
                  case 0xC0: // "c"
                      result = Sign.Positive;
                      break;
      
                  case 0xD0: // "d"
                      result = Sign.Negative;
                      break;
      
                  case 0xF0: // "f"
                      result = Sign.Unsigned;
                      break;
      
                  default:
                      hasSignDigit = false;
                      break;
              }
      
              // Remove the sign digit if it's present.
              buffer = hasSignDigit 
                  ? value.Substring(0, value.Length - 1) + loNibble 
                  : value;
      
              return result;
          }
          #endregion
      
          #region Sign Enum
          private enum Sign
          {
              Unsigned,
              Positive,
              Negative
          }
          #endregion
      }
      

      支持它的扩展方法:

      using System;
      using System.Linq;
      using System.Text;
      
      public static class Extensions
      {
          /// <summary>
          /// Gets the high nibble (the high 4 bits) from a byte.
          /// </summary>
          /// <param name="value">The byte from which the high 4-bit nibble will be retrieved.</param>
          /// <returns>A byte containing the value of this byte, with all bits shifted four bits to the right.</returns>
          public static byte HiNibble(this byte value)
          {
              return (byte)((value & 0xF0) >> 4);
          }
      
          /// <summary>
          /// Gets the low nibble (the lowest 4 bits) from this byte.
          /// </summary>
          /// <param name="value">The byte from which the low 4-bit nibble will be retrieved.</param>
          /// <returns>A byte containing the value of this byte, with the high four bits discarded.</returns>
          public static byte LoNibble(this byte value)
          {
              return (byte)(value & 0x0F);
          }
      
          /// <summary>
          /// Gets the individual bytes from a string.
          /// </summary>
          /// <param name="value">The string to convert to a byte array.</param>
          /// <returns>An array of bytes representing the string.</returns>
          public static byte[] ToByteArray(this string value)
          {
              var bytes = new byte[Encoding.ASCII.GetByteCount(value)];
              Buffer.BlockCopy(value.ToCharArray(), 0, bytes, 0, bytes.Length);
              return bytes;
          }
      }
      
      public enum SourceEncoding
      {
          Ascii,
          Ebcdic
      }
      

0 个答案:

没有答案