// 获得 element 占用的总 byte 数 public static int GetTotalLength(byte[] data) { Precursor precursor = new Precursor(data[0]); int padding_length_count = 0; // “填充字节数”位,的字节个数。0 或 1 int additional_oid_count = 0; // 附加的 OID 字节个数。0 或 1 int padding_count = 0; // padding byte 个数。注意这个值没有包含 padding length byte 本身的 1 int compacted_data_length = 0; if (precursor.Offset) { padding_length_count = 1; padding_count = data[1]; } if (precursor.ObjectIdentifier >= 15) { additional_oid_count = 1; } compacted_data_length = data[1 + padding_length_count + additional_oid_count]; return(1 // (precursor) byte + padding_length_count // (padding length) byte + additional_oid_count // (additional oid value) byte + 1 // (length of data) byte + compacted_data_length + padding_count); }
// 构造一个 Precursor 对象 public Precursor Compact(bool offset, int compaction_code, int oid) { Precursor result = new Precursor { Offset = offset, CompactionCode = compaction_code, ObjectIdentifier = oid }; return(result); }
// 获得 element 用到的填充 byte 个数 public static int GetPaddingCount(byte[] data) { Precursor precursor = new Precursor(data[0]); int padding_length_count = 0; // “填充字节数”位,的字节个数。0 或 1 int padding_count = 0; // padding byte 个数。注意这个值没有包含 padding length byte 本身的 1 if (precursor.Offset) { padding_length_count = 1; padding_count = data[1]; } return(padding_count + padding_length_count); }
// 根据 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()); }
// 调整 padding bytes。 // 如果 data 包含超过一个元素的内容,则第一个元素后面的内容操作后不会被损坏 // 注: // 当 OID 为 1-14 时: // Precursor (+Padding length) + Length of data + Compacted data (+padding bytes) // 当 OID 为 15-127 时 // Precursor (+Padding length) + Additioal OID value + Length of data + Compacted data (+padding bytes) // parameters: // data 待加工的数据 // delta 变化数。可以是负数。表示增加或者减少这么多个 bytes 的 padding 字符 // exception: // 可能会抛出 Exception 或 PaddingOverflowException public static byte[] AdjustPaddingBytes(byte[] data, int delta) { if (delta == 0) { throw new ArgumentException("不允许以 delta 为 0 进行调用"); } Precursor precursor = new Precursor(data[0]); int padding_length_count = 0; // “填充字节数”位,的字节个数。0 或 1 int additional_oid_count = 0; // 附加的 OID 字节个数。0 或 1 int padding_count = 0; // padding byte 个数。注意这个值没有包含 padding length byte 本身的 1 int compacted_data_length = 0; int total_length = 0; if (precursor.Offset) { padding_length_count = 1; padding_count = data[1]; } if (precursor.ObjectIdentifier >= 15) { additional_oid_count = 1; } compacted_data_length = data[1 + padding_length_count + additional_oid_count]; total_length = 1 // (precursor) byte + padding_length_count // (padding length) byte + additional_oid_count // (additional oid value) byte + 1 // (length of data) byte + compacted_data_length + padding_count; if (data.Length < total_length) { throw new Exception($"调用时给出的 data 长度为 {data.Length}, 不足 {total_length}。数据不完整"); } List <byte> result = new List <byte>(); List <byte> more = new List <byte>(); { int i = 0; // 确保没有多余的数据 for (i = 0; i < total_length; i++) { result.Add(data[i]); } // 多余的部分暂存起来 for (; i < data.Length; i++) { more.Add(data[i]); } } // 开始腾挪 // *** padding 增多的情况 if (delta > 0) { // 加工前已经有 padding 的情况 if (precursor.Offset) { // 在末尾增加 delta 个填充 byte for (int i = 0; i < delta; i++) { result.Add(0); } // 检查 byte 值是否溢出 // 有办法预先知道多大的 delta 值会溢出 if (result[1] + delta > byte.MaxValue) { throw new PaddingOverflowException($"Padding Length 原值为 {result[1]},加上 {delta} 以后发生了溢出", byte.MaxValue - result[1]); } // 修改 Padding Length 位 result[1] = (byte)(result[1] + delta); result.AddRange(more); return(result.ToArray()); } // 加工前没有 padding 的情况 // 1) 先插入一个 Padding length 位 result.Insert(1, (byte)(delta - 1)); if (delta - 1 > 0) { for (int i = 0; i < delta - 1; i++) { result.Add(0); } } // 2) Offset bit 设置为 1 result[0] |= 0x80; result.AddRange(more); return(result.ToArray()); } // *** delta 减少的情况 Debug.Assert(delta < 0); // 加工前已经有 padding 的情况 if (precursor.Offset) { if (padding_count + delta < -1) { throw new Exception($"delta 值 {delta} 太小以至于超过可用范围"); } // 去掉尾部 padding 字节就可以满足的情况 if (padding_count + delta >= 0) { for (int i = 0; i < -delta; i++) { result.RemoveAt(result.Count - 1); } } else { Debug.Assert(padding_count + delta == -1); for (int i = 0; i < -delta - 1; i++) { result.RemoveAt(result.Count - 1); } // 还要去掉 padding length 位 result.RemoveAt(1); // Offset 变为 false precursor.Offset = false; result[0] = precursor.ToByte(); } result.AddRange(more); return(result.ToArray()); } // 加工前没有 padding 的情况 throw new PaddingOverflowException($"delta 值为 {delta} 但原始数据中并没有 padding 可以去除", 0); }
// 根据 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; // 注: SetInformation 的编码方式是根据字符串来自动选定的 (GB/T 35660.2-2017 page 32 例子) if (oid == (int)ElementOID.ContentParameter || oid == (int)ElementOID.TypeOfUsage || oid == (int)ElementOID.MediaFormat || oid == (int)ElementOID.SupplyChainStage) { compact_method = CompactionScheme.OctectString; } else if (oid == (int)ElementOID.OwnerInstitution || oid == (int)ElementOID.IllBorrowingInstitution) { compact_method = CompactionScheme.ISIL; } // 自动选定压缩方案 if (compact_method == CompactionScheme.Null) { compact_method = RFID.Compact.AutoSelectCompactMethod((ElementOID)oid, text); if (compact_method == CompactionScheme.Null) { throw new Exception($"无法为字符串 '{text}' (oid='{(ElementOID)oid}') 自动选定压缩方案"); } } byte[] data = null; if (compact_method == CompactionScheme.Integer) { data = RFID.Compact.IntegerCompact(text); } else if (compact_method == CompactionScheme.Numeric) { data = RFID.Compact.NumericCompact(text); } else if (compact_method == CompactionScheme.FivebitCode) { data = RFID.Compact.Bit5Compact(text); } else if (compact_method == CompactionScheme.SixBitCode) { data = RFID.Compact.Bit6Compact(text); } else if (compact_method == CompactionScheme.Integer) { data = RFID.Compact.IntegerCompact(text); } else if (compact_method == CompactionScheme.SevenBitCode) { data = RFID.Compact.Bit7Compact(text); } else if (compact_method == CompactionScheme.OctectString) { data = FromHexString(text); } else if (compact_method == CompactionScheme.Utf8String) { data = Encoding.UTF8.GetBytes(text); } else if (compact_method == CompactionScheme.ISIL) { data = RFID.Compact.IsilCompact(text); } else if (compact_method == CompactionScheme.Base64) { data = Convert.FromBase64String(text); } if (oid == (int)ElementOID.ContentParameter) { compact_method = 0; } if (compact_method == CompactionScheme.ISIL) { compact_method = (int)CompactionScheme.ApplicationDefined; } precursor.CompactionCode = (int)compact_method; // 通过 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 (alignment) { 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()); }