-#if YAZ_HAVE_XML2
-int yaz_marc_read_xml_subfields(yaz_marc_t mt, const xmlNode *ptr)
-{
- for (; ptr; ptr = ptr->next)
- {
- if (ptr->type == XML_ELEMENT_NODE)
- {
- if (!strcmp((const char *) ptr->name, "subfield"))
- {
- size_t ctrl_data_len = 0;
- char *ctrl_data_buf = 0;
- const xmlNode *p = 0, *ptr_code = 0;
- struct _xmlAttr *attr;
- for (attr = ptr->properties; attr; attr = attr->next)
- if (!strcmp((const char *)attr->name, "code"))
- ptr_code = attr->children;
- else
- {
- yaz_marc_cprintf(
- mt, "Bad attribute '%.80s' for 'subfield'",
- attr->name);
- return -1;
- }
- if (!ptr_code)
- {
- yaz_marc_cprintf(
- mt, "Missing attribute 'code' for 'subfield'" );
- return -1;
- }
- if (ptr_code->type == XML_TEXT_NODE)
- {
- ctrl_data_len =
- strlen((const char *)ptr_code->content);
- }
- else
- {
- yaz_marc_cprintf(
- mt, "Missing value for 'code' in 'subfield'" );
- return -1;
- }
- for (p = ptr->children; p ; p = p->next)
- if (p->type == XML_TEXT_NODE)
- ctrl_data_len += strlen((const char *)p->content);
- ctrl_data_buf = nmem_malloc(mt->nmem, ctrl_data_len+1);
- strcpy(ctrl_data_buf, (const char *)ptr_code->content);
- for (p = ptr->children; p ; p = p->next)
- if (p->type == XML_TEXT_NODE)
- strcat(ctrl_data_buf, (const char *)p->content);
- yaz_marc_add_subfield(mt, ctrl_data_buf, ctrl_data_len);
- }
- else
- {
- yaz_marc_cprintf(
- mt, "Expected element 'subfield', got '%.80s'", ptr->name);
- return -1;
- }
- }
- }
- return 0;
-}
-
-static int yaz_marc_read_xml_leader(yaz_marc_t mt, const xmlNode **ptr_p)
-{
- int indicator_length;
- int identifier_length;
- int base_address;
- int length_data_entry;
- int length_starting;
- int length_implementation;
- const char *leader = 0;
- const xmlNode *ptr = *ptr_p;
-
- for(; ptr; ptr = ptr->next)
- if (ptr->type == XML_ELEMENT_NODE)
- {
- if (!strcmp((const char *) ptr->name, "leader"))
- {
- xmlNode *p = ptr->children;
- for(; p; p = p->next)
- if (p->type == XML_TEXT_NODE)
- leader = (const char *) p->content;
- break;
- }
- else
- {
- yaz_marc_cprintf(
- mt, "Expected element 'leader', got '%.80s'", ptr->name);
- return -1;
- }
- }
- if (!leader)
- {
- yaz_marc_cprintf(mt, "Missing element 'leader'");
- return -1;
- }
- if (strlen(leader) != 24)
- {
- yaz_marc_cprintf(mt, "Bad length %d of leader data."
- " Must have length of 24 characters", strlen(leader));
- return -1;
- }
- yaz_marc_read_leader(mt, leader,
- &indicator_length,
- &identifier_length,
- &base_address,
- &length_data_entry,
- &length_starting,
- &length_implementation);
- *ptr_p = ptr;
- return 0;
-}
-
-static int yaz_marc_read_xml_fields(yaz_marc_t mt, const xmlNode *ptr)
-{
- for(; ptr; ptr = ptr->next)
- if (ptr->type == XML_ELEMENT_NODE)
- {
- if (!strcmp((const char *) ptr->name, "controlfield"))
- {
- const xmlNode *ptr_tag = 0;
- struct _xmlAttr *attr;
- for (attr = ptr->properties; attr; attr = attr->next)
- if (!strcmp((const char *)attr->name, "tag"))
- ptr_tag = attr->children;
- else
- {
- yaz_marc_cprintf(
- mt, "Bad attribute '%.80s' for 'controlfield'",
- attr->name);
- return -1;
- }
- if (!ptr_tag)
- {
- yaz_marc_cprintf(
- mt, "Missing attribute 'tag' for 'controlfield'" );
- return -1;
- }
- yaz_marc_add_controlfield_xml(mt, ptr_tag, ptr->children);
- }
- else if (!strcmp((const char *) ptr->name, "datafield"))
- {
- char indstr[11]; /* 0(unused), 1,....9, + zero term */
- const xmlNode *ptr_tag = 0;
- struct _xmlAttr *attr;
- int i;
- for (i = 0; i<11; i++)
- indstr[i] = '\0';
- for (attr = ptr->properties; attr; attr = attr->next)
- if (!strcmp((const char *)attr->name, "tag"))
- ptr_tag = attr->children;
- else if (strlen((const char *)attr->name) == 4 &&
- !memcmp(attr->name, "ind", 3))
- {
- int no = atoi((const char *)attr->name+3);
- if (attr->children
- && attr->children->type == XML_TEXT_NODE)
- indstr[no] = attr->children->content[0];
- }
- else
- {
- yaz_marc_cprintf(
- mt, "Bad attribute '%.80s' for 'datafield'",
- attr->name);
- return -1;
- }
- if (!ptr_tag)
- {
- yaz_marc_cprintf(
- mt, "Missing attribute 'tag' for 'datafield'" );
- return -1;
- }
- /* note that indstr[0] is unused so we use indstr[1..] */
- yaz_marc_add_datafield_xml(mt, ptr_tag,
- indstr+1, strlen(indstr+1));
-
- if (yaz_marc_read_xml_subfields(mt, ptr->children))
- return -1;
- }
- else
- {
- yaz_marc_cprintf(mt,
- "Expected element controlfield or datafield,"
- " got %.80s", ptr->name);
- return -1;
- }
- }
- return 0;
-}
-#endif
-
-int yaz_marc_read_xml(yaz_marc_t mt, const xmlNode *ptr)
-{
-#if YAZ_HAVE_XML2
- for(; ptr; ptr = ptr->next)
- if (ptr->type == XML_ELEMENT_NODE)
- {
- if (!strcmp((const char *) ptr->name, "record"))
- break;
- else
- {
- yaz_marc_cprintf(
- mt, "Unknown element '%.80s' in MARC XML reader",
- ptr->name);
- return -1;
- }
- }
- if (!ptr)
- {
- yaz_marc_cprintf(mt, "Missing element 'record' in MARC XML record");
- return -1;
- }
- /* ptr points to record node now */
- ptr = ptr->children;
- if (yaz_marc_read_xml_leader(mt, &ptr))
- return -1;
- return yaz_marc_read_xml_fields(mt, ptr->next);
-#else
- return -1;
-#endif
-}
-
-int yaz_marc_read_iso2709(yaz_marc_t mt, const char *buf, int bsize)
-{
- int entry_p;
- int record_length;
- int indicator_length;
- int identifier_length;
- int end_of_directory;
- int base_address;
- int length_data_entry;
- int length_starting;
- int length_implementation;
-
- yaz_marc_reset(mt);
-
- record_length = atoi_n (buf, 5);
- if (record_length < 25)
- {
- yaz_marc_cprintf(mt, "Record length %d < 24", record_length);
- return -1;
- }
- /* ballout if bsize is known and record_length is less than that */
- if (bsize != -1 && record_length > bsize)
- {
- yaz_marc_cprintf(mt, "Record appears to be larger than buffer %d < %d",
- record_length, bsize);
- return -1;
- }
- if (mt->debug)
- yaz_marc_cprintf(mt, "Record length %5d", record_length);
-
- yaz_marc_read_leader(mt, buf,
- &indicator_length,
- &identifier_length,
- &base_address,
- &length_data_entry,
- &length_starting,
- &length_implementation);
-
- /* First pass. determine length of directory & base of data */
- for (entry_p = 24; buf[entry_p] != ISO2709_FS; )
- {
- /* length of directory entry */
- int l = 3 + length_data_entry + length_starting;
- if (entry_p + l >= record_length)
- {
- yaz_marc_cprintf(mt, "Directory offset %d: end of record."
- " Missing FS char", entry_p);
- return -1;
- }
- if (mt->debug)
- {
- yaz_marc_cprintf(mt, "Directory offset %d: Tag %.3s",
- entry_p, buf+entry_p);
- }
- /* Check for digits in length info */
- while (--l >= 3)
- if (!isdigit(*(const unsigned char *) (buf + entry_p+l)))
- break;
- if (l >= 3)
- {
- /* Not all digits, so stop directory scan */
- yaz_marc_cprintf(mt, "Directory offset %d: Bad value for data"
- " length and/or length starting", entry_p);
- break;
- }
- entry_p += 3 + length_data_entry + length_starting;
- }
- end_of_directory = entry_p;
- if (base_address != entry_p+1)
- {
- yaz_marc_cprintf(mt, "Base address not at end of directory,"
- " base %d, end %d", base_address, entry_p+1);
- }
-
- /* Second pass. parse control - and datafields */
- for (entry_p = 24; entry_p != end_of_directory; )
- {
- int data_length;
- int data_offset;
- int end_offset;
- int i;
- char tag[4];
- int identifier_flag = 0;
- int entry_p0 = entry_p;
-
- memcpy (tag, buf+entry_p, 3);
- entry_p += 3;
- tag[3] = '\0';
- data_length = atoi_n(buf+entry_p, length_data_entry);
- entry_p += length_data_entry;
- data_offset = atoi_n(buf+entry_p, length_starting);
- entry_p += length_starting;
- i = data_offset + base_address;
- end_offset = i+data_length-1;
-
- if (data_length <= 0 || data_offset < 0)
- break;
-
- if (mt->debug)
- {
- yaz_marc_cprintf(mt, "Tag: %s. Directory offset %d: data-length %d,"
- " data-offset %d",
- tag, entry_p0, data_length, data_offset);
- }
- if (end_offset >= record_length)
- {
- yaz_marc_cprintf(mt, "Directory offset %d: Data out of bounds %d >= %d",
- entry_p0, end_offset, record_length);
- break;
- }
-
- if (memcmp (tag, "00", 2))
- identifier_flag = 1; /* if not 00X assume subfields */
- else if (indicator_length < 4 && indicator_length > 0)
- {
- /* Danmarc 00X have subfields */
- if (buf[i + indicator_length] == ISO2709_IDFS)
- identifier_flag = 1;
- else if (buf[i + indicator_length + 1] == ISO2709_IDFS)
- identifier_flag = 2;
- }
-
- if (identifier_flag)
- {
- /* datafield */
- i += identifier_flag-1;
- yaz_marc_add_datafield(mt, tag, buf+i, indicator_length);
- i += indicator_length;
-
- while (i < end_offset &&
- buf[i] != ISO2709_RS && buf[i] != ISO2709_FS)
- {
- int code_offset = i+1;
-
- i ++;
- while (i < end_offset &&
- buf[i] != ISO2709_RS && buf[i] != ISO2709_IDFS &&
- buf[i] != ISO2709_FS)
- i++;
- yaz_marc_add_subfield(mt, buf+code_offset, i - code_offset);
- }
- }
- else
- {
- /* controlfield */
- int i0 = i;
- while (i < end_offset &&
- buf[i] != ISO2709_RS && buf[i] != ISO2709_FS)
- i++;
- yaz_marc_add_controlfield(mt, tag, buf+i0, i-i0);
- }
- if (i < end_offset)
- {
- yaz_marc_cprintf(mt, "Separator but not at end of field length=%d",
- data_length);
- }
- if (buf[i] != ISO2709_RS && buf[i] != ISO2709_FS)
- {
- yaz_marc_cprintf(mt, "No separator at end of field length=%d",
- data_length);
- }
- }
- return record_length;
-}