diff --git a/DOCBparser.c b/DOCBparser.c index e1d20c58..ddb08a2e 100644 --- a/DOCBparser.c +++ b/DOCBparser.c @@ -6025,7 +6025,7 @@ docbCreateFileParserCtxt(const char *filename, } memset(inputStream, 0, sizeof(docbParserInput)); - inputStream->filename = xmlMemStrdup(filename); + inputStream->filename = xmlNormalizeWindowsPath(filename); inputStream->line = 1; inputStream->col = 1; inputStream->buf = buf; diff --git a/HTMLparser.c b/HTMLparser.c index 927cf2c7..5f078d6a 100644 --- a/HTMLparser.c +++ b/HTMLparser.c @@ -4881,7 +4881,7 @@ htmlCreateFileParserCtxt(const char *filename, const char *encoding) } memset(inputStream, 0, sizeof(htmlParserInput)); - inputStream->filename = xmlMemStrdup(filename); + inputStream->filename = xmlNormalizeWindowsPath(filename); inputStream->line = 1; inputStream->col = 1; inputStream->buf = buf; diff --git a/include/libxml/xmlIO.h b/include/libxml/xmlIO.h index 92aa179e..7daa717e 100644 --- a/include/libxml/xmlIO.h +++ b/include/libxml/xmlIO.h @@ -252,6 +252,7 @@ xmlParserInputPtr xmlNoNetExternalEntityLoader(const char *URL, const char *ID, xmlParserCtxtPtr ctxt); +xmlChar *xmlNormalizeWindowsPath (const xmlChar *path); /** * Default 'file://' protocol callbacks diff --git a/parser.c b/parser.c index 0374f681..7311c9ef 100644 --- a/parser.c +++ b/parser.c @@ -666,7 +666,7 @@ xmlParseStringCharRef(xmlParserCtxtPtr ctxt, const xmlChar **str) { static void deallocblankswrapper (xmlChar *str) {xmlFree(str);} -xmlParserInputPtr +static xmlParserInputPtr xmlNewBlanksWrapperInputStream(xmlParserCtxtPtr ctxt, xmlEntityPtr entity) { xmlParserInputPtr input; xmlChar *buffer; @@ -1808,12 +1808,11 @@ xmlParseName(xmlParserCtxtPtr ctxt) { * and the name for mismatch */ -xmlChar * +static xmlChar * xmlParseNameAndCompare(xmlParserCtxtPtr ctxt, xmlChar const *other) { const xmlChar *cmp = other; const xmlChar *in; xmlChar *ret; - int count = 0; GROW; @@ -2275,8 +2274,7 @@ xmlParseAttValueComplex(xmlParserCtxtPtr ctxt); xmlChar * xmlParseAttValue(xmlParserCtxtPtr ctxt) { xmlChar limit = 0; - xmlChar *buf = NULL; - xmlChar *in = NULL; + const xmlChar *in = NULL; xmlChar *ret = NULL; SHRINK; GROW; @@ -9002,7 +9000,8 @@ xmlCreatePushParserCtxt(xmlSAXHandlerPtr sax, void *user_data, if (filename == NULL) inputStream->filename = NULL; else - inputStream->filename = xmlMemStrdup(filename); + inputStream->filename = (char *) + xmlNormalizeWindowsPath((const xmlChar *) filename); inputStream->buf = buf; inputStream->base = inputStream->buf->buffer->content; inputStream->cur = inputStream->buf->buffer->content; @@ -10021,6 +10020,7 @@ xmlCreateFileParserCtxt(const char *filename) xmlParserCtxtPtr ctxt; xmlParserInputPtr inputStream; char *directory = NULL; + xmlChar *normalized; ctxt = xmlNewParserCtxt(); if (ctxt == NULL) { @@ -10030,18 +10030,26 @@ xmlCreateFileParserCtxt(const char *filename) return(NULL); } - inputStream = xmlLoadExternalEntity(filename, NULL, ctxt); + normalized = xmlNormalizeWindowsPath((const xmlChar *) filename); + if (normalized == NULL) { + xmlFreeParserCtxt(ctxt); + return(NULL); + } + inputStream = xmlLoadExternalEntity((char *) normalized, NULL, ctxt); if (inputStream == NULL) { xmlFreeParserCtxt(ctxt); + xmlFree(normalized); return(NULL); } inputPush(ctxt, inputStream); if ((ctxt->directory == NULL) && (directory == NULL)) - directory = xmlParserGetDirectory(filename); + directory = xmlParserGetDirectory((char *) normalized); if ((ctxt->directory == NULL) && (directory != NULL)) ctxt->directory = directory; + xmlFree(normalized); + return(ctxt); } diff --git a/xmlIO.c b/xmlIO.c index 3cd4c2ae..137ea033 100644 --- a/xmlIO.c +++ b/xmlIO.c @@ -123,6 +123,64 @@ static xmlOutputCallback xmlOutputCallbackTable[MAX_OUTPUT_CALLBACK]; static int xmlOutputCallbackNr = 0; static int xmlOutputCallbackInitialized = 0; +/************************************************************************ + * * + * Handling of Windows file paths * + * * + ************************************************************************/ + +#define IS_WINDOWS_PATH(p) \ + ((p != NULL) && \ + (((p[0] >= 'a') && (p[0] <= 'z')) || \ + ((p[0] >= 'A') && (p[0] <= 'Z'))) && \ + (p[1] == ':') && ((p[2] == '/') || (p[2] == '\\'))) + + +/** + * xmlNormalizeWindowsPath + * @path: a windows path like "C:/foo/bar" + * + * Normalize a Windows path to make an URL from it + * + * Returns a new URI which must be freed by the caller or NULL + * in case of error + */ +xmlChar * +xmlNormalizeWindowsPath(const xmlChar *path) +{ + int len, i, j; + xmlChar *ret; + + if (path == NULL) + return(NULL); + if (!IS_WINDOWS_PATH(path)) + return(xmlStrdup(path)); + + len = xmlStrlen(path); + len += 10; + ret = xmlMalloc(len); + if (ret == NULL) + return(NULL); + + ret[0] = 'f'; + ret[1] = 'i'; + ret[2] = 'l'; + ret[3] = 'e'; + ret[4] = ':'; + ret[5] = '/'; + ret[6] = '/'; + ret[7] = '/'; + for (i = 0,j = 8;i < len;i++,j++) { + /* TODO: UTF8 conversion + URI escaping ??? */ + if (path[i] == '\\') + ret[j] = '/'; + else + ret[j] = path[i]; + } + ret[j] = 0; + return(ret); +} + /** * xmlCleanupInputCallbacks: * @@ -296,7 +354,7 @@ xmlFileOpen (const char *filename) { return((void *) fd); } - if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost", 16)) + if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17)) #if defined (_WIN32) && !defined(__CYGWIN__) path = &filename[17]; #else @@ -343,8 +401,12 @@ xmlFileOpenW (const char *filename) { return((void *) fd); } - if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost", 16)) + if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17)) +#if defined (_WIN32) && !defined(__CYGWIN__) + path = &filename[17]; +#else path = &filename[16]; +#endif else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) { #if defined (_WIN32) && !defined(__CYGWIN__) path = &filename[8]; @@ -460,8 +522,12 @@ xmlGzfileOpen (const char *filename) { return((void *) fd); } - if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost", 16)) + if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17)) +#if defined (_WIN32) && !defined(__CYGWIN__) + path = &filename[17]; +#else path = &filename[16]; +#endif else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) { #if defined (_WIN32) && !defined(__CYGWIN__) path = &filename[8]; @@ -502,8 +568,12 @@ xmlGzfileOpenW (const char *filename, int compression) { return((void *) fd); } - if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost", 16)) + if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17)) +#if defined (_WIN32) && !defined(__CYGWIN__) + path = &filename[17]; +#else path = &filename[16]; +#endif else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) { #if defined (_WIN32) && !defined(__CYGWIN__) path = &filename[8]; @@ -1656,11 +1726,14 @@ xmlParserInputBufferCreateFilename int i = 0; void *context = NULL; char *unescaped; + char *normalized; if (xmlInputCallbackInitialized == 0) xmlRegisterDefaultInputCallbacks(); if (URI == NULL) return(NULL); + normalized = (char *) xmlNormalizeWindowsPath((const xmlChar *)URI); + if (normalized == NULL) return(NULL); #ifdef LIBXML_CATALOG_ENABLED #endif @@ -1670,7 +1743,7 @@ xmlParserInputBufferCreateFilename * Go in reverse to give precedence to user defined handlers. * try with an unescaped version of the URI */ - unescaped = xmlURIUnescapeString(URI, 0, NULL); + unescaped = xmlURIUnescapeString((char *) normalized, 0, NULL); if (unescaped != NULL) { for (i = xmlInputCallbackNr - 1;i >= 0;i--) { if ((xmlInputCallbackTable[i].matchcallback != NULL) && @@ -1691,12 +1764,13 @@ xmlParserInputBufferCreateFilename for (i = xmlInputCallbackNr - 1;i >= 0;i--) { if ((xmlInputCallbackTable[i].matchcallback != NULL) && (xmlInputCallbackTable[i].matchcallback(URI) != 0)) { - context = xmlInputCallbackTable[i].opencallback(URI); + context = xmlInputCallbackTable[i].opencallback(normalized); if (context != NULL) break; } } } + xmlFree(normalized); if (context == NULL) { return(NULL); } @@ -1736,6 +1810,7 @@ xmlOutputBufferCreateFilename(const char *URI, int i = 0; void *context = NULL; char *unescaped; + char *normalized; int is_http_uri = 0; /* Can't change if HTTP disabled */ @@ -1743,11 +1818,13 @@ xmlOutputBufferCreateFilename(const char *URI, xmlRegisterDefaultOutputCallbacks(); if (URI == NULL) return(NULL); + normalized = (char *) xmlNormalizeWindowsPath((const xmlChar *)URI); + if (normalized == NULL) return(NULL); #ifdef LIBXML_HTTP_ENABLED /* Need to prevent HTTP URI's from falling into zlib short circuit */ - is_http_uri = xmlIOHTTPMatch( URI ); + is_http_uri = xmlIOHTTPMatch( normalized ); #endif @@ -1756,7 +1833,7 @@ xmlOutputBufferCreateFilename(const char *URI, * Go in reverse to give precedence to user defined handlers. * try with an unescaped version of the URI */ - unescaped = xmlURIUnescapeString(URI, 0, NULL); + unescaped = xmlURIUnescapeString(normalized, 0, NULL); if (unescaped != NULL) { #ifdef HAVE_ZLIB_H if ((compression > 0) && (compression <= 9) && (is_http_uri == 0)) { @@ -1769,6 +1846,7 @@ xmlOutputBufferCreateFilename(const char *URI, ret->closecallback = xmlGzfileClose; } xmlFree(unescaped); + xmlFree(normalized); return(ret); } } @@ -1797,7 +1875,7 @@ xmlOutputBufferCreateFilename(const char *URI, if (context == NULL) { #ifdef HAVE_ZLIB_H if ((compression > 0) && (compression <= 9) && (is_http_uri == 0)) { - context = xmlGzfileOpenW(URI, compression); + context = xmlGzfileOpenW(normalized, compression); if (context != NULL) { ret = xmlAllocOutputBuffer(encoder); if (ret != NULL) { @@ -1805,13 +1883,14 @@ xmlOutputBufferCreateFilename(const char *URI, ret->writecallback = xmlGzfileWrite; ret->closecallback = xmlGzfileClose; } + xmlFree(normalized); return(ret); } } #endif for (i = xmlOutputCallbackNr - 1;i >= 0;i--) { if ((xmlOutputCallbackTable[i].matchcallback != NULL) && - (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) { + (xmlOutputCallbackTable[i].matchcallback(normalized) != 0)) { #if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H) /* Need to pass compression parameter into HTTP open calls */ if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch) @@ -1824,6 +1903,7 @@ xmlOutputBufferCreateFilename(const char *URI, } } } + xmlFree(normalized); if (context == NULL) { return(NULL); @@ -2450,8 +2530,12 @@ static int xmlSysIDExists(const char *URL) { if (URL == NULL) return(0); - if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost", 16)) + if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17)) +#if defined (_WIN32) && !defined(__CYGWIN__) + path = &URL[17]; +#else path = &URL[16]; +#endif else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) { #if defined (_WIN32) && !defined(__CYGWIN__) path = &URL[8]; @@ -2639,8 +2723,12 @@ xmlNoNetExists(const char *URL) if (URL == NULL) return (0); - if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost", 16)) - path = &URL[16]; + if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17)) +#if defined (_WIN32) && !defined(__CYGWIN__) + path = &URL[17]; +#else + path = &URL[16]; +#endif else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) { #if defined (_WIN32) && !defined(__CYGWIN__) path = &URL[8];