예제 #1
0
        public static IrbisRecord ReadRecord
        (
            [NotNull] Stream stream,
            [NotNull] Encoding encoding
        )
        {
            IrbisRecord result = new IrbisRecord();

            // Считываем длину записи
            byte[] marker = new byte[5];
            if (stream.Read(marker, 0, marker.Length) != marker.Length)
            {
                return(null);
            }

            // а затем и ее остаток
            int recordLength = FastNumber.ParseInt32(marker, 0, marker.Length);

            byte[] record = new byte[recordLength];
            int    need   = recordLength - marker.Length;

            if (stream.Read(record, marker.Length, need) != need)
            {
                return(null);
            }

            // Простая проверка, что мы имеем дело
            // с нормальной ISO-записью
            if (record[recordLength - 1] != RecordDelimiter)
            {
                return(null);
            }

            int lengthOfLength  = FastNumber.ParseInt32(record, 20, 1);
            int lengthOfOffset  = FastNumber.ParseInt32(record, 21, 1);
            int additionalData  = FastNumber.ParseInt32(record, 22, 1);
            int directoryLength = 3 + lengthOfLength + lengthOfOffset
                                  + additionalData;

            // Превращаем запись в Unicode
            char[] chars           = encoding.GetChars(record);
            int    indicatorLength = FastNumber.ParseInt32(record, 10, 1);
            int    baseAddress     = FastNumber.ParseInt32(record, 12, 5);

            // Пошли по полям при помощи справочника
            for (int directory = MarkerLength; ; directory += directoryLength)
            {
                // Переходим к следующему полю.
                // Если нарвались на разделитель, значит, справочник закончился
                if (record[directory] == FieldDelimiter)
                {
                    break;
                }

                int    tag         = FastNumber.ParseInt32(record, directory, 3);
                string tagText     = tag.ToInvariantString();
                int    fieldLength = FastNumber.ParseInt32
                                     (
                    record,
                    directory + 3,
                    lengthOfLength
                                     );
                int fieldOffset = baseAddress + FastNumber.ParseInt32
                                  (
                    record,
                    directory + 3 + lengthOfLength,
                    lengthOfOffset
                                  );
                RecordField field = new RecordField(tagText);
                result.Fields.Add(field);
                if (tag < 10)
                {
                    // Фиксированное поле
                    // не может содержать подполей и индикаторов
                    field.Text = new string(chars, fieldOffset, fieldLength - 1);
                }
                else
                {
                    // Поле переменной длины
                    // Содержит два однобайтных индикатора
                    // может содерджать подполя

                    // пропускаем индикаторы
                    int start    = fieldOffset + indicatorLength;
                    int stop     = fieldOffset + fieldLength - indicatorLength + 1;
                    int position = start;

                    // Ищем значение поля до первого разделителя
                    while (position < stop)
                    {
                        if (record[start] == SubfieldDelimiter)
                        {
                            break;
                        }
                        position++;
                    }

                    // Если есть текст до первого разделителя, запоминаем его
                    if (position != start)
                    {
                        field.Text = new string(chars, start, position - start);
                    }

                    // Просматриваем подполя
                    start = position;
                    while (start < stop)
                    {
                        position = start + 1;
                        while (position < stop)
                        {
                            if (record[position] == SubfieldDelimiter)
                            {
                                break;
                            }
                            position++;
                        }
                        SubField subField = new SubField
                                            (
                            chars[start + 1],
                            new string(chars, start + 2, position - start - 2)
                                            );
                        field.SubFields.Add(subField);
                        start = position;
                    }
                }
            }

            return(result);
        }
예제 #2
0
        public static MarcRecord ReadRecord
        (
            int mfn
        )
        {
            const string recordSeparator = "*****";

            MarcRecord result = new MarcRecord
            {
                Mfn      = mfn,
                Database = "ISTU"
            };

            while (true)
            {
                string line = _reader.ReadLine();
                if (string.IsNullOrEmpty(line))
                {
                    return(null);
                }

                if (line == recordSeparator)
                {
                    break;
                }

                if (line[0] != '#')
                {
                    return(null);
                }

                int pos = line.IndexOf(':') + 1;
                if (pos <= 1 || line[pos] != ' ')
                {
                    return(null);
                }

                int         tag   = FastNumber.ParseInt32(line, 1, pos - 2);
                RecordField field = new RecordField(tag);
                result.Fields.Add(field);
                int start = ++pos, length = line.Length;
                while (pos < length)
                {
                    if (line[pos] == '^')
                    {
                        break;
                    }
                    pos++;
                }

                if (pos != start)
                {
                    field.Value = line.Substring(start, pos - start);
                    start       = pos;
                }

                while (start < length - 1)
                {
                    char code = line[++start];
                    pos = ++start;
                    while (pos < length)
                    {
                        if (line[pos] == '^')
                        {
                            break;
                        }
                        pos++;
                    }

                    SubField sub = new SubField
                                   (
                        code,
                        line.Substring(start, pos - start)
                                   );
                    field.SubFields.Add(sub);
                    start = pos;
                }
            }

            result.Modified = false;
            return(result);
        }
