1 /* This file is part of the YAZ toolkit.
2 * Copyright (C) 1995-2010 Index Data
3 * See the file LICENSE for details.
7 * \file marc_read_iso2709.c
8 * \brief Implements reading of MARC as ISO2709
22 #include <yaz/marcdisp.h>
23 #include <yaz/wrbuf.h>
24 #include <yaz/yaz-util.h>
26 int yaz_marc_read_iso2709(yaz_marc_t mt, const char *buf, int bsize)
31 int identifier_length;
34 int length_data_entry;
36 int length_implementation;
40 record_length = atoi_n (buf, 5);
41 if (record_length < 25)
43 yaz_marc_cprintf(mt, "Record length %d < 24", record_length);
46 /* ballout if bsize is known and record_length is less than that */
47 if (bsize != -1 && record_length > bsize)
49 yaz_marc_cprintf(mt, "Record appears to be larger than buffer %d < %d",
50 record_length, bsize);
53 if (yaz_marc_get_debug(mt))
54 yaz_marc_cprintf(mt, "Record length %5d", record_length);
56 yaz_marc_set_leader(mt, buf,
62 &length_implementation);
64 /* First pass. determine length of directory & base of data */
65 for (entry_p = 24; buf[entry_p] != ISO2709_FS; )
67 /* length of directory entry */
68 int l = 3 + length_data_entry + length_starting;
69 if (entry_p + l >= record_length)
71 yaz_marc_cprintf(mt, "Directory offset %d: end of record."
72 " Missing FS char", entry_p);
75 if (yaz_marc_get_debug(mt))
77 WRBUF hex = wrbuf_alloc();
79 wrbuf_puts(hex, "Tag ");
80 wrbuf_write_escaped(hex, buf + entry_p, 3);
81 wrbuf_puts(hex, ", length ");
82 wrbuf_write_escaped(hex, buf + entry_p + 3,
84 wrbuf_puts(hex, ", starting ");
85 wrbuf_write_escaped(hex, buf + entry_p + 3 + length_data_entry,
87 yaz_marc_cprintf(mt, "Directory offset %d: %s",
88 entry_p, wrbuf_cstr(hex));
91 /* Check for digits in length+starting info */
93 if (!isdigit(*(const unsigned char *) (buf + entry_p+l)))
97 WRBUF hex = wrbuf_alloc();
98 /* Not all digits, so stop directory scan */
99 wrbuf_write_escaped(hex, buf + entry_p,
100 length_data_entry + length_starting + 3);
101 yaz_marc_cprintf(mt, "Directory offset %d: Bad value for data"
102 " length and/or length starting (%s)", entry_p,
107 entry_p += 3 + length_data_entry + length_starting;
109 end_of_directory = entry_p;
110 if (base_address != entry_p+1)
112 yaz_marc_cprintf(mt, "Base address not at end of directory,"
113 " base %d, end %d", base_address, entry_p+1);
116 /* Second pass. parse control - and datafields */
117 for (entry_p = 24; entry_p != end_of_directory; )
124 int identifier_flag = 0;
125 int entry_p0 = entry_p;
127 memcpy (tag, buf+entry_p, 3);
130 data_length = atoi_n(buf+entry_p, length_data_entry);
131 entry_p += length_data_entry;
132 data_offset = atoi_n(buf+entry_p, length_starting);
133 entry_p += length_starting;
134 i = data_offset + base_address;
135 end_offset = i+data_length-1;
137 if (data_length <= 0 || data_offset < 0)
140 if (yaz_marc_get_debug(mt))
142 yaz_marc_cprintf(mt, "Tag: %s. Directory offset %d: data-length %d,"
144 tag, entry_p0, data_length, data_offset);
146 if (end_offset >= record_length)
148 yaz_marc_cprintf(mt, "Directory offset %d: Data out of bounds %d >= %d",
149 entry_p0, end_offset, record_length);
153 if (memcmp (tag, "00", 2))
154 identifier_flag = 1; /* if not 00X assume subfields */
155 else if (indicator_length < 4 && indicator_length > 0)
157 /* Danmarc 00X have subfields */
158 if (buf[i + indicator_length] == ISO2709_IDFS)
160 else if (buf[i + indicator_length + 1] == ISO2709_IDFS)
167 i += identifier_flag-1;
168 if (indicator_length)
170 /* skip RS/FS bytes in indicator. They are not allowed there */
172 for (j = indicator_length; --j >= 0; )
178 yaz_marc_cprintf(mt, "Bad indicator data. "
179 "Skipping %d bytes", j);
182 yaz_marc_add_datafield(mt, tag, buf+i, indicator_length);
183 i += indicator_length;
186 while (i < end_offset &&
187 buf[i] != ISO2709_RS && buf[i] != ISO2709_FS)
189 int code_offset = i+1;
192 while (i < end_offset &&
193 buf[i] != ISO2709_RS && buf[i] != ISO2709_IDFS &&
194 buf[i] != ISO2709_FS)
197 yaz_marc_add_subfield(mt, buf+code_offset, i - code_offset);
204 while (i < end_offset &&
205 buf[i] != ISO2709_RS && buf[i] != ISO2709_FS)
207 yaz_marc_add_controlfield(mt, tag, buf+i0, i-i0);
211 yaz_marc_cprintf(mt, "Separator but not at end of field length=%d",
214 if (buf[i] != ISO2709_RS && buf[i] != ISO2709_FS)
216 yaz_marc_cprintf(mt, "No separator at end of field length=%d",
220 return record_length;
226 * c-file-style: "Stroustrup"
227 * indent-tabs-mode: nil
229 * vim: shiftwidth=4 tabstop=8 expandtab