예제 #1
0
        // 根据 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);
        }
예제 #2
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());
        }