Exemple #1
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());
        }
Exemple #2
0
        // 对元素进行排序
        // 调用前,要确保每个元素都 Compact 好了,内容放入 OriginData 中了
        // 排序原则:
        // 1) PII 在第一个;
        // 2) Content Parameter 在第二个; 
        // 2.1) 如果元素里面至少有一个锁定元素,Content Parameter 元素要对齐 block 边界(便于锁定元素锁定)
        // 3) 其余拟锁定元素聚集在一起,最后给必要的 padding
        // 4) 所有非锁定的元素聚集在一起
        // 5) 锁定的元素,和非锁定元素区域内部,可以按照 OID 号码排序
        // 上述算法有个优势,就是所有锁定元素中间不一定要 block 边界对齐,这样可以节省一点空间
        // 但存在一个小问题: Content Parameter 要占用多少 byte? 如果以后元素数量增多,(因为它后面就是锁定区域)它无法变大怎么办?
        public void Sort(int max_bytes,
            int block_size,
            bool trim_cp_right)
        {
            SetContentParameter(trim_cp_right);
            if (this.IsNew == true)
            {
                this._elements.Sort((a, b) =>
                {
                    // OID 为 1 的始终靠前
                    if ((int)a.OID == 1)
                    {
                        if (a.OID == b.OID)
                            return 0;
                        return -1;
                    }
                    if ((int)b.OID == 1)
                        return 1;

                    // 比较 WillLock。拟锁定的位置靠后
                    int lock_a = a.WillLock ? 1 : 0;
                    int lock_b = b.WillLock ? 1 : 0;
                    int delta = lock_a - lock_b;
                    if (delta != 0)
                        return delta;

                    // 最后比较 OID。OID 值小的靠前
                    delta = a.OID - b.OID;
                    return delta;
                });

                // 更新 element.OriginData
                // 对 WillLock 切换的情形,和最后一个 WillLock 元素进行 padding 调整
                Element prev_element = null;
                string prev_type = "";   // free or will_lock
                string current_type = "";
                int start = 0;
                int i = 0;
                foreach (Element element in this._elements)
                {
                    if (element.WillLock == false)
                        current_type = "free";
                    else
                        current_type = "will_lock";

                    // 如果切换了类型(类型指“普通”还是 WillLock)
                    // 需要把 prev_element 尾部对齐 block 边界
                    if (current_type != prev_type
                        && prev_element != null)
                    {
                        int result = AdjustCount(block_size, start);
                        int delta = result - start;

                        // 调整 prev_element 的 padding
                        if (delta != 0)
                            prev_element.OriginData = Element.AdjustPaddingBytes(prev_element.OriginData, delta);

                        start = result;
                    }

#if NO
                    CompactionScheme compact_method = CompactionScheme.Null;
                    if (element.OID == ElementOID.ContentParameter)
                        compact_method = CompactionScheme.OctectString;
                    else if (element.OID == ElementOID.OwnerInstitution
                        || element.OID == ElementOID.IllBorrowingInstitution)
                        compact_method = CompactionScheme.ISIL;
#endif
                    element.OriginData = Element.Compact((int)element.OID,
                        element.Text,
                        CompactionScheme.Null,
                        false);
                    //if (start != element.StartOffs)
                    //    throw new Exception($"element {element.ToString()} 的 StartOffs {element.StartOffs} 不符合预期值 {start}");


                    start += element.OriginData.Length;
                    prev_type = current_type;
                    prev_element = element;
                    i++;
                }

                // 如果是最后一个 element(并且它是 WillLock 类型)
                // 需要把尾部对齐 block 边界
                if (prev_element != null && prev_element.WillLock)
                {
                    int result = AdjustCount(block_size, start);
                    int delta = result - start;

                    // 调整 prev_element 的 padding
                    if (delta != 0)
                        prev_element.OriginData = Element.AdjustPaddingBytes(prev_element.OriginData, delta);

                    start = result;
                }
            }
            else
            {
                foreach (Element element in this._elements)
                {
                    if (element.Locked)
                        continue;

                    element.OriginData = Element.Compact((int)element.OID,
                        element.Text,
                        CompactionScheme.Null,
                        false);
                }


                // 改写状态。Locked 的元素不能动。只能在余下空挡位置,见缝插针组合排列非 Lock 元素
                // 组合算法是:每当得到一个区间尺寸,就去查询余下的元素中尺寸组合起来最适合的那些元素
                // 可以用一种利用率指标来评价组合好坏。也就是余下的空挡越小,越好
                List<int> elements = GetFreeElements();
                if (elements.Count == 0)
                    return; // 没有必要进行排序

                bool bRet = GetFreeSegments(max_bytes,
                    out List<int> free_segments,
                    out List<object> anchor_list);

                if (bRet == false)
                    throw new Exception("当前没有任何自由空间可用于存储自由字段信息");

                // 对 n 个区间进行填充尝试。把每个可能的组合,都填充试验一轮
                // parameters:
                //      areas   空闲区间的列表。每个数字表示空闲的 byte 数
                //      elements    元素尺寸列表。每个数字表示元素占用的 byte 数
                List<List<OneArea>> layouts = GetPossibleLayouts(
                    block_size,
                    free_segments,
                    elements);
                if (layouts.Count == 0)
                    throw new Exception("没有找到可用的排列方式");

                // TODO: 如何优选 layouts? 目前能想到的,是把 ContentParameter 在第一个元素以后的优选出来

                // 安排元素顺序
                SetElementsPos(
                    block_size,
                    layouts[0],
                    free_segments,
                    anchor_list);
            }
        }
Exemple #3
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());
        }