// 根据 byte [] 建立一个 Element 对象 // parameter: // bytes [out] 返回本次用掉的 byte 数 public static Element Parse(byte[] data, int start, out int bytes) { bytes = 0; if (start >= data.Length) { throw new ArgumentException($"start 值 {start} 不应越过 data length {data.Length}"); } int offset = start; Element element = new Element(); if (data.Length - offset < 1) { throw new Exception($"data 长度不足,从 {offset} 开始应至少为 1 bytes"); } element._precursor = new Precursor(data[offset]); offset++; // OID 为 1-14, 元素存储结构为 Precursor + Length of data + Compacted data if (element._precursor.ObjectIdentifier <= 14) { element.OID = element._precursor.ObjectIdentifier; } else { // OID 为 15-127。元素存储结构为 Precursor + Relative-OID 15 to 127 + Length of data + Compacted data if (data.Length - offset < 3) { throw new Exception($"data 长度不足,从 {offset} 开始应至少为 3 bytes"); } element.OID = 15 + data[offset]; offset++; } if (data.Length - offset < 2) { throw new Exception($"data 长度不足,从 {offset} 开始应至少为 2 bytes"); } if (element._precursor.Offset == true) { // 填充字节数 element._paddings = data[offset]; offset++; } element._lengthOfData = data[offset]; offset++; if (data.Length - offset < element._lengthOfData) { throw new Exception($"data 长度不足,从 {offset} 开始应至少为 {element._lengthOfData} bytes"); } element._compactedData = new byte[element._lengthOfData]; Array.Copy(data, offset, element._compactedData, 0, element._lengthOfData); bytes = offset - start + element._lengthOfData + element._paddings; // 解析出 Text if (element._precursor.CompactionCode == (int)CompactionScheme.ApplicationDefined) { if (element.OID == (int)ElementOID.OwnerInstitution || element.OID == (int)ElementOID.IllBorrowingInstitution ) { element.Text = Compress.IsilExtract(element._compactedData); } else { // 只能用 Content 表示 element.Content = element._compactedData; // TODO: 此时 Text 里面放什么?是否要让 get Text 抛出异常引起注意? } } else { if (element._precursor.CompactionCode == (int)CompactionScheme.Integer) { element.Text = Compress.IntegerExtract(element._compactedData); } else if (element._precursor.CompactionCode == (int)CompactionScheme.Integer) { element.Text = Compress.IntegerExtract(element._compactedData); } else if (element._precursor.CompactionCode == (int)CompactionScheme.Numeric) { element.Text = Compress.NumericExtract(element._compactedData); } else if (element._precursor.CompactionCode == (int)CompactionScheme.FivebitCode) { element.Text = Compress.Bit5Extract(element._compactedData); } else if (element._precursor.CompactionCode == (int)CompactionScheme.SixBitCode) { element.Text = Compress.Bit6Extract(element._compactedData); } else if (element._precursor.CompactionCode == (int)CompactionScheme.SevenBitCode) { element.Text = Compress.Bit7Extract(element._compactedData); } else if (element._precursor.CompactionCode == (int)CompactionScheme.OctectString) { element.Text = Encoding.ASCII.GetString(element._compactedData); } else if (element._precursor.CompactionCode == (int)CompactionScheme.Utf8String) { element.Text = Encoding.UTF8.GetString(element._compactedData); } else { throw new Exception($"出现意料之外的 CompactScheme {element._precursor.CompactionCode}"); } } return(element); }
// 根据 OID 和字符内容,构造一个 element 的原始数据 // parameters: // text 内容文字。如果是给 ISIL 类型的, 要明确用 compact_method 指明 // alignment 对齐 block 边界 public static byte[] Compact(int oid, string text, CompactionScheme compact_method, bool alignment) { Precursor precursor = new Precursor(); precursor.ObjectIdentifier = oid; // 自动选定压缩方案 if (compact_method == CompactionScheme.Null) { compact_method = Compress.AutoSelectCompressMethod(text); if (compact_method == CompactionScheme.Null) { throw new Exception($"无法为字符串 '{text}' 自动选定压缩方案"); } } if (compact_method == CompactionScheme.ISIL) { precursor.CompactionCode = (int)CompactionScheme.ApplicationDefined; } else { precursor.CompactionCode = (int)compact_method; } byte[] data = null; if (compact_method == CompactionScheme.Integer) { data = Compress.IntegerCompress(text); } else if (compact_method == CompactionScheme.Numeric) { data = Compress.NumericCompress(text); } else if (compact_method == CompactionScheme.FivebitCode) { data = Compress.Bit5Compress(text); } else if (compact_method == CompactionScheme.SixBitCode) { data = Compress.Bit6Compress(text); } else if (compact_method == CompactionScheme.Integer) { data = Compress.IntegerCompress(text); } else if (compact_method == CompactionScheme.SevenBitCode) { data = Compress.Bit7Compress(text); } else if (compact_method == CompactionScheme.OctectString) { data = Encoding.ASCII.GetBytes(text); } else if (compact_method == CompactionScheme.Utf8String) { data = Encoding.UTF8.GetBytes(text); } else if (compact_method == CompactionScheme.ISIL) { data = Compress.IsilCompress(text); } else if (compact_method == CompactionScheme.Base64) { data = Convert.FromBase64String(text); } // 通过 data 计算出是否需要 padding bytes int total_bytes = 1 // precursor + 1 // length of data + data.Length; // data if (precursor.ObjectIdentifier >= 15) { total_bytes++; // relative-OID 需要多占一个 byte } int paddings = 0; if ((total_bytes % 4) != 0) { paddings = 4 - (total_bytes % 4); } // 组装最终数据 List <byte> result = new List <byte>(); // OID 值是否越过 precursor 表达范围 if (precursor.ObjectIdentifier >= 15) { precursor.ObjectIdentifier = 0x0f; } if (paddings > 0) { precursor.Offset = true; } result.Add(precursor.ToByte()); if (precursor.ObjectIdentifier == 0x0f) { Debug.Assert(oid >= 15); result.Add((byte)(oid - 15)); // relative-OID } // padding length byte if (paddings > 0) { result.Add((byte)(paddings - 1)); } result.Add((byte)data.Length); // length of data result.AddRange(data); // data for (int i = 0; i < paddings - 1; i++) { result.Add((byte)0); // padding bytes } return(result.ToArray()); }