예제 #3
0
        /// <summary>
        /// Выводит запись в ISO-поток.
        /// </summary>
        public static void WriteRecord
        (
            [NotNull] IrbisRecord record,
            [NotNull] Stream stream,
            [NotNull] Encoding encoding
        )
        {
            int recordLength     = MarkerLength;
            int dictionaryLength = 1;                         // С учетом ограничителя справочника

            int[] fieldLength = new int[record.Fields.Count]; // Длины полей

            // Сначала пытаемся подсчитать полную длину
            for (int i = 0; i < record.Fields.Count; i++)
            {
                dictionaryLength += 12; // Одна статья справочника
                RecordField field = record.Fields[i];
                int         tag   = FastNumber.ParseInt32(field.Tag);
                if (tag <= 0 || tag >= 1000)
                {
                    throw new IrbisException("Wrong field: " + field.Tag);
                }
                int fldlen = 0;
                if (tag < 10)
                {
                    // В фиксированном поле не бывает подполей.
                    fldlen += encoding.GetByteCount(field.Text ?? string.Empty);
                }
                else
                {
                    fldlen += 2; // Индикаторы
                    fldlen += encoding.GetByteCount(field.Text ?? string.Empty);
                    for (int j = 0; j < field.SubFields.Count; j++)
                    {
                        fldlen += 2; // Признак подполя и его код
                        fldlen += encoding.GetByteCount
                                  (
                            field.SubFields[j].Text
                            ?? string.Empty
                                  );
                    }
                }

                fldlen++; // Разделитель полей
                if (fldlen >= 10000)
                {
                    throw new IrbisException("Record too long");
                }

                fieldLength[i] = fldlen;
                recordLength  += fldlen;
            }
            recordLength += dictionaryLength; // Справочник
            recordLength++;                   // Разделитель записей

            if (recordLength >= 100000)
            {
                // Слишком длинная запись
                throw new IrbisException("Record too long");
            }

            // Приступаем к кодированию
            int dictionaryPosition = MarkerLength;
            int baseAddress        = MarkerLength + dictionaryLength;
            int currentAddress     = baseAddress;

            byte[] bytes = new byte[recordLength];

            // Кодируем маркер
            for (int i = 0; i <= baseAddress; i++)
            {
                bytes[i] = (byte)' ';
            }
            _Encode(bytes, 0, 5, recordLength);
            _Encode(bytes, 12, 5, baseAddress);

            bytes[5]  = (byte)'n';
            bytes[6]  = (byte)'a';
            bytes[7]  = (byte)'m';
            bytes[8]  = (byte)'2';
            bytes[10] = (byte)'2';
            bytes[11] = (byte)'2';
            bytes[18] = (byte)'i';
            bytes[20] = (byte)'4';
            bytes[21] = (byte)'5';
            bytes[22] = (byte)'0';

            // Кодируем конец справочника
            bytes[baseAddress - 1] = FieldDelimiter;

            // Проходим по полям
            for (int i = 0; i < record.Fields.Count; i++, dictionaryPosition += 12)
            {
                // Кодируем справочник
                RecordField field = record.Fields[i];
                int         tag   = FastNumber.ParseInt32(field.Tag);
                _Encode(bytes, dictionaryPosition, 3, tag);
                _Encode(bytes, dictionaryPosition + 3, 4, fieldLength[i]);
                _Encode(bytes, dictionaryPosition + 7, 5, currentAddress - baseAddress);

                // Кодируем поле
                if (tag < 10)
                {
                    // В фиксированном поле не бывает подполей и индикаторов.
                    currentAddress = _Encode
                                     (
                        bytes,
                        currentAddress,
                        field.Text,
                        encoding
                                     );
                }
                else
                {
#if WITH_INDICATORS
                    chars[currentAddress++] = (byte)fld.Indicator1.Value[0];
                    chars[currentAddress++] = (byte)fld.Indicator2.Value[0];
#else
                    bytes[currentAddress++] = (byte)' ';
                    bytes[currentAddress++] = (byte)' ';
#endif

                    currentAddress = _Encode
                                     (
                        bytes,
                        currentAddress,
                        field.Text,
                        encoding
                                     );

                    for (int j = 0; j < field.SubFields.Count; j++)
                    {
                        bytes[currentAddress++] = SubfieldDelimiter;
                        bytes[currentAddress++] = (byte)field.SubFields[j].Code;
                        currentAddress          = _Encode
                                                  (
                            bytes,
                            currentAddress,
                            field.SubFields[j].Text,
                            encoding
                                                  );
                    }
                }
                bytes[currentAddress++] = FieldDelimiter;
            }

            // Ограничитель записи
            bytes[recordLength - 2] = FieldDelimiter;
            bytes[recordLength - 1] = RecordDelimiter;

            // Собственно записываем
            stream.Write(bytes, 0, bytes.Length);
        }