Example #1
0
        // 获得 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);
        }
Example #2
0
        // 构造一个 Precursor 对象
        public Precursor Compact(bool offset, int compaction_code, int oid)
        {
            Precursor result = new Precursor
            {
                Offset           = offset,
                CompactionCode   = compaction_code,
                ObjectIdentifier = oid
            };

            return(result);
        }
Example #3
0
        // 获得 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);
        }
Example #4
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;

            // 自动选定压缩方案
            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());
        }
Example #5
0
        // 调整 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);
        }
Example #6
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());
        }