+#include <idzebra/recgrs.h>
+
+#include <yaz/xmalloc.h>
+#include <yaz/ylog.h>
+
+#include <expat.h>
+
+#define XML_CHUNK 1024
+
+struct user_info {
+ data1_node *d1_stack[256];
+ int level;
+ data1_handle dh;
+ NMEM nmem;
+ int loglevel;
+};
+
+static void cb_start (void *user, const char *el, const char **attr)
+{
+ struct user_info *ui = (struct user_info*) user;
+ if (ui->level == 1)
+ data1_set_root (ui->dh, ui->d1_stack[0], ui->nmem, el);
+ ui->d1_stack[ui->level] = data1_mk_tag (ui->dh, ui->nmem, el, attr,
+ ui->d1_stack[ui->level-1]);
+ ui->level++;
+ yaz_log (ui->loglevel, "cb_start %s", el);
+}
+
+static void cb_end (void *user, const char *el)
+{
+ struct user_info *ui = (struct user_info*) user;
+
+ ui->level--;
+ yaz_log (ui->loglevel, "cb_end %s", el);
+}
+
+static void cb_chardata (void *user, const char *s, int len)
+{
+ struct user_info *ui = (struct user_info*) user;
+#if 0
+ yaz_log (ui->loglevel, "cb_chardata %.*s", len, s);
+#endif
+ ui->d1_stack[ui->level] = data1_mk_text_n (ui->dh, ui->nmem, s, len,
+ ui->d1_stack[ui->level -1]);
+}
+
+static void cb_decl (void *user, const char *version, const char *encoding,
+ int standalone)
+{
+ struct user_info *ui = (struct user_info*) user;
+ const char *attr_list[7];
+
+ attr_list[0] = "version";
+ attr_list[1] = version;
+
+ attr_list[2] = "encoding";
+ attr_list[3] = "UTF-8"; /* internally it's always UTF-8 */
+
+ attr_list[4] = "standalone";
+ attr_list[5] = standalone ? "yes" : "no";
+
+ attr_list[6] = 0;
+
+ data1_mk_preprocess (ui->dh, ui->nmem, "xml", attr_list,
+ ui->d1_stack[ui->level-1]);
+#if 0
+ yaz_log (YLOG_LOG, "decl version=%s encoding=%s",
+ version ? version : "null",
+ encoding ? encoding : "null");
+#endif
+}
+
+static void cb_processing (void *user, const char *target,
+ const char *data)
+{
+ struct user_info *ui = (struct user_info*) user;
+ data1_node *res =
+ data1_mk_preprocess (ui->dh, ui->nmem, target, 0,
+ ui->d1_stack[ui->level-1]);
+ data1_mk_text_nf (ui->dh, ui->nmem, data, strlen(data), res);
+
+ yaz_log (ui->loglevel, "decl processing target=%s data=%s",
+ target ? target : "null",
+ data ? data : "null");
+}
+
+static void cb_comment (void *user, const char *data)
+{
+ struct user_info *ui = (struct user_info*) user;
+ yaz_log (ui->loglevel, "decl comment data=%s", data ? data : "null");
+ data1_mk_comment (ui->dh, ui->nmem, data, ui->d1_stack[ui->level-1]);
+}
+
+static void cb_doctype_start (void *userData, const char *doctypeName,
+ const char *sysid, const char *pubid,
+ int has_internal_subset)
+{
+ struct user_info *ui = (struct user_info*) userData;
+ yaz_log (ui->loglevel, "doctype start doctype=%s sysid=%s pubid=%s",
+ doctypeName, sysid, pubid);
+}
+
+static void cb_doctype_end (void *userData)
+{
+ struct user_info *ui = (struct user_info*) userData;
+ yaz_log (ui->loglevel, "doctype end");
+}
+
+
+static void cb_entity_decl (void *userData, const char *entityName,
+ int is_parameter_entity,
+ const char *value, int value_length,
+ const char *base, const char *systemId,
+ const char *publicId, const char *notationName)
+{
+ struct user_info *ui = (struct user_info*) userData;
+ yaz_log (ui->loglevel,
+ "entity decl %s is_para_entry=%d value=%.*s base=%s systemId=%s"
+ " publicId=%s notationName=%s",
+ entityName, is_parameter_entity, value_length, value,
+ base, systemId, publicId, notationName);
+
+}
+
+static int cb_external_entity (XML_Parser pparser,
+ const char *context,
+ const char *base,
+ const char *systemId,
+ const char *publicId)
+{
+ struct user_info *ui = (struct user_info*) XML_GetUserData(pparser);
+ FILE *inf;
+ int done = 0;
+ XML_Parser parser;
+
+ yaz_log (ui->loglevel,
+ "external entity context=%s base=%s systemid=%s publicid=%s",
+ context, base, systemId, publicId);
+ if (!systemId)
+ return 1;
+
+ 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;