2 * Copyright (C) 1995-2007, Index Data ApS
3 * See the file LICENSE for details.
5 * $Id: marc_read_iso2709.c,v 1.2 2007-01-03 08:42:15 adam Exp $
9 * \file marc_read_iso2709.c
10 * \brief Implements reading of MARC as ISO2709
24 #include <yaz/marcdisp.h>
25 #include <yaz/wrbuf.h>
26 #include <yaz/yaz-util.h>
28 int yaz_marc_read_iso2709(yaz_marc_t mt, const char *buf, int bsize)
33 int identifier_length;
36 int length_data_entry;
38 int length_implementation;
42 record_length = atoi_n (buf, 5);
43 if (record_length < 25)
45 yaz_marc_cprintf(mt, "Record length %d < 24", record_length);
48 /* ballout if bsize is known and record_length is less than that */
49 if (bsize != -1 && record_length > bsize)
51 yaz_marc_cprintf(mt, "Record appears to be larger than buffer %d < %d",
52 record_length, bsize);
55 if (yaz_marc_get_debug(mt))
56 yaz_marc_cprintf(mt, "Record length %5d", record_length);
58 yaz_marc_set_leader(mt, buf,
64 &length_implementation);
66 /* First pass. determine length of directory & base of data */
67 for (entry_p = 24; buf[entry_p] != ISO2709_FS; )
69 /* length of directory entry */
70 int l = 3 + length_data_entry + length_starting;
71 if (entry_p + l >= record_length)
73 yaz_marc_cprintf(mt, "Directory offset %d: end of record."
74 " Missing FS char", entry_p);
77 if (yaz_marc_get_debug(mt))
79 yaz_marc_cprintf(mt, "Directory offset %d: Tag %.3s",
80 entry_p, buf+entry_p);
82 /* Check for digits in length info */
84 if (!isdigit(*(const unsigned char *) (buf + entry_p+l)))
88 /* Not all digits, so stop directory scan */
89 yaz_marc_cprintf(mt, "Directory offset %d: Bad value for data"
90 " length and/or length starting", entry_p);
93 entry_p += 3 + length_data_entry + length_starting;
95 end_of_directory = entry_p;
96 if (base_address != entry_p+1)
98 yaz_marc_cprintf(mt, "Base address not at end of directory,"
99 " base %d, end %d", base_address, entry_p+1);
102 /* Second pass. parse control - and datafields */
103 for (entry_p = 24; entry_p != end_of_directory; )
110 int identifier_flag = 0;
111 int entry_p0 = entry_p;
113 memcpy (tag, buf+entry_p, 3);
116 data_length = atoi_n(buf+entry_p, length_data_entry);
117 entry_p += length_data_entry;
118 data_offset = atoi_n(buf+entry_p, length_starting);
119 entry_p += length_starting;
120 i = data_offset + base_address;
121 end_offset = i+data_length-1;
123 if (data_length <= 0 || data_offset < 0)
126 if (yaz_marc_get_debug(mt))
128 yaz_marc_cprintf(mt, "Tag: %s. Directory offset %d: data-length %d,"
130 tag, entry_p0, data_length, data_offset);
132 if (end_offset >= record_length)
134 yaz_marc_cprintf(mt, "Directory offset %d: Data out of bounds %d >= %d",
135 entry_p0, end_offset, record_length);
139 if (memcmp (tag, "00", 2))
140 identifier_flag = 1; /* if not 00X assume subfields */
141 else if (indicator_length < 4 && indicator_length > 0)
143 /* Danmarc 00X have subfields */
144 if (buf[i + indicator_length] == ISO2709_IDFS)
146 else if (buf[i + indicator_length + 1] == ISO2709_IDFS)
153 i += identifier_flag-1;
154 yaz_marc_add_datafield(mt, tag, buf+i, indicator_length);
155 i += indicator_length;
157 while (i < end_offset &&
158 buf[i] != ISO2709_RS && buf[i] != ISO2709_FS)
160 int code_offset = i+1;
163 while (i < end_offset &&
164 buf[i] != ISO2709_RS && buf[i] != ISO2709_IDFS &&
165 buf[i] != ISO2709_FS)
167 yaz_marc_add_subfield(mt, buf+code_offset, i - code_offset);
174 while (i < end_offset &&
175 buf[i] != ISO2709_RS && buf[i] != ISO2709_FS)
177 yaz_marc_add_controlfield(mt, tag, buf+i0, i-i0);
181 yaz_marc_cprintf(mt, "Separator but not at end of field length=%d",
184 if (buf[i] != ISO2709_RS && buf[i] != ISO2709_FS)
186 yaz_marc_cprintf(mt, "No separator at end of field length=%d",
190 return record_length;
196 * indent-tabs-mode: nil
198 * vim: shiftwidth=4 tabstop=8 expandtab