1 /* This file is part of the YAZ toolkit.
2 * Copyright (C) 1995-2013 Index Data
3 * See the file LICENSE for details.
7 * \file marc_read_iso2709.c
8 * \brief Implements reading of MARC as ISO2709
21 #include <yaz/marcdisp.h>
22 #include <yaz/wrbuf.h>
23 #include <yaz/yaz-util.h>
25 int yaz_marc_read_iso2709(yaz_marc_t mt, const char *buf, int bsize)
30 int identifier_length;
33 int length_data_entry;
35 int length_implementation;
39 if (!atoi_n_check(buf, 5, &record_length))
41 yaz_marc_cprintf(mt, "Bad leader");
44 if (record_length < 25)
46 yaz_marc_cprintf(mt, "Record length %d < 24", record_length);
49 /* ballout if bsize is known and record_length is less than that */
50 if (bsize != -1 && record_length > bsize)
52 yaz_marc_cprintf(mt, "Record appears to be larger than buffer %d < %d",
53 record_length, bsize);
56 if (yaz_marc_get_debug(mt))
57 yaz_marc_cprintf(mt, "Record length %5d", record_length);
59 yaz_marc_set_leader(mt, buf,
65 &length_implementation);
67 /* First pass. determine length of directory & base of data */
68 for (entry_p = 24; buf[entry_p] != ISO2709_FS; )
70 /* length of directory entry */
71 int l = 3 + length_data_entry + length_starting;
72 if (entry_p + l >= record_length)
74 yaz_marc_cprintf(mt, "Directory offset %d: end of record."
75 " Missing FS char", entry_p);
78 if (yaz_marc_get_debug(mt))
80 WRBUF hex = wrbuf_alloc();
82 wrbuf_puts(hex, "Tag ");
83 wrbuf_write_escaped(hex, buf + entry_p, 3);
84 wrbuf_puts(hex, ", length ");
85 wrbuf_write_escaped(hex, buf + entry_p + 3,
87 wrbuf_puts(hex, ", starting ");
88 wrbuf_write_escaped(hex, buf + entry_p + 3 + length_data_entry,
90 yaz_marc_cprintf(mt, "Directory offset %d: %s",
91 entry_p, wrbuf_cstr(hex));
94 /* Check for digits in length+starting info */
96 if (!yaz_isdigit(buf[entry_p + l]))
100 WRBUF hex = wrbuf_alloc();
101 /* Not all digits, so stop directory scan */
102 wrbuf_write_escaped(hex, buf + entry_p,
103 length_data_entry + length_starting + 3);
104 yaz_marc_cprintf(mt, "Directory offset %d: Bad value for data"
105 " length and/or length starting (%s)", entry_p,
110 entry_p += 3 + length_data_entry + length_starting;
112 end_of_directory = entry_p;
113 if (base_address != entry_p+1)
115 yaz_marc_cprintf(mt, "Base address not at end of directory,"
116 " base %d, end %d", base_address, entry_p+1);
119 /* Second pass. parse control - and datafields */
120 for (entry_p = 24; entry_p != end_of_directory; )
127 int identifier_flag = 0;
128 int entry_p0 = entry_p;
130 memcpy (tag, buf+entry_p, 3);
133 data_length = atoi_n(buf+entry_p, length_data_entry);
134 entry_p += length_data_entry;
135 data_offset = atoi_n(buf+entry_p, length_starting);
136 entry_p += length_starting;
137 i = data_offset + base_address;
138 end_offset = i+data_length-1;
140 if (data_length <= 0 || data_offset < 0)
143 if (yaz_marc_get_debug(mt))
145 yaz_marc_cprintf(mt, "Tag: %s. Directory offset %d: data-length %d,"
147 tag, entry_p0, data_length, data_offset);
149 if (end_offset >= record_length)
151 yaz_marc_cprintf(mt, "Directory offset %d: Data out of bounds %d >= %d",
152 entry_p0, end_offset, record_length);
156 if (memcmp (tag, "00", 2))
157 identifier_flag = 1; /* if not 00X assume subfields */
158 else if (indicator_length < 4 && indicator_length > 0)
160 /* Danmarc 00X have subfields */
161 if (buf[i + indicator_length] == ISO2709_IDFS)
163 else if (buf[i + indicator_length + 1] == ISO2709_IDFS)
170 i += identifier_flag-1;
171 if (indicator_length)
173 /* skip RS/FS bytes in indicator. They are not allowed there */
175 for (j = indicator_length; --j >= 0; )
181 yaz_marc_cprintf(mt, "Bad indicator data. "
182 "Skipping %d bytes", j);
185 yaz_marc_add_datafield(mt, tag, buf+i, indicator_length);
186 i += indicator_length;
189 while (i < end_offset &&
190 buf[i] != ISO2709_RS && buf[i] != ISO2709_FS)
192 int code_offset = i+1;
195 while (i < end_offset &&
196 buf[i] != ISO2709_RS && buf[i] != ISO2709_IDFS &&
197 buf[i] != ISO2709_FS)
200 yaz_marc_add_subfield(mt, buf+code_offset, i - code_offset);
207 while (i < end_offset &&
208 buf[i] != ISO2709_RS && buf[i] != ISO2709_FS)
210 yaz_marc_add_controlfield(mt, tag, buf+i0, i-i0);
214 yaz_marc_cprintf(mt, "Separator but not at end of field length=%d",
217 if (buf[i] != ISO2709_RS && buf[i] != ISO2709_FS)
219 yaz_marc_cprintf(mt, "No separator at end of field length=%d",
223 return record_length;
229 * c-file-style: "Stroustrup"
230 * indent-tabs-mode: nil
232 * vim: shiftwidth=4 tabstop=8 expandtab