|
4 | 4 | #include <libxml/parser.h> |
5 | 5 | #include <string.h> |
6 | 6 |
|
| 7 | +static xmlExternalEntityLoader defaultLoader = NULL; |
| 8 | + |
7 | 9 | /* * * |
8 | 10 | * Author: Nick Wellnhofer <[email protected]> |
9 | 11 | * Date: Tue, 24 Oct 2023 15:02:36 +0200 |
@@ -49,12 +51,49 @@ void handleGenericError(void *ctx, const char *fmt, ...){ |
49 | 51 | Rf_error("%s", buffer); |
50 | 52 | } |
51 | 53 |
|
| 54 | +#if LIBXML_VERSION >= 21500 |
| 55 | + |
| 56 | +xmlParserInput *download_file_callback(const char *url){ |
| 57 | + SEXP arg = PROTECT(Rf_mkString(url)); |
| 58 | + SEXP expr = PROTECT(Rf_install("download_file_callback")); |
| 59 | + SEXP call = PROTECT(Rf_lang2(expr, arg)); |
| 60 | + SEXP env = R_FindNamespace(Rf_mkString("xml2")); |
| 61 | + int err = 1; |
| 62 | + SEXP out = PROTECT(R_tryEvalSilent(call, env, &err)); |
| 63 | + if(err) return NULL; |
| 64 | + xmlParserInputFlags flags = XML_INPUT_BUF_STATIC | XML_INPUT_USE_SYS_CATALOG; |
| 65 | + xmlParserInput *buf = xmlNewInputFromMemory(url, RAW(out), Rf_length(out), flags); |
| 66 | + //xmlParserInputBuffer *buf = xmlParserInputBufferCreateMem((char*) RAW(out), Rf_length(out), XML_CHAR_ENCODING_UTF8); |
| 67 | + UNPROTECT(4); |
| 68 | + return buf; |
| 69 | +} |
| 70 | + |
| 71 | +static xmlParserInputPtr myExternalEntityLoader(const char *URL, const char *ID, xmlParserCtxtPtr ctxt){ |
| 72 | + if (URL && (strncmp(URL, "http://", 7) == 0 || strncmp(URL, "https://", 8) == 0)) { |
| 73 | + //REprintf("Fetching external resource %s\n", URL); |
| 74 | + xmlParserInput *buf = download_file_callback(URL); |
| 75 | + if(buf) return buf; |
| 76 | + } |
| 77 | + // Fallback to default behavior |
| 78 | + if (defaultLoader) |
| 79 | + return defaultLoader(URL, ID, ctxt); |
| 80 | + return NULL; |
| 81 | +} |
| 82 | + |
| 83 | +#endif |
| 84 | + |
| 85 | + |
52 | 86 | void init_libxml2_library(void) { |
53 | 87 | // Check that header and libs are compatible |
54 | 88 | LIBXML_TEST_VERSION |
55 | 89 |
|
56 | 90 | xmlInitParser(); |
57 | 91 | xmlSetStructuredErrorFunc(NULL, handleStructuredError); |
58 | 92 | xmlSetGenericErrorFunc(NULL, handleGenericError); |
59 | | -} |
60 | 93 |
|
| 94 | + // Set custom download callback |
| 95 | +#if LIBXML_VERSION >= 21500 |
| 96 | + defaultLoader = xmlGetExternalEntityLoader(); |
| 97 | + xmlSetExternalEntityLoader(myExternalEntityLoader); |
| 98 | +#endif |
| 99 | +} |
0 commit comments