+ if (!(inf = fopen (systemId, "rb")))
+ {
+ yaz_log (YLOG_WARN|YLOG_ERRNO, "fopen %s", systemId);
+ return 0;
+ }
+
+ parser = XML_ExternalEntityParserCreate (pparser, "", 0);
+ while (!done)
+ {
+ int r;
+ void *buf = XML_GetBuffer (parser, XML_CHUNK);
+ if (!buf)
+ {
+ yaz_log (YLOG_WARN, "XML_GetBuffer fail");
+ break;
+ }
+ r = fread (buf, 1, XML_CHUNK, inf);
+ if (r == 0)
+ {
+ if (ferror(inf))
+ {
+ yaz_log (YLOG_WARN|YLOG_ERRNO, "fread %s", systemId);
+ break;
+ }
+ done = 1;
+ }
+ if (!XML_ParseBuffer (parser, r, done))
+ {
+ done = 1;
+ yaz_log (YLOG_WARN, "%s:%d:%d:XML error: %s",
+ systemId,
+ XML_GetCurrentLineNumber(parser),
+ XML_GetCurrentColumnNumber(parser),
+ XML_ErrorString(XML_GetErrorCode(parser)));
+ }
+ }
+ fclose (inf);
+ XML_ParserFree (parser);
+ return done;
+}
+
+
+#if HAVE_ICONV_H
+static int cb_encoding_convert (void *data, const char *s)
+{
+ iconv_t t = (iconv_t) data;
+ size_t ret;
+ size_t outleft = 2;
+ char outbuf_[2], *outbuf = outbuf_;
+ size_t inleft = 4;
+ char *inbuf = (char *) s;
+ unsigned short code;
+
+#if 1
+ yaz_log(YLOG_LOG, "------------------------- cb_encoding_convert --- ");
+#endif
+ ret = iconv (t, &inbuf, &inleft, &outbuf, &outleft);
+ if (ret == (size_t) (-1) && errno != E2BIG)
+ {
+ iconv (t, 0, 0, 0, 0);
+ return -1;
+ }
+ if (outleft != 0)
+ return -1;
+ memcpy (&code, outbuf_, sizeof(short));
+ return code;
+}
+
+static void cb_encoding_release (void *data)
+{
+ iconv_t t = (iconv_t) data;
+ iconv_close (t);
+}
+
+static int cb_encoding_handler (void *userData, const char *name,
+ XML_Encoding *info)
+{
+ int i = 0;
+ int no_ok = 0;
+ struct user_info *ui = (struct user_info*) userData;
+
+ iconv_t t = iconv_open ("UNICODE", name);
+ if (t == (iconv_t) (-1))
+ return 0;
+
+ info->data = 0; /* signal that multibyte is not in use */
+ yaz_log (ui->loglevel, "Encoding handler of %s", name);
+ for (i = 0; i<256; i++)
+ {
+ size_t ret;
+ char outbuf_[5];
+ char inbuf_[5];
+ char *inbuf = inbuf_;
+ char *outbuf = outbuf_;
+ size_t inleft = 1;
+ size_t outleft = 2;
+ inbuf_[0] = i;
+
+ iconv (t, 0, 0, 0, 0); /* reset iconv */
+
+ ret = iconv(t, &inbuf, &inleft, &outbuf, &outleft);
+ if (ret == (size_t) (-1))
+ {
+ if (errno == EILSEQ)
+ {
+ yaz_log (ui->loglevel, "Encoding %d: invalid sequence", i);
+ info->map[i] = -1; /* invalid sequence */
+ }
+ if (errno == EINVAL)
+ { /* multi byte input */
+ int len = 2;
+ int j = 0;
+ info->map[i] = -1;
+
+ while (len <= 4)
+ {
+ char sbuf[80];
+ int k;
+ inbuf = inbuf_;
+ inleft = len;
+ outbuf = outbuf_;
+ outleft = 2;
+
+ inbuf_[len-1] = j;
+ iconv (t, 0,0,0,0);
+
+ assert (i >= 0 && i<255);
+
+ *sbuf = 0;
+ for (k = 0; k<len; k++)
+ {
+ sprintf (sbuf+strlen(sbuf), "%d ", inbuf_[k]&255);
+ }
+ ret = iconv (t, &inbuf, &inleft, &outbuf, &outleft);
+ if (ret == (size_t) (-1))
+ {
+ if (errno == EILSEQ || errno == E2BIG)
+ {
+ j++;
+ if (j > 255)
+ break;
+ }
+ else if (errno == EINVAL)
+ {
+ len++;
+ j = 7;
+ }
+ }
+ else if (outleft == 0)
+ {
+ info->map[i] = -len;
+ info->data = t; /* signal that multibyte is in use */
+ break;
+ }
+ else
+ {
+ break;
+ }
+ }
+ if (info->map[i] < -1)
+ yaz_log (ui->loglevel, "Encoding %d: multibyte input %d",
+ i, -info->map[i]);
+ else
+ yaz_log (ui->loglevel, "Encoding %d: multibyte input failed",
+ i);
+ }
+ if (errno == E2BIG)
+ {
+ info->map[i] = -1; /* no room for output */
+ if (i != 0)
+ yaz_log (YLOG_WARN, "Encoding %d: no room for output",
+ i);
+ }
+ }
+ else if (outleft == 0)
+ {
+ unsigned short code;
+ memcpy (&code, outbuf_, sizeof(short));
+ info->map[i] = code;
+ no_ok++;
+ }
+ else
+ { /* should never happen */
+ info->map[i] = -1;
+ yaz_log (YLOG_DEBUG, "Encoding %d: bad state", i);
+ }
+ }
+ if (info->data)
+ { /* at least one multi byte */
+ info->convert = cb_encoding_convert;
+ info->release = cb_encoding_release;
+ }
+ else
+ {
+ /* no multi byte - we no longer need iconv handler */
+ iconv_close(t);
+ info->convert = 0;
+ info->release = 0;
+ }
+ if (!no_ok)
+ return 0;
+ return 1;
+}
+/* HAVE_ICONV_H */
+#endif
+
+static void cb_ns_start(void *userData, const char *prefix, const char *uri)
+{
+ struct user_info *ui = (struct user_info*) userData;
+ if (prefix && uri)
+ yaz_log(ui->loglevel, "cb_ns_start %s %s", prefix, uri);
+}
+
+static void cb_ns_end(void *userData, const char *prefix)
+{
+ struct user_info *ui = (struct user_info*) userData;
+ if (prefix)
+ yaz_log(ui->loglevel, "cb_ns_end %s", prefix);
+}
+data1_node *zebra_read_xml (data1_handle dh,
+ int (*rf)(void *, char *, size_t), void *fh,
+ NMEM m)
+{
+ XML_Parser parser;
+ struct user_info uinfo;
+ int done = 0;
+ data1_node *first_node;
+ int no_read = 0;
+
+ uinfo.loglevel = YLOG_DEBUG;
+ uinfo.level = 1;
+ uinfo.dh = dh;
+ uinfo.nmem = m;
+ uinfo.d1_stack[0] = data1_mk_node2 (dh, m, DATA1N_root, 0);
+ uinfo.d1_stack[1] = 0; /* indicate no children (see end of routine) */
+
+ parser = XML_ParserCreate (0 /* encoding */);
+
+ XML_SetElementHandler (parser, cb_start, cb_end);
+ XML_SetCharacterDataHandler (parser, cb_chardata);
+ XML_SetXmlDeclHandler (parser, cb_decl);
+ XML_SetProcessingInstructionHandler (parser, cb_processing);
+ XML_SetUserData (parser, &uinfo);
+ XML_SetCommentHandler (parser, cb_comment);
+ XML_SetDoctypeDeclHandler (parser, cb_doctype_start, cb_doctype_end);
+ XML_SetEntityDeclHandler (parser, cb_entity_decl);
+ XML_SetExternalEntityRefHandler (parser, cb_external_entity);
+ XML_SetNamespaceDeclHandler(parser, cb_ns_start, cb_ns_end);
+#if HAVE_ICONV_H
+ XML_SetUnknownEncodingHandler (parser, cb_encoding_handler, &uinfo);
+#endif
+ while (!done)
+ {
+ int r;
+ void *buf = XML_GetBuffer (parser, XML_CHUNK);
+ if (!buf)
+ {
+ /* error */
+ yaz_log (YLOG_WARN, "XML_GetBuffer fail");
+ break;
+ }
+ r = (*rf)(fh, buf, XML_CHUNK);
+ if (r < 0)
+ {
+ /* error */
+ yaz_log (YLOG_WARN, "XML read fail");
+ break;
+ }
+ else if (r == 0)
+ done = 1;
+ else
+ no_read += r;
+ if (no_read && !XML_ParseBuffer (parser, r, done))
+ {
+ done = 1;
+ yaz_log (YLOG_WARN, "%d:%d:XML error: %s",
+ XML_GetCurrentLineNumber(parser),
+ XML_GetCurrentColumnNumber(parser),
+ XML_ErrorString(XML_GetErrorCode(parser)));
+ }
+ }
+ XML_ParserFree (parser);
+ if (no_read == 0)
+ return 0;
+ if (!uinfo.d1_stack[1] || !done)
+ return 0;
+ /* insert XML header if not present .. */
+ first_node = uinfo.d1_stack[0]->child;
+ if (first_node->which != DATA1N_preprocess ||
+ strcmp(first_node->u.preprocess.target, "xml"))
+ {
+ const char *attr_list[5];
+
+ attr_list[0] = "version";
+ attr_list[1] = "1.0";
+
+ attr_list[2] = "encoding";
+ attr_list[3] = "UTF-8"; /* encoding */
+
+ attr_list[4] = 0;
+
+ data1_insert_preprocess (uinfo.dh, uinfo.nmem, "xml", attr_list,
+ uinfo.d1_stack[0]);
+ }
+ return uinfo.d1_stack[0];
+}