static int tst_convert_x(yaz_iconv_t cd, const char *buf, const char *cmpbuf, int expect_error) { int ret = 1; WRBUF b = wrbuf_alloc(); char outbuf[16]; size_t inbytesleft = strlen(buf); const char *inp = buf; int rounds = 0; for (rounds = 0; inbytesleft && rounds < (int) sizeof(outbuf); rounds++) { size_t outbytesleft = sizeof(outbuf); char *outp = outbuf; size_t r = yaz_iconv(cd, (char**) &inp, &inbytesleft, &outp, &outbytesleft); wrbuf_write(b, outbuf, outp - outbuf); if (r == (size_t) (-1)) { int e = yaz_iconv_error(cd); if (e != YAZ_ICONV_E2BIG) { if (expect_error != -1) if (e != expect_error) ret = 0; break; } } else { size_t outbytesleft = sizeof(outbuf); char *outp = outbuf; r = yaz_iconv(cd, 0, 0, &outp, &outbytesleft); wrbuf_write(b, outbuf, outp - outbuf); if (expect_error != -1) if (expect_error) ret = 0; break; } } if (wrbuf_len(b) == strlen(cmpbuf) && !memcmp(cmpbuf, wrbuf_buf(b), wrbuf_len(b))) ; else { WRBUF w = wrbuf_alloc(); ret = 0; wrbuf_rewind(w); wrbuf_puts_escaped(w, buf); yaz_log(YLOG_LOG, "input %s", wrbuf_cstr(w)); wrbuf_rewind(w); wrbuf_write_escaped(w, wrbuf_buf(b), wrbuf_len(b)); yaz_log(YLOG_LOG, "got %s", wrbuf_cstr(w)); wrbuf_rewind(w); wrbuf_puts_escaped(w, cmpbuf); yaz_log(YLOG_LOG, "exp %s", wrbuf_cstr(w)); wrbuf_destroy(w); } wrbuf_destroy(b); return ret; }
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); if (!atoi_n_check(buf, 5, &record_length)) { yaz_marc_cprintf(mt, "Bad leader"); return -1; } 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 (yaz_marc_get_debug(mt)) yaz_marc_cprintf(mt, "Record length %5d", record_length); yaz_marc_set_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 (yaz_marc_get_debug(mt)) { WRBUF hex = wrbuf_alloc(); wrbuf_puts(hex, "Tag "); wrbuf_write_escaped(hex, buf + entry_p, 3); wrbuf_puts(hex, ", length "); wrbuf_write_escaped(hex, buf + entry_p + 3, length_data_entry); wrbuf_puts(hex, ", starting "); wrbuf_write_escaped(hex, buf + entry_p + 3 + length_data_entry, length_starting); yaz_marc_cprintf(mt, "Directory offset %d: %s", entry_p, wrbuf_cstr(hex)); wrbuf_destroy(hex); } /* Check for digits in length+starting info */ while (--l >= 3) if (!yaz_isdigit(buf[entry_p + l])) break; if (l >= 3) { WRBUF hex = wrbuf_alloc(); /* Not all digits, so stop directory scan */ wrbuf_write_escaped(hex, buf + entry_p, length_data_entry + length_starting + 3); yaz_marc_cprintf(mt, "Directory offset %d: Bad value for data" " length and/or length starting (%s)", entry_p, wrbuf_cstr(hex)); wrbuf_destroy(hex); 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 (yaz_marc_get_debug(mt)) { 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; if (indicator_length) { /* skip RS/FS bytes in indicator. They are not allowed there */ int j; for (j = indicator_length; --j >= 0; ) if (buf[j+i] < ' ') { j++; i += j; end_offset += j; yaz_marc_cprintf(mt, "Bad indicator data. " "Skipping %d bytes", j); break; } 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++; if (i > code_offset) 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; }