/* libwmf (xml.c): library for wmf conversion Copyright (C) 2000,2001 Francis James Franklin The libwmf Library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The libwmf Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with the libwmf Library; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifdef HAVE_CONFIG_H #include "wmfconfig.h" #endif /* HAVE_CONFIG_H */ #include #include #include "wmfdefs.h" #include "xml.h" static int s_value (char c) { int v = -1; if ((c >= 'A') && (c <= 'Z')) v = c - 'A'; else if ((c >= 'a') && (c <= 'z')) v = 26 + c - 'a'; else if ((c >= '0') && (c <= '9')) v = 52 + c - '0'; else if (c == '+') v = 62; else if (c == '/') v = 63; return v; } static void cd_append (wmfXML_InputData * data, const char * buffer, unsigned long length) { unsigned long i; unsigned long size; int v; char c; char * more = 0; const char * ptr = buffer; if ((length == 0) || (buffer == 0)) return; if (data->cd_buffer == 0) { more = (char *) wmf_malloc (data->API, length); if (ERR (data->API)) { WMF_DEBUG (data->API,"bailing..."); return; } data->cd_buffer = more; data->cd_bufptr = data->cd_buffer; data->cd_max = length; } if (data->cd_length + length > data->cd_max) { size = data->cd_length + length; more = (char *) wmf_realloc (data->API, data->cd_buffer, size); if (ERR (data->API)) { WMF_DEBUG (data->API,"bailing..."); return; } data->cd_buffer = more; data->cd_bufptr = data->cd_buffer + data->cd_length; data->cd_max = size; } for (i = 0; i < length; i++) { c = *ptr++; v = s_value (c); if (v >= 0) { *(data->cd_bufptr++) = c; data->cd_length++; } } } static void mem_append (wmfXML_InputData * data, unsigned char * buffer, unsigned long length) { unsigned char * more = 0; unsigned long size; if ((length == 0) || (buffer == 0)) return; if (data->mem_buffer == 0) { more = (unsigned char *) wmf_malloc (data->API, length); if (ERR (data->API)) { WMF_DEBUG (data->API,"bailing..."); return; } data->mem_buffer = more; data->mem_bufptr = data->mem_buffer; data->mem_max = length; } if (data->mem_length + length > data->mem_max) { size = data->mem_length + length; more = (unsigned char *) wmf_realloc (data->API, data->mem_buffer, size); if (ERR (data->API)) { WMF_DEBUG (data->API,"bailing..."); return; } data->mem_buffer = more; data->mem_bufptr = data->mem_buffer + data->mem_length; data->mem_max = size; } memcpy (data->mem_bufptr, buffer, length); data->mem_bufptr += length; data->mem_length += length; } static void store_clear (wmfAPI * API) { unsigned long i; for (i = 0; i < API->store.count; i++) wmf_attr_free (API, API->store.attrlist + i); API->store.count = 0; } static void store_atts (wmfAPI * API, const char * element_name, const char ** atts) { unsigned long size; const char ** attr = 0; const char * name = 0; const char * value = 0; wmfAttributes * more = 0; if (API->store.attrlist == 0) { more = (wmfAttributes *) wmf_malloc (API, 16 * sizeof (wmfAttributes)); if (ERR (API)) { WMF_DEBUG (API, "bailing..."); return; } API->store.attrlist = more; API->store.max = 16; API->store.count = 0; } if (API->store.count == API->store.max) { size = (API->store.max + 16) * sizeof (wmfAttributes); more = (wmfAttributes *) wmf_realloc (API, API->store.attrlist, size); if (ERR (API)) { WMF_DEBUG (API, "bailing..."); return; } API->store.attrlist = more; API->store.max += 16; } more = API->store.attrlist + API->store.count++; wmf_attr_new (API, more); more->name = wmf_strdup (API, element_name); if (atts == 0) return; attr = atts; while (*attr) { name = *attr++; value = *attr++; wmf_attr_add (API, more, name, value); } } static void xml_start (void * user_data, const char * name, const char ** atts) { wmfXML_InputData * input_data = (wmfXML_InputData *) user_data; wmfAPI* API = input_data->API; if (ERR (API)) return; if (input_data->wmfxml == 0) { if (strcmp (name, "wmfxml") == 0) { input_data->wmfxml = 1; } else { input_data->wmfxml = -1; } return; } if (input_data->wmfxml != 1) return; store_atts (API, name, atts); input_data->cd_bufptr = input_data->cd_buffer; input_data->cd_length = 0; } static void xml_data (void * user_data, const char * buffer, int length) { wmfXML_InputData * input_data = (wmfXML_InputData *) user_data; if (ERR (input_data->API)) return; if (input_data->wmfxml != 1) return; cd_append (input_data, buffer, (unsigned long) ((unsigned) length)); } static void xml_end (void * user_data, const char * name) { unsigned char buffer[54]; unsigned char * bufptr = 0; char * cd_ptr = 0; unsigned long i; unsigned long b32; unsigned long length; unsigned long remaining; wmfXML_InputData * input_data = (wmfXML_InputData *) user_data; wmfAttributes * attr = 0; wmfAPI * API = input_data->API; if (ERR (API)) return; if (input_data->wmfxml != 1) return; if (strcmp (name, "wmfxml") == 0) { for (i = 0; i < API->store.count; i++) { attr = API->store.attrlist + i; attr->buffer = input_data->mem_buffer + attr->offset; } return; } attr = API->store.attrlist + (API->store.count - 1); attr->length = 0; attr->offset = (unsigned long) (input_data->mem_bufptr - input_data->mem_buffer); cd_ptr = input_data->cd_buffer; remaining = input_data->cd_length; while (remaining >= 72) { bufptr = buffer; for (i = 0; i < 18; i++) { b32 = (unsigned long) ( s_value (*(cd_ptr++))); b32 = (unsigned long) ((b32 << 6) | s_value (*(cd_ptr++))); b32 = (unsigned long) ((b32 << 6) | s_value (*(cd_ptr++))); b32 = (unsigned long) ((b32 << 6) | s_value (*(cd_ptr++))); *bufptr++ = (unsigned char) ((b32 >> 16) ); *bufptr++ = (unsigned char) ((b32 >> 8) & 0xff); *bufptr++ = (unsigned char) ((b32 ) & 0xff); } mem_append (input_data, buffer, 54); remaining -= 72; attr->length += 54; } bufptr = buffer; length = 0; while (remaining >= 4) { b32 = (unsigned long) ((unsigned) s_value (*(cd_ptr++))); b32 = (b32 << 6) | (unsigned long) ((unsigned) s_value (*(cd_ptr++))); b32 = (b32 << 6) | (unsigned long) ((unsigned) s_value (*(cd_ptr++))); b32 = (b32 << 6) | (unsigned long) ((unsigned) s_value (*(cd_ptr++))); *bufptr++ = (unsigned char) ((b32 >> 16) ); *bufptr++ = (unsigned char) ((b32 >> 8) & 0xff); *bufptr++ = (unsigned char) ((b32 ) & 0xff); remaining -= 4; length += 3; } if (remaining == 3) { b32 = (unsigned long) ((unsigned) s_value (*(cd_ptr++))); b32 = (b32 << 6) | (unsigned long) ((unsigned) s_value (*(cd_ptr++))); b32 = (b32 << 6) | (unsigned long) ((unsigned) s_value (*(cd_ptr++))); b32 = (b32 << 6); *bufptr++ = (unsigned char) ((b32 >> 16) ); *bufptr++ = (unsigned char) ((b32 >> 8) & 0xff); remaining -= 3; length += 2; } if (remaining == 2) { b32 = (unsigned long) ((unsigned) s_value (*(cd_ptr++))); b32 = (b32 << 6) | (unsigned long) ((unsigned) s_value (*(cd_ptr++))); b32 = (b32 << 12); *bufptr++ = (unsigned char) ((b32 >> 16) ); remaining -= 2; length++; } if (remaining == 1) WMF_DEBUG (API, "xml_end: WMF Record has unexpected length!"); if (length) { mem_append (input_data, buffer, length); attr->length += length; } input_data->cd_bufptr = input_data->cd_buffer; input_data->cd_length = 0; } #ifdef HAVE_EXPAT #include #define EXML_BUFSIZE 1024 wmf_error_t wmf_wmfxml_import (wmfAPI * API, const char * wmfxml_filename) { char buffer[EXML_BUFSIZE]; int status; int length; FILE * in = 0; XML_Parser parser = 0; wmfXML_InputData input_data; input_data.API = API; input_data.cd_buffer = 0; input_data.cd_bufptr = 0; input_data.cd_length = 0; input_data.cd_max = 0; input_data.mem_buffer = 0; input_data.mem_bufptr = 0; input_data.mem_length = 0; input_data.mem_max = 0; input_data.wmfxml = 0; if (ERR (API)) return API->err; store_clear (API); if ( wmfxml_filename == 0) return wmf_E_BadFile; if (*wmfxml_filename == 0) return wmf_E_BadFile; in = fopen (wmfxml_filename, "r"); if (in == 0) { WMF_DEBUG (API, "wmf_wmfxml_import: unable to open file"); return wmf_E_BadFile; } parser = XML_ParserCreate (0); if (parser == 0) { WMF_DEBUG (API, "wmf_wmfxml_import: error creating expat-xml parser"); fclose (in); return wmf_E_InsMem; } XML_SetUserData (parser, (void *) (&input_data)); XML_SetStartElementHandler (parser, xml_start); XML_SetEndElementHandler (parser, xml_end); XML_SetCharacterDataHandler (parser, xml_data); status = 0; while (fgets (buffer, EXML_BUFSIZE, in) && (API->err == wmf_E_None)) { length = (int) strlen (buffer); if (XML_Parse (parser, buffer, length, 0) == 0) { WMF_DEBUG (API,"wmf_wmfxml_import: error parsing file"); status = 1; break; } } if ((status == 0) && (API->err == wmf_E_None)) XML_Parse (parser, buffer, 0, 1); XML_ParserFree (parser); fclose (in); if (input_data.cd_buffer) wmf_free (API, input_data.cd_buffer); if (ERR (API)) { if (input_data.mem_buffer) wmf_free (API, input_data.mem_buffer); return API->err; } API->flags |= API_ENABLE_EDITING; return wmf_mem_open (API, input_data.mem_buffer, (long) input_data.mem_length); } #endif /* HAVE_EXPAT */ #ifdef HAVE_LIBXML2 #include #include wmf_error_t wmf_wmfxml_import (wmfAPI * API, const char * wmfxml_filename) { xmlParserCtxtPtr ctxt = 0; xmlSAXHandler sax; wmfXML_InputData input_data; input_data.API = API; input_data.cd_buffer = 0; input_data.cd_bufptr = 0; input_data.cd_length = 0; input_data.cd_max = 0; input_data.mem_buffer = 0; input_data.mem_bufptr = 0; input_data.mem_length = 0; input_data.mem_max = 0; input_data.wmfxml = 0; if (ERR (API)) return API->err; store_clear (API); if ( wmfxml_filename == 0) return wmf_E_BadFile; if (*wmfxml_filename == 0) return wmf_E_BadFile; memset ((void*) (&sax), 0, sizeof (xmlSAXHandler)); sax.startElement = (startElementSAXFunc)xml_start; sax.endElement = (endElementSAXFunc)xml_end; sax.characters = (charactersSAXFunc)xml_data; ctxt = xmlCreateFileParserCtxt (wmfxml_filename); if (ctxt == 0) return wmf_E_InsMem; ctxt->sax = &sax; ctxt->userData = (void*) (&input_data); xmlParseDocument (ctxt); ctxt->sax = 0; xmlFreeParserCtxt (ctxt); if (input_data.cd_buffer) wmf_free (API, input_data.cd_buffer); if (ERR (API)) { if (input_data.mem_buffer) wmf_free (API, input_data.mem_buffer); return API->err; } API->flags |= API_ENABLE_EDITING; return wmf_mem_open (API, input_data.mem_buffer, (long) input_data.mem_length); } #endif /* HAVE_LIBXML2 */