xmlIO.c
1 /* 2 * xmlIO.c : implementation of the I/O interfaces used by the parser 3 * 4 * See Copyright for the status of this software. 5 * 6 * daniel@veillard.com 7 * 8 * 14 Nov 2000 ht - for VMS, truncated name of long functions to under 32 char 9 */ 10 11 #define IN_LIBXML 12 #include "libxml.h" 13 14 #include <string.h> 15 #ifdef HAVE_ERRNO_H 16 #include <errno.h> 17 #endif 18 19 20 #ifdef HAVE_SYS_TYPES_H 21 #include <sys/types.h> 22 #endif 23 #ifdef HAVE_SYS_STAT_H 24 #include <sys/stat.h> 25 #endif 26 #ifdef HAVE_FCNTL_H 27 #include <fcntl.h> 28 #endif 29 #ifdef HAVE_UNISTD_H 30 #include <unistd.h> 31 #endif 32 #ifdef HAVE_STDLIB_H 33 #include <stdlib.h> 34 #endif 35 #ifdef HAVE_ZLIB_H 36 #include <zlib.h> 37 #endif 38 #ifdef HAVE_LZMA_H 39 #include <lzma.h> 40 #endif 41 42 #if defined(WIN32) || defined(_WIN32) 43 #include <windows.h> 44 #endif 45 46 #if defined(_WIN32_WCE) 47 #include <winnls.h> /* for CP_UTF8 */ 48 #endif 49 50 /* Figure a portable way to know if a file is a directory. */ 51 #ifndef HAVE_STAT 52 # ifdef HAVE__STAT 53 /* MS C library seems to define stat and _stat. The definition 54 is identical. Still, mapping them to each other causes a warning. */ 55 # ifndef _MSC_VER 56 # define stat(x,y) _stat(x,y) 57 # endif 58 # define HAVE_STAT 59 # endif 60 #else 61 # ifdef HAVE__STAT 62 # if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__) 63 # define stat _stat 64 # endif 65 # endif 66 #endif 67 #ifdef HAVE_STAT 68 # ifndef S_ISDIR 69 # ifdef _S_ISDIR 70 # define S_ISDIR(x) _S_ISDIR(x) 71 # else 72 # ifdef S_IFDIR 73 # ifndef S_IFMT 74 # ifdef _S_IFMT 75 # define S_IFMT _S_IFMT 76 # endif 77 # endif 78 # ifdef S_IFMT 79 # define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) 80 # endif 81 # endif 82 # endif 83 # endif 84 #endif 85 86 #include <libxml/xmlmemory.h> 87 #include <libxml/parser.h> 88 #include <libxml/parserInternals.h> 89 #include <libxml/xmlIO.h> 90 #include <libxml/uri.h> 91 #include <libxml/nanohttp.h> 92 #include <libxml/nanoftp.h> 93 #include <libxml/xmlerror.h> 94 #ifdef LIBXML_CATALOG_ENABLED 95 #include <libxml/catalog.h> 96 #endif 97 #include <libxml/globals.h> 98 99 #include "buf.h" 100 #include "enc.h" 101 102 /* #define VERBOSE_FAILURE */ 103 /* #define DEBUG_EXTERNAL_ENTITIES */ 104 /* #define DEBUG_INPUT */ 105 106 #ifdef DEBUG_INPUT 107 #define MINLEN 40 108 #else 109 #define MINLEN 4000 110 #endif 111 112 /* 113 * Input I/O callback sets 114 */ 115 typedef struct _xmlInputCallback { 116 xmlInputMatchCallback matchcallback; 117 xmlInputOpenCallback opencallback; 118 xmlInputReadCallback readcallback; 119 xmlInputCloseCallback closecallback; 120 } xmlInputCallback; 121 122 #define MAX_INPUT_CALLBACK 15 123 124 static xmlInputCallback xmlInputCallbackTable[MAX_INPUT_CALLBACK]; 125 static int xmlInputCallbackNr = 0; 126 static int xmlInputCallbackInitialized = 0; 127 128 #ifdef LIBXML_OUTPUT_ENABLED 129 /* 130 * Output I/O callback sets 131 */ 132 typedef struct _xmlOutputCallback { 133 xmlOutputMatchCallback matchcallback; 134 xmlOutputOpenCallback opencallback; 135 xmlOutputWriteCallback writecallback; 136 xmlOutputCloseCallback closecallback; 137 } xmlOutputCallback; 138 139 #define MAX_OUTPUT_CALLBACK 15 140 141 static xmlOutputCallback xmlOutputCallbackTable[MAX_OUTPUT_CALLBACK]; 142 static int xmlOutputCallbackNr = 0; 143 static int xmlOutputCallbackInitialized = 0; 144 145 xmlOutputBufferPtr 146 xmlAllocOutputBufferInternal(xmlCharEncodingHandlerPtr encoder); 147 #endif /* LIBXML_OUTPUT_ENABLED */ 148 149 /************************************************************************ 150 * * 151 * Tree memory error handler * 152 * * 153 ************************************************************************/ 154 155 static const char * const IOerr[] = { 156 "Unknown IO error", /* UNKNOWN */ 157 "Permission denied", /* EACCES */ 158 "Resource temporarily unavailable",/* EAGAIN */ 159 "Bad file descriptor", /* EBADF */ 160 "Bad message", /* EBADMSG */ 161 "Resource busy", /* EBUSY */ 162 "Operation canceled", /* ECANCELED */ 163 "No child processes", /* ECHILD */ 164 "Resource deadlock avoided",/* EDEADLK */ 165 "Domain error", /* EDOM */ 166 "File exists", /* EEXIST */ 167 "Bad address", /* EFAULT */ 168 "File too large", /* EFBIG */ 169 "Operation in progress", /* EINPROGRESS */ 170 "Interrupted function call",/* EINTR */ 171 "Invalid argument", /* EINVAL */ 172 "Input/output error", /* EIO */ 173 "Is a directory", /* EISDIR */ 174 "Too many open files", /* EMFILE */ 175 "Too many links", /* EMLINK */ 176 "Inappropriate message buffer length",/* EMSGSIZE */ 177 "Filename too long", /* ENAMETOOLONG */ 178 "Too many open files in system",/* ENFILE */ 179 "No such device", /* ENODEV */ 180 "No such file or directory",/* ENOENT */ 181 "Exec format error", /* ENOEXEC */ 182 "No locks available", /* ENOLCK */ 183 "Not enough space", /* ENOMEM */ 184 "No space left on device", /* ENOSPC */ 185 "Function not implemented", /* ENOSYS */ 186 "Not a directory", /* ENOTDIR */ 187 "Directory not empty", /* ENOTEMPTY */ 188 "Not supported", /* ENOTSUP */ 189 "Inappropriate I/O control operation",/* ENOTTY */ 190 "No such device or address",/* ENXIO */ 191 "Operation not permitted", /* EPERM */ 192 "Broken pipe", /* EPIPE */ 193 "Result too large", /* ERANGE */ 194 "Read-only file system", /* EROFS */ 195 "Invalid seek", /* ESPIPE */ 196 "No such process", /* ESRCH */ 197 "Operation timed out", /* ETIMEDOUT */ 198 "Improper link", /* EXDEV */ 199 "Attempt to load network entity %s", /* XML_IO_NETWORK_ATTEMPT */ 200 "encoder error", /* XML_IO_ENCODER */ 201 "flush error", 202 "write error", 203 "no input", 204 "buffer full", 205 "loading error", 206 "not a socket", /* ENOTSOCK */ 207 "already connected", /* EISCONN */ 208 "connection refused", /* ECONNREFUSED */ 209 "unreachable network", /* ENETUNREACH */ 210 "adddress in use", /* EADDRINUSE */ 211 "already in use", /* EALREADY */ 212 "unknown address familly", /* EAFNOSUPPORT */ 213 }; 214 215 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__) 216 /** 217 * __xmlIOWin32UTF8ToWChar: 218 * @u8String: uft-8 string 219 * 220 * Convert a string from utf-8 to wchar (WINDOWS ONLY!) 221 */ 222 static wchar_t * 223 __xmlIOWin32UTF8ToWChar(const char *u8String) 224 { 225 wchar_t *wString = NULL; 226 227 if (u8String) { 228 int wLen = 229 MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, u8String, 230 -1, NULL, 0); 231 if (wLen) { 232 wString = xmlMalloc(wLen * sizeof(wchar_t)); 233 if (wString) { 234 if (MultiByteToWideChar 235 (CP_UTF8, 0, u8String, -1, wString, wLen) == 0) { 236 xmlFree(wString); 237 wString = NULL; 238 } 239 } 240 } 241 } 242 243 return wString; 244 } 245 #endif 246 247 /** 248 * xmlIOErrMemory: 249 * @extra: extra informations 250 * 251 * Handle an out of memory condition 252 */ 253 static void 254 xmlIOErrMemory(const char *extra) 255 { 256 __xmlSimpleError(XML_FROM_IO, XML_ERR_NO_MEMORY, NULL, NULL, extra); 257 } 258 259 /** 260 * __xmlIOErr: 261 * @code: the error number 262 * @ 263 * @extra: extra informations 264 * 265 * Handle an I/O error 266 */ 267 void 268 __xmlIOErr(int domain, int code, const char *extra) 269 { 270 unsigned int idx; 271 272 if (code == 0) { 273 #ifdef HAVE_ERRNO_H 274 if (errno == 0) code = 0; 275 #ifdef EACCES 276 else if (errno == EACCES) code = XML_IO_EACCES; 277 #endif 278 #ifdef EAGAIN 279 else if (errno == EAGAIN) code = XML_IO_EAGAIN; 280 #endif 281 #ifdef EBADF 282 else if (errno == EBADF) code = XML_IO_EBADF; 283 #endif 284 #ifdef EBADMSG 285 else if (errno == EBADMSG) code = XML_IO_EBADMSG; 286 #endif 287 #ifdef EBUSY 288 else if (errno == EBUSY) code = XML_IO_EBUSY; 289 #endif 290 #ifdef ECANCELED 291 else if (errno == ECANCELED) code = XML_IO_ECANCELED; 292 #endif 293 #ifdef ECHILD 294 else if (errno == ECHILD) code = XML_IO_ECHILD; 295 #endif 296 #ifdef EDEADLK 297 else if (errno == EDEADLK) code = XML_IO_EDEADLK; 298 #endif 299 #ifdef EDOM 300 else if (errno == EDOM) code = XML_IO_EDOM; 301 #endif 302 #ifdef EEXIST 303 else if (errno == EEXIST) code = XML_IO_EEXIST; 304 #endif 305 #ifdef EFAULT 306 else if (errno == EFAULT) code = XML_IO_EFAULT; 307 #endif 308 #ifdef EFBIG 309 else if (errno == EFBIG) code = XML_IO_EFBIG; 310 #endif 311 #ifdef EINPROGRESS 312 else if (errno == EINPROGRESS) code = XML_IO_EINPROGRESS; 313 #endif 314 #ifdef EINTR 315 else if (errno == EINTR) code = XML_IO_EINTR; 316 #endif 317 #ifdef EINVAL 318 else if (errno == EINVAL) code = XML_IO_EINVAL; 319 #endif 320 #ifdef EIO 321 else if (errno == EIO) code = XML_IO_EIO; 322 #endif 323 #ifdef EISDIR 324 else if (errno == EISDIR) code = XML_IO_EISDIR; 325 #endif 326 #ifdef EMFILE 327 else if (errno == EMFILE) code = XML_IO_EMFILE; 328 #endif 329 #ifdef EMLINK 330 else if (errno == EMLINK) code = XML_IO_EMLINK; 331 #endif 332 #ifdef EMSGSIZE 333 else if (errno == EMSGSIZE) code = XML_IO_EMSGSIZE; 334 #endif 335 #ifdef ENAMETOOLONG 336 else if (errno == ENAMETOOLONG) code = XML_IO_ENAMETOOLONG; 337 #endif 338 #ifdef ENFILE 339 else if (errno == ENFILE) code = XML_IO_ENFILE; 340 #endif 341 #ifdef ENODEV 342 else if (errno == ENODEV) code = XML_IO_ENODEV; 343 #endif 344 #ifdef ENOENT 345 else if (errno == ENOENT) code = XML_IO_ENOENT; 346 #endif 347 #ifdef ENOEXEC 348 else if (errno == ENOEXEC) code = XML_IO_ENOEXEC; 349 #endif 350 #ifdef ENOLCK 351 else if (errno == ENOLCK) code = XML_IO_ENOLCK; 352 #endif 353 #ifdef ENOMEM 354 else if (errno == ENOMEM) code = XML_IO_ENOMEM; 355 #endif 356 #ifdef ENOSPC 357 else if (errno == ENOSPC) code = XML_IO_ENOSPC; 358 #endif 359 #ifdef ENOSYS 360 else if (errno == ENOSYS) code = XML_IO_ENOSYS; 361 #endif 362 #ifdef ENOTDIR 363 else if (errno == ENOTDIR) code = XML_IO_ENOTDIR; 364 #endif 365 #ifdef ENOTEMPTY 366 else if (errno == ENOTEMPTY) code = XML_IO_ENOTEMPTY; 367 #endif 368 #ifdef ENOTSUP 369 else if (errno == ENOTSUP) code = XML_IO_ENOTSUP; 370 #endif 371 #ifdef ENOTTY 372 else if (errno == ENOTTY) code = XML_IO_ENOTTY; 373 #endif 374 #ifdef ENXIO 375 else if (errno == ENXIO) code = XML_IO_ENXIO; 376 #endif 377 #ifdef EPERM 378 else if (errno == EPERM) code = XML_IO_EPERM; 379 #endif 380 #ifdef EPIPE 381 else if (errno == EPIPE) code = XML_IO_EPIPE; 382 #endif 383 #ifdef ERANGE 384 else if (errno == ERANGE) code = XML_IO_ERANGE; 385 #endif 386 #ifdef EROFS 387 else if (errno == EROFS) code = XML_IO_EROFS; 388 #endif 389 #ifdef ESPIPE 390 else if (errno == ESPIPE) code = XML_IO_ESPIPE; 391 #endif 392 #ifdef ESRCH 393 else if (errno == ESRCH) code = XML_IO_ESRCH; 394 #endif 395 #ifdef ETIMEDOUT 396 else if (errno == ETIMEDOUT) code = XML_IO_ETIMEDOUT; 397 #endif 398 #ifdef EXDEV 399 else if (errno == EXDEV) code = XML_IO_EXDEV; 400 #endif 401 #ifdef ENOTSOCK 402 else if (errno == ENOTSOCK) code = XML_IO_ENOTSOCK; 403 #endif 404 #ifdef EISCONN 405 else if (errno == EISCONN) code = XML_IO_EISCONN; 406 #endif 407 #ifdef ECONNREFUSED 408 else if (errno == ECONNREFUSED) code = XML_IO_ECONNREFUSED; 409 #endif 410 #ifdef ETIMEDOUT 411 else if (errno == ETIMEDOUT) code = XML_IO_ETIMEDOUT; 412 #endif 413 #ifdef ENETUNREACH 414 else if (errno == ENETUNREACH) code = XML_IO_ENETUNREACH; 415 #endif 416 #ifdef EADDRINUSE 417 else if (errno == EADDRINUSE) code = XML_IO_EADDRINUSE; 418 #endif 419 #ifdef EINPROGRESS 420 else if (errno == EINPROGRESS) code = XML_IO_EINPROGRESS; 421 #endif 422 #ifdef EALREADY 423 else if (errno == EALREADY) code = XML_IO_EALREADY; 424 #endif 425 #ifdef EAFNOSUPPORT 426 else if (errno == EAFNOSUPPORT) code = XML_IO_EAFNOSUPPORT; 427 #endif 428 else code = XML_IO_UNKNOWN; 429 #endif /* HAVE_ERRNO_H */ 430 } 431 idx = 0; 432 if (code >= XML_IO_UNKNOWN) idx = code - XML_IO_UNKNOWN; 433 if (idx >= (sizeof(IOerr) / sizeof(IOerr[0]))) idx = 0; 434 435 #pragma clang diagnostic push 436 #pragma clang diagnostic ignored "-Wformat-nonliteral" 437 __xmlSimpleError(domain, code, NULL, IOerr[idx], extra); 438 #pragma clang diagnostic pop 439 } 440 441 /** 442 * xmlIOErr: 443 * @code: the error number 444 * @extra: extra informations 445 * 446 * Handle an I/O error 447 */ 448 static void 449 xmlIOErr(int code, const char *extra) 450 { 451 __xmlIOErr(XML_FROM_IO, code, extra); 452 } 453 454 /** 455 * __xmlLoaderErr: 456 * @ctx: the parser context 457 * @extra: extra informations 458 * 459 * Handle a resource access error 460 */ 461 void 462 __xmlLoaderErr(void *ctx, const char *msg, const char *filename) 463 { 464 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; 465 xmlStructuredErrorFunc schannel = NULL; 466 xmlGenericErrorFunc channel = NULL; 467 void *data = NULL; 468 xmlErrorLevel level = XML_ERR_ERROR; 469 470 if ((ctxt != NULL) && (ctxt->disableSAX != 0) && 471 (ctxt->instate == XML_PARSER_EOF)) 472 return; 473 if ((ctxt != NULL) && (ctxt->sax != NULL)) { 474 if (ctxt->validate) { 475 channel = ctxt->sax->error; 476 level = XML_ERR_ERROR; 477 } else { 478 channel = ctxt->sax->warning; 479 level = XML_ERR_WARNING; 480 } 481 if (ctxt->sax->initialized == XML_SAX2_MAGIC) 482 schannel = ctxt->sax->serror; 483 data = ctxt->userData; 484 } 485 #pragma clang diagnostic push 486 #pragma clang diagnostic ignored "-Wformat-nonliteral" 487 __xmlRaiseError(schannel, channel, data, ctxt, NULL, XML_FROM_IO, 488 XML_IO_LOAD_ERROR, level, NULL, 0, 489 filename, NULL, NULL, 0, 0, 490 msg, filename); 491 #pragma clang diagnostic pop 492 } 493 494 /************************************************************************ 495 * * 496 * Tree memory error handler * 497 * * 498 ************************************************************************/ 499 /** 500 * xmlNormalizeWindowsPath: 501 * @path: the input file path 502 * 503 * This function is obsolete. Please see xmlURIFromPath in uri.c for 504 * a better solution. 505 * 506 * Returns a canonicalized version of the path 507 */ 508 xmlChar * 509 xmlNormalizeWindowsPath(const xmlChar *path) 510 { 511 return xmlCanonicPath(path); 512 } 513 514 /** 515 * xmlCleanupInputCallbacks: 516 * 517 * clears the entire input callback table. this includes the 518 * compiled-in I/O. 519 */ 520 void 521 xmlCleanupInputCallbacks(void) 522 { 523 int i; 524 525 if (!xmlInputCallbackInitialized) 526 return; 527 528 for (i = xmlInputCallbackNr - 1; i >= 0; i--) { 529 xmlInputCallbackTable[i].matchcallback = NULL; 530 xmlInputCallbackTable[i].opencallback = NULL; 531 xmlInputCallbackTable[i].readcallback = NULL; 532 xmlInputCallbackTable[i].closecallback = NULL; 533 } 534 535 xmlInputCallbackNr = 0; 536 xmlInputCallbackInitialized = 0; 537 } 538 539 /** 540 * xmlPopInputCallbacks: 541 * 542 * Clear the top input callback from the input stack. this includes the 543 * compiled-in I/O. 544 * 545 * Returns the number of input callback registered or -1 in case of error. 546 */ 547 int 548 xmlPopInputCallbacks(void) 549 { 550 if (!xmlInputCallbackInitialized) 551 return(-1); 552 553 if (xmlInputCallbackNr <= 0) 554 return(-1); 555 556 xmlInputCallbackNr--; 557 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = NULL; 558 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = NULL; 559 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = NULL; 560 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = NULL; 561 562 return(xmlInputCallbackNr); 563 } 564 565 #ifdef LIBXML_OUTPUT_ENABLED 566 /** 567 * xmlCleanupOutputCallbacks: 568 * 569 * clears the entire output callback table. this includes the 570 * compiled-in I/O callbacks. 571 */ 572 void 573 xmlCleanupOutputCallbacks(void) 574 { 575 int i; 576 577 if (!xmlOutputCallbackInitialized) 578 return; 579 580 for (i = xmlOutputCallbackNr - 1; i >= 0; i--) { 581 xmlOutputCallbackTable[i].matchcallback = NULL; 582 xmlOutputCallbackTable[i].opencallback = NULL; 583 xmlOutputCallbackTable[i].writecallback = NULL; 584 xmlOutputCallbackTable[i].closecallback = NULL; 585 } 586 587 xmlOutputCallbackNr = 0; 588 xmlOutputCallbackInitialized = 0; 589 } 590 #endif /* LIBXML_OUTPUT_ENABLED */ 591 592 /************************************************************************ 593 * * 594 * Standard I/O for file accesses * 595 * * 596 ************************************************************************/ 597 598 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__) 599 600 /** 601 * xmlWrapOpenUtf8: 602 * @path: the path in utf-8 encoding 603 * @mode: type of access (0 - read, 1 - write) 604 * 605 * function opens the file specified by @path 606 * 607 */ 608 static FILE* 609 xmlWrapOpenUtf8(const char *path,int mode) 610 { 611 FILE *fd = NULL; 612 wchar_t *wPath; 613 614 wPath = __xmlIOWin32UTF8ToWChar(path); 615 if(wPath) 616 { 617 fd = _wfopen(wPath, mode ? L"wb" : L"rb"); 618 xmlFree(wPath); 619 } 620 /* maybe path in native encoding */ 621 if(fd == NULL) 622 fd = fopen(path, mode ? "wb" : "rb"); 623 624 return fd; 625 } 626 627 #ifdef HAVE_ZLIB_H 628 static gzFile 629 xmlWrapGzOpenUtf8(const char *path, const char *mode) 630 { 631 gzFile fd; 632 wchar_t *wPath; 633 634 fd = gzopen (path, mode); 635 if (fd) 636 return fd; 637 638 wPath = __xmlIOWin32UTF8ToWChar(path); 639 if(wPath) 640 { 641 int d, m = (strstr(mode, "r") ? O_RDONLY : O_RDWR); 642 #ifdef _O_BINARY 643 m |= (strstr(mode, "b") ? _O_BINARY : 0); 644 #endif 645 d = _wopen(wPath, m); 646 if (d >= 0) 647 fd = gzdopen(d, mode); 648 xmlFree(wPath); 649 } 650 651 return fd; 652 } 653 #endif 654 655 /** 656 * xmlWrapStatUtf8: 657 * @path: the path in utf-8 encoding 658 * @info: structure that stores results 659 * 660 * function obtains information about the file or directory 661 * 662 */ 663 static int 664 xmlWrapStatUtf8(const char *path,struct stat *info) 665 { 666 #ifdef HAVE_STAT 667 int retval = -1; 668 wchar_t *wPath; 669 670 wPath = __xmlIOWin32UTF8ToWChar(path); 671 if (wPath) 672 { 673 retval = _wstat(wPath,info); 674 xmlFree(wPath); 675 } 676 /* maybe path in native encoding */ 677 if(retval < 0) 678 retval = stat(path,info); 679 return retval; 680 #else 681 return -1; 682 #endif 683 } 684 685 /** 686 * xmlWrapOpenNative: 687 * @path: the path 688 * @mode: type of access (0 - read, 1 - write) 689 * 690 * function opens the file specified by @path 691 * 692 */ 693 static FILE* 694 xmlWrapOpenNative(const char *path,int mode) 695 { 696 return fopen(path,mode ? "wb" : "rb"); 697 } 698 699 /** 700 * xmlWrapStatNative: 701 * @path: the path 702 * @info: structure that stores results 703 * 704 * function obtains information about the file or directory 705 * 706 */ 707 static int 708 xmlWrapStatNative(const char *path,struct stat *info) 709 { 710 #ifdef HAVE_STAT 711 return stat(path,info); 712 #else 713 return -1; 714 #endif 715 } 716 717 typedef int (* xmlWrapStatFunc) (const char *f, struct stat *s); 718 static xmlWrapStatFunc xmlWrapStat = xmlWrapStatNative; 719 typedef FILE* (* xmlWrapOpenFunc)(const char *f,int mode); 720 static xmlWrapOpenFunc xmlWrapOpen = xmlWrapOpenNative; 721 #ifdef HAVE_ZLIB_H 722 typedef gzFile (* xmlWrapGzOpenFunc) (const char *f, const char *mode); 723 static xmlWrapGzOpenFunc xmlWrapGzOpen = gzopen; 724 #endif 725 /** 726 * xmlInitPlatformSpecificIo: 727 * 728 * Initialize platform specific features. 729 */ 730 static void 731 xmlInitPlatformSpecificIo(void) 732 { 733 static int xmlPlatformIoInitialized = 0; 734 OSVERSIONINFO osvi; 735 736 if(xmlPlatformIoInitialized) 737 return; 738 739 osvi.dwOSVersionInfoSize = sizeof(osvi); 740 741 if(GetVersionEx(&osvi) && (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT)) { 742 xmlWrapStat = xmlWrapStatUtf8; 743 xmlWrapOpen = xmlWrapOpenUtf8; 744 #ifdef HAVE_ZLIB_H 745 xmlWrapGzOpen = xmlWrapGzOpenUtf8; 746 #endif 747 } else { 748 xmlWrapStat = xmlWrapStatNative; 749 xmlWrapOpen = xmlWrapOpenNative; 750 #ifdef HAVE_ZLIB_H 751 xmlWrapGzOpen = gzopen; 752 #endif 753 } 754 755 xmlPlatformIoInitialized = 1; 756 return; 757 } 758 759 #endif 760 761 /** 762 * xmlCheckFilename: 763 * @path: the path to check 764 * 765 * function checks to see if @path is a valid source 766 * (file, socket...) for XML. 767 * 768 * if stat is not available on the target machine, 769 * returns 1. if stat fails, returns 0 (if calling 770 * stat on the filename fails, it can't be right). 771 * if stat succeeds and the file is a directory, 772 * returns 2. otherwise returns 1. 773 */ 774 775 int 776 xmlCheckFilename (const char *path) 777 { 778 #ifdef HAVE_STAT 779 struct stat stat_buffer; 780 #endif 781 if (path == NULL) 782 return(0); 783 784 #ifdef HAVE_STAT 785 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__) 786 /* 787 * On Windows stat and wstat do not work with long pathname, 788 * which start with '\\?\' 789 */ 790 if ((path[0] == '\\') && (path[1] == '\\') && (path[2] == '?') && 791 (path[3] == '\\') ) 792 return 1; 793 794 if (xmlWrapStat(path, &stat_buffer) == -1) 795 return 0; 796 #else 797 if (stat(path, &stat_buffer) == -1) 798 return 0; 799 #endif 800 #ifdef S_ISDIR 801 if (S_ISDIR(stat_buffer.st_mode)) 802 return 2; 803 #endif 804 #endif /* HAVE_STAT */ 805 return 1; 806 } 807 808 /** 809 * xmlNop: 810 * 811 * No Operation function, does nothing, no input 812 * 813 * Returns zero 814 */ 815 int 816 xmlNop(void) { 817 return(0); 818 } 819 820 /** 821 * xmlFdRead: 822 * @context: the I/O context 823 * @buffer: where to drop data 824 * @len: number of bytes to read 825 * 826 * Read @len bytes to @buffer from the I/O channel. 827 * 828 * Returns the number of bytes written 829 */ 830 static int 831 xmlFdRead (void * context, char * buffer, int len) { 832 int ret; 833 834 ret = read((int) (long) context, &buffer[0], len); 835 if (ret < 0) xmlIOErr(0, "read()"); 836 return(ret); 837 } 838 839 #ifdef LIBXML_OUTPUT_ENABLED 840 /** 841 * xmlFdWrite: 842 * @context: the I/O context 843 * @buffer: where to get data 844 * @len: number of bytes to write 845 * 846 * Write @len bytes from @buffer to the I/O channel. 847 * 848 * Returns the number of bytes written 849 */ 850 static int 851 xmlFdWrite (void * context, const char * buffer, int len) { 852 int ret = 0; 853 854 if (len > 0) { 855 ret = write((int) (long) context, &buffer[0], len); 856 if (ret < 0) xmlIOErr(0, "write()"); 857 } 858 return(ret); 859 } 860 #endif /* LIBXML_OUTPUT_ENABLED */ 861 862 /** 863 * xmlFdClose: 864 * @context: the I/O context 865 * 866 * Close an I/O channel 867 * 868 * Returns 0 in case of success and error code otherwise 869 */ 870 static int 871 xmlFdClose (void * context) { 872 int ret; 873 ret = close((int) (long) context); 874 if (ret < 0) xmlIOErr(0, "close()"); 875 return(ret); 876 } 877 878 /** 879 * xmlFileMatch: 880 * @filename: the URI for matching 881 * 882 * input from FILE * 883 * 884 * Returns 1 if matches, 0 otherwise 885 */ 886 int 887 xmlFileMatch (const char *filename ATTRIBUTE_UNUSED) { 888 return(1); 889 } 890 891 /** 892 * xmlFileOpen_real: 893 * @filename: the URI for matching 894 * 895 * input from FILE *, supports compressed input 896 * if @filename is " " then the standard input is used 897 * 898 * Returns an I/O context or NULL in case of error 899 */ 900 static void * 901 xmlFileOpen_real (const char *filename) { 902 const char *path = filename; 903 FILE *fd; 904 905 if (filename == NULL) 906 return(NULL); 907 908 if (!strcmp(filename, "-")) { 909 fd = stdin; 910 return((void *) fd); 911 } 912 913 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17)) { 914 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__) 915 path = &filename[17]; 916 #else 917 path = &filename[16]; 918 #endif 919 } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) { 920 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__) 921 path = &filename[8]; 922 #else 923 path = &filename[7]; 924 #endif 925 } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:/", 6)) { 926 /* lots of generators seems to lazy to read RFC 1738 */ 927 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__) 928 path = &filename[6]; 929 #else 930 path = &filename[5]; 931 #endif 932 } 933 934 if (!xmlCheckFilename(path)) 935 return(NULL); 936 937 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__) 938 fd = xmlWrapOpen(path, 0); 939 #else 940 fd = fopen(path, "r"); 941 #endif /* WIN32 */ 942 if (fd == NULL) xmlIOErr(0, path); 943 return((void *) fd); 944 } 945 946 /** 947 * xmlFileOpen: 948 * @filename: the URI for matching 949 * 950 * Wrapper around xmlFileOpen_real that try it with an unescaped 951 * version of @filename, if this fails fallback to @filename 952 * 953 * Returns a handler or NULL in case or failure 954 */ 955 void * 956 xmlFileOpen (const char *filename) { 957 char *unescaped; 958 void *retval; 959 960 retval = xmlFileOpen_real(filename); 961 if (retval == NULL) { 962 unescaped = xmlURIUnescapeString(filename, 0, NULL); 963 if (unescaped != NULL) { 964 retval = xmlFileOpen_real(unescaped); 965 xmlFree(unescaped); 966 } 967 } 968 969 return retval; 970 } 971 972 #ifdef LIBXML_OUTPUT_ENABLED 973 /** 974 * xmlFileOpenW: 975 * @filename: the URI for matching 976 * 977 * output to from FILE *, 978 * if @filename is "-" then the standard output is used 979 * 980 * Returns an I/O context or NULL in case of error 981 */ 982 static void * 983 xmlFileOpenW (const char *filename) { 984 const char *path = NULL; 985 FILE *fd; 986 987 if (!strcmp(filename, "-")) { 988 fd = stdout; 989 return((void *) fd); 990 } 991 992 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17)) 993 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__) 994 path = &filename[17]; 995 #else 996 path = &filename[16]; 997 #endif 998 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) { 999 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__) 1000 path = &filename[8]; 1001 #else 1002 path = &filename[7]; 1003 #endif 1004 } else 1005 path = filename; 1006 1007 if (path == NULL) 1008 return(NULL); 1009 1010 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__) 1011 fd = xmlWrapOpen(path, 1); 1012 #else 1013 fd = fopen(path, "wb"); 1014 #endif /* WIN32 */ 1015 1016 if (fd == NULL) xmlIOErr(0, path); 1017 return((void *) fd); 1018 } 1019 #endif /* LIBXML_OUTPUT_ENABLED */ 1020 1021 /** 1022 * xmlFileRead: 1023 * @context: the I/O context 1024 * @buffer: where to drop data 1025 * @len: number of bytes to write 1026 * 1027 * Read @len bytes to @buffer from the I/O channel. 1028 * 1029 * Returns the number of bytes written or < 0 in case of failure 1030 */ 1031 int 1032 xmlFileRead (void * context, char * buffer, int len) { 1033 int ret; 1034 if ((context == NULL) || (buffer == NULL)) 1035 return(-1); 1036 ret = fread(&buffer[0], 1, len, (FILE *) context); 1037 if (ret < 0) xmlIOErr(0, "fread()"); 1038 return(ret); 1039 } 1040 1041 #ifdef LIBXML_OUTPUT_ENABLED 1042 /** 1043 * xmlFileWrite: 1044 * @context: the I/O context 1045 * @buffer: where to drop data 1046 * @len: number of bytes to write 1047 * 1048 * Write @len bytes from @buffer to the I/O channel. 1049 * 1050 * Returns the number of bytes written 1051 */ 1052 static int 1053 xmlFileWrite (void * context, const char * buffer, int len) { 1054 int items; 1055 1056 if ((context == NULL) || (buffer == NULL)) 1057 return(-1); 1058 items = fwrite(&buffer[0], len, 1, (FILE *) context); 1059 if ((items == 0) && (ferror((FILE *) context))) { 1060 xmlIOErr(0, "fwrite()"); 1061 return(-1); 1062 } 1063 return(items * len); 1064 } 1065 #endif /* LIBXML_OUTPUT_ENABLED */ 1066 1067 /** 1068 * xmlFileClose: 1069 * @context: the I/O context 1070 * 1071 * Close an I/O channel 1072 * 1073 * Returns 0 or -1 in case of error 1074 */ 1075 int 1076 xmlFileClose (void * context) { 1077 FILE *fil; 1078 int ret; 1079 1080 if (context == NULL) 1081 return(-1); 1082 fil = (FILE *) context; 1083 if ((fil == stdout) || (fil == stderr)) { 1084 ret = fflush(fil); 1085 if (ret < 0) 1086 xmlIOErr(0, "fflush()"); 1087 return(0); 1088 } 1089 if (fil == stdin) 1090 return(0); 1091 ret = ( fclose((FILE *) context) == EOF ) ? -1 : 0; 1092 if (ret < 0) 1093 xmlIOErr(0, "fclose()"); 1094 return(ret); 1095 } 1096 1097 /** 1098 * xmlFileFlush: 1099 * @context: the I/O context 1100 * 1101 * Flush an I/O channel 1102 */ 1103 static int 1104 xmlFileFlush (void * context) { 1105 int ret; 1106 1107 if (context == NULL) 1108 return(-1); 1109 ret = ( fflush((FILE *) context) == EOF ) ? -1 : 0; 1110 if (ret < 0) 1111 xmlIOErr(0, "fflush()"); 1112 return(ret); 1113 } 1114 1115 #ifdef LIBXML_OUTPUT_ENABLED 1116 /** 1117 * xmlBufferWrite: 1118 * @context: the xmlBuffer 1119 * @buffer: the data to write 1120 * @len: number of bytes to write 1121 * 1122 * Write @len bytes from @buffer to the xml buffer 1123 * 1124 * Returns the number of bytes written 1125 */ 1126 static int 1127 xmlBufferWrite (void * context, const char * buffer, int len) { 1128 int ret; 1129 1130 ret = xmlBufferAdd((xmlBufferPtr) context, (const xmlChar *) buffer, len); 1131 if (ret != 0) 1132 return(-1); 1133 return(len); 1134 } 1135 #endif 1136 1137 #ifdef HAVE_ZLIB_H 1138 /************************************************************************ 1139 * * 1140 * I/O for compressed file accesses * 1141 * * 1142 ************************************************************************/ 1143 /** 1144 * xmlGzfileMatch: 1145 * @filename: the URI for matching 1146 * 1147 * input from compressed file test 1148 * 1149 * Returns 1 if matches, 0 otherwise 1150 */ 1151 static int 1152 xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED) { 1153 return(1); 1154 } 1155 1156 /** 1157 * xmlGzfileOpen_real: 1158 * @filename: the URI for matching 1159 * 1160 * input from compressed file open 1161 * if @filename is " " then the standard input is used 1162 * 1163 * Returns an I/O context or NULL in case of error 1164 */ 1165 static void * 1166 xmlGzfileOpen_real (const char *filename) { 1167 const char *path = NULL; 1168 gzFile fd; 1169 1170 if (!strcmp(filename, "-")) { 1171 int duped_fd = dup(fileno(stdin)); 1172 fd = gzdopen(duped_fd, "rb"); 1173 if (fd == Z_NULL && duped_fd >= 0) { 1174 close(duped_fd); /* gzdOpen() does not close on failure */ 1175 } 1176 1177 return((void *) fd); 1178 } 1179 1180 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17)) 1181 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__) 1182 path = &filename[17]; 1183 #else 1184 path = &filename[16]; 1185 #endif 1186 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) { 1187 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__) 1188 path = &filename[8]; 1189 #else 1190 path = &filename[7]; 1191 #endif 1192 } else 1193 path = filename; 1194 1195 if (path == NULL) 1196 return(NULL); 1197 if (!xmlCheckFilename(path)) 1198 return(NULL); 1199 1200 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__) 1201 fd = xmlWrapGzOpen(path, "rb"); 1202 #else 1203 fd = gzopen(path, "rb"); 1204 #endif 1205 return((void *) fd); 1206 } 1207 1208 /** 1209 * xmlGzfileOpen: 1210 * @filename: the URI for matching 1211 * 1212 * Wrapper around xmlGzfileOpen if the open fais, it will 1213 * try to unescape @filename 1214 */ 1215 static void * 1216 xmlGzfileOpen (const char *filename) { 1217 char *unescaped; 1218 void *retval; 1219 1220 retval = xmlGzfileOpen_real(filename); 1221 if (retval == NULL) { 1222 unescaped = xmlURIUnescapeString(filename, 0, NULL); 1223 if (unescaped != NULL) { 1224 retval = xmlGzfileOpen_real(unescaped); 1225 } 1226 xmlFree(unescaped); 1227 } 1228 return retval; 1229 } 1230 1231 #ifdef LIBXML_OUTPUT_ENABLED 1232 /** 1233 * xmlGzfileOpenW: 1234 * @filename: the URI for matching 1235 * @compression: the compression factor (0 - 9 included) 1236 * 1237 * input from compressed file open 1238 * if @filename is " " then the standard input is used 1239 * 1240 * Returns an I/O context or NULL in case of error 1241 */ 1242 static void * 1243 xmlGzfileOpenW (const char *filename, int compression) { 1244 const char *path = NULL; 1245 char mode[15]; 1246 gzFile fd; 1247 1248 snprintf(mode, sizeof(mode), "wb%d", compression); 1249 if (!strcmp(filename, "-")) { 1250 int duped_fd = dup(fileno(stdout)); 1251 fd = gzdopen(duped_fd, "rb"); 1252 if (fd == Z_NULL && duped_fd >= 0) { 1253 close(duped_fd); /* gzdOpen() does not close on failure */ 1254 } 1255 1256 return((void *) fd); 1257 } 1258 1259 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17)) 1260 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__) 1261 path = &filename[17]; 1262 #else 1263 path = &filename[16]; 1264 #endif 1265 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) { 1266 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__) 1267 path = &filename[8]; 1268 #else 1269 path = &filename[7]; 1270 #endif 1271 } else 1272 path = filename; 1273 1274 if (path == NULL) 1275 return(NULL); 1276 1277 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__) 1278 fd = xmlWrapGzOpen(path, mode); 1279 #else 1280 fd = gzopen(path, mode); 1281 #endif 1282 return((void *) fd); 1283 } 1284 #endif /* LIBXML_OUTPUT_ENABLED */ 1285 1286 /** 1287 * xmlGzfileRead: 1288 * @context: the I/O context 1289 * @buffer: where to drop data 1290 * @len: number of bytes to write 1291 * 1292 * Read @len bytes to @buffer from the compressed I/O channel. 1293 * 1294 * Returns the number of bytes written 1295 */ 1296 static int 1297 xmlGzfileRead (void * context, char * buffer, int len) { 1298 int ret; 1299 1300 ret = gzread((gzFile) context, &buffer[0], len); 1301 if (ret < 0) xmlIOErr(0, "gzread()"); 1302 return(ret); 1303 } 1304 1305 #ifdef LIBXML_OUTPUT_ENABLED 1306 /** 1307 * xmlGzfileWrite: 1308 * @context: the I/O context 1309 * @buffer: where to drop data 1310 * @len: number of bytes to write 1311 * 1312 * Write @len bytes from @buffer to the compressed I/O channel. 1313 * 1314 * Returns the number of bytes written 1315 */ 1316 static int 1317 xmlGzfileWrite (void * context, const char * buffer, int len) { 1318 int ret; 1319 1320 ret = gzwrite((gzFile) context, (char *) &buffer[0], len); 1321 if (ret < 0) xmlIOErr(0, "gzwrite()"); 1322 return(ret); 1323 } 1324 #endif /* LIBXML_OUTPUT_ENABLED */ 1325 1326 /** 1327 * xmlGzfileClose: 1328 * @context: the I/O context 1329 * 1330 * Close a compressed I/O channel 1331 */ 1332 static int 1333 xmlGzfileClose (void * context) { 1334 int ret; 1335 1336 ret = (gzclose((gzFile) context) == Z_OK ) ? 0 : -1; 1337 if (ret < 0) xmlIOErr(0, "gzclose()"); 1338 return(ret); 1339 } 1340 #endif /* HAVE_ZLIB_H */ 1341 1342 #ifdef LIBXML_LZMA_ENABLED 1343 /************************************************************************ 1344 * * 1345 * I/O for compressed file accesses * 1346 * * 1347 ************************************************************************/ 1348 #include "xzlib.h" 1349 /** 1350 * xmlXzfileMatch: 1351 * @filename: the URI for matching 1352 * 1353 * input from compressed file test 1354 * 1355 * Returns 1 if matches, 0 otherwise 1356 */ 1357 static int 1358 xmlXzfileMatch (const char *filename ATTRIBUTE_UNUSED) { 1359 return(1); 1360 } 1361 1362 /** 1363 * xmlXzFileOpen_real: 1364 * @filename: the URI for matching 1365 * 1366 * input from compressed file open 1367 * if @filename is " " then the standard input is used 1368 * 1369 * Returns an I/O context or NULL in case of error 1370 */ 1371 static void * 1372 xmlXzfileOpen_real (const char *filename) { 1373 const char *path = NULL; 1374 xzFile fd; 1375 1376 if (!strcmp(filename, "-")) { 1377 fd = __libxml2_xzdopen(dup(fileno(stdin)), "rb"); 1378 return((void *) fd); 1379 } 1380 1381 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17)) { 1382 path = &filename[16]; 1383 } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) { 1384 path = &filename[7]; 1385 } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:/", 6)) { 1386 /* lots of generators seems to lazy to read RFC 1738 */ 1387 path = &filename[5]; 1388 } else 1389 path = filename; 1390 1391 if (path == NULL) 1392 return(NULL); 1393 if (!xmlCheckFilename(path)) 1394 return(NULL); 1395 1396 fd = __libxml2_xzopen(path, "rb"); 1397 return((void *) fd); 1398 } 1399 1400 /** 1401 * xmlXzfileOpen: 1402 * @filename: the URI for matching 1403 * 1404 * Wrapper around xmlXzfileOpen_real that try it with an unescaped 1405 * version of @filename, if this fails fallback to @filename 1406 * 1407 * Returns a handler or NULL in case or failure 1408 */ 1409 static void * 1410 xmlXzfileOpen (const char *filename) { 1411 char *unescaped; 1412 void *retval; 1413 1414 retval = xmlXzfileOpen_real(filename); 1415 if (retval == NULL) { 1416 unescaped = xmlURIUnescapeString(filename, 0, NULL); 1417 if (unescaped != NULL) { 1418 retval = xmlXzfileOpen_real(unescaped); 1419 } 1420 xmlFree(unescaped); 1421 } 1422 1423 return retval; 1424 } 1425 1426 /** 1427 * xmlXzfileRead: 1428 * @context: the I/O context 1429 * @buffer: where to drop data 1430 * @len: number of bytes to write 1431 * 1432 * Read @len bytes to @buffer from the compressed I/O channel. 1433 * 1434 * Returns the number of bytes written 1435 */ 1436 static int 1437 xmlXzfileRead (void * context, char * buffer, int len) { 1438 int ret; 1439 1440 ret = __libxml2_xzread((xzFile) context, &buffer[0], len); 1441 if (ret < 0) xmlIOErr(0, "xzread()"); 1442 return(ret); 1443 } 1444 1445 /** 1446 * xmlXzfileClose: 1447 * @context: the I/O context 1448 * 1449 * Close a compressed I/O channel 1450 */ 1451 static int 1452 xmlXzfileClose (void * context) { 1453 int ret; 1454 1455 ret = (__libxml2_xzclose((xzFile) context) == LZMA_OK ) ? 0 : -1; 1456 if (ret < 0) xmlIOErr(0, "xzclose()"); 1457 return(ret); 1458 } 1459 #endif /* LIBXML_LZMA_ENABLED */ 1460 1461 #ifdef LIBXML_HTTP_ENABLED 1462 /************************************************************************ 1463 * * 1464 * I/O for HTTP file accesses * 1465 * * 1466 ************************************************************************/ 1467 1468 #ifdef LIBXML_OUTPUT_ENABLED 1469 typedef struct xmlIOHTTPWriteCtxt_ 1470 { 1471 int compression; 1472 1473 char * uri; 1474 1475 void * doc_buff; 1476 1477 } xmlIOHTTPWriteCtxt, *xmlIOHTTPWriteCtxtPtr; 1478 1479 #ifdef HAVE_ZLIB_H 1480 1481 #define DFLT_WBITS ( -15 ) 1482 #define DFLT_MEM_LVL ( 8 ) 1483 #define GZ_MAGIC1 ( 0x1f ) 1484 #define GZ_MAGIC2 ( 0x8b ) 1485 #define LXML_ZLIB_OS_CODE ( 0x03 ) 1486 #define INIT_HTTP_BUFF_SIZE ( 32768 ) 1487 #define DFLT_ZLIB_RATIO ( 5 ) 1488 1489 /* 1490 ** Data structure and functions to work with sending compressed data 1491 ** via HTTP. 1492 */ 1493 1494 typedef struct xmlZMemBuff_ 1495 { 1496 unsigned long size; 1497 unsigned long crc; 1498 1499 unsigned char * zbuff; 1500 z_stream zctrl; 1501 1502 } xmlZMemBuff, *xmlZMemBuffPtr; 1503 1504 /** 1505 * append_reverse_ulong 1506 * @buff: Compressed memory buffer 1507 * @data: Unsigned long to append 1508 * 1509 * Append a unsigned long in reverse byte order to the end of the 1510 * memory buffer. 1511 */ 1512 static void 1513 append_reverse_ulong( xmlZMemBuff * buff, unsigned long data ) { 1514 1515 int idx; 1516 1517 if ( buff == NULL ) 1518 return; 1519 1520 /* 1521 ** This is plagiarized from putLong in gzio.c (zlib source) where 1522 ** the number "4" is hardcoded. If zlib is ever patched to 1523 ** support 64 bit file sizes, this code would need to be patched 1524 ** as well. 1525 */ 1526 1527 for ( idx = 0; idx < 4; idx++ ) { 1528 *buff->zctrl.next_out = ( data & 0xff ); 1529 data >>= 8; 1530 buff->zctrl.next_out++; 1531 } 1532 1533 return; 1534 } 1535 1536 /** 1537 * 1538 * xmlFreeZMemBuff 1539 * @buff: The memory buffer context to clear 1540 * 1541 * Release all the resources associated with the compressed memory buffer. 1542 */ 1543 static void 1544 xmlFreeZMemBuff( xmlZMemBuffPtr buff ) { 1545 1546 #ifdef DEBUG_HTTP 1547 int z_err; 1548 #endif 1549 1550 if ( buff == NULL ) 1551 return; 1552 1553 xmlFree( buff->zbuff ); 1554 #ifdef DEBUG_HTTP 1555 z_err = deflateEnd( &buff->zctrl ); 1556 if ( z_err != Z_OK ) 1557 xmlGenericError( xmlGenericErrorContext, 1558 "xmlFreeZMemBuff: Error releasing zlib context: %d\n", 1559 z_err ); 1560 #else 1561 deflateEnd( &buff->zctrl ); 1562 #endif 1563 1564 xmlFree( buff ); 1565 return; 1566 } 1567 1568 /** 1569 * xmlCreateZMemBuff 1570 *@compression: Compression value to use 1571 * 1572 * Create a memory buffer to hold the compressed XML document. The 1573 * compressed document in memory will end up being identical to what 1574 * would be created if gzopen/gzwrite/gzclose were being used to 1575 * write the document to disk. The code for the header/trailer data to 1576 * the compression is plagiarized from the zlib source files. 1577 */ 1578 static void * 1579 xmlCreateZMemBuff( int compression ) { 1580 1581 int z_err; 1582 int hdr_lgth; 1583 xmlZMemBuffPtr buff = NULL; 1584 1585 if ( ( compression < 1 ) || ( compression > 9 ) ) 1586 return ( NULL ); 1587 1588 /* Create the control and data areas */ 1589 1590 buff = xmlMalloc( sizeof( xmlZMemBuff ) ); 1591 if ( buff == NULL ) { 1592 xmlIOErrMemory("creating buffer context"); 1593 return ( NULL ); 1594 } 1595 1596 (void)memset( buff, 0, sizeof( xmlZMemBuff ) ); 1597 buff->size = INIT_HTTP_BUFF_SIZE; 1598 buff->zbuff = xmlMalloc( buff->size ); 1599 if ( buff->zbuff == NULL ) { 1600 xmlFreeZMemBuff( buff ); 1601 xmlIOErrMemory("creating buffer"); 1602 return ( NULL ); 1603 } 1604 1605 z_err = deflateInit2( &buff->zctrl, compression, Z_DEFLATED, 1606 DFLT_WBITS, DFLT_MEM_LVL, Z_DEFAULT_STRATEGY ); 1607 if ( z_err != Z_OK ) { 1608 xmlChar msg[500]; 1609 xmlFreeZMemBuff( buff ); 1610 buff = NULL; 1611 xmlStrPrintf(msg, 500, 1612 "xmlCreateZMemBuff: %s %d\n", 1613 "Error initializing compression context. ZLIB error:", 1614 z_err ); 1615 xmlIOErr(XML_IO_WRITE, (const char *) msg); 1616 return ( NULL ); 1617 } 1618 1619 /* Set the header data. The CRC will be needed for the trailer */ 1620 buff->crc = crc32( 0L, NULL, 0 ); 1621 hdr_lgth = snprintf( (char *)buff->zbuff, buff->size, 1622 "%c%c%c%c%c%c%c%c%c%c", 1623 GZ_MAGIC1, GZ_MAGIC2, Z_DEFLATED, 1624 0, 0, 0, 0, 0, 0, LXML_ZLIB_OS_CODE ); 1625 buff->zctrl.next_out = buff->zbuff + hdr_lgth; 1626 buff->zctrl.avail_out = buff->size - hdr_lgth; 1627 1628 return ( buff ); 1629 } 1630 1631 /** 1632 * xmlZMemBuffExtend 1633 * @buff: Buffer used to compress and consolidate data. 1634 * @ext_amt: Number of bytes to extend the buffer. 1635 * 1636 * Extend the internal buffer used to store the compressed data by the 1637 * specified amount. 1638 * 1639 * Returns 0 on success or -1 on failure to extend the buffer. On failure 1640 * the original buffer still exists at the original size. 1641 */ 1642 static int 1643 xmlZMemBuffExtend( xmlZMemBuffPtr buff, size_t ext_amt ) { 1644 1645 int rc = -1; 1646 size_t new_size; 1647 size_t cur_used; 1648 1649 unsigned char * tmp_ptr = NULL; 1650 1651 if ( buff == NULL ) 1652 return ( -1 ); 1653 1654 else if ( ext_amt == 0 ) 1655 return ( 0 ); 1656 1657 cur_used = buff->zctrl.next_out - buff->zbuff; 1658 new_size = buff->size + ext_amt; 1659 1660 #ifdef DEBUG_HTTP 1661 if ( cur_used > new_size ) 1662 xmlGenericError( xmlGenericErrorContext, 1663 "xmlZMemBuffExtend: %s\n%s %d bytes.\n", 1664 "Buffer overwrite detected during compressed memory", 1665 "buffer extension. Overflowed by", 1666 (cur_used - new_size ) ); 1667 #endif 1668 1669 tmp_ptr = xmlRealloc( buff->zbuff, new_size ); 1670 if ( tmp_ptr != NULL ) { 1671 rc = 0; 1672 buff->size = new_size; 1673 buff->zbuff = tmp_ptr; 1674 buff->zctrl.next_out = tmp_ptr + cur_used; 1675 buff->zctrl.avail_out = new_size - cur_used; 1676 } 1677 else { 1678 xmlChar msg[500]; 1679 xmlStrPrintf(msg, 500, 1680 "xmlZMemBuffExtend: %s %lu bytes.\n", 1681 "Allocation failure extending output buffer to", 1682 (unsigned long) new_size ); 1683 xmlIOErr(XML_IO_WRITE, (const char *) msg); 1684 } 1685 1686 return ( rc ); 1687 } 1688 1689 /** 1690 * xmlZMemBuffAppend 1691 * @buff: Buffer used to compress and consolidate data 1692 * @src: Uncompressed source content to append to buffer 1693 * @len: Length of source data to append to buffer 1694 * 1695 * Compress and append data to the internal buffer. The data buffer 1696 * will be expanded if needed to store the additional data. 1697 * 1698 * Returns the number of bytes appended to the buffer or -1 on error. 1699 */ 1700 static int 1701 xmlZMemBuffAppend( xmlZMemBuffPtr buff, const char * src, int len ) { 1702 1703 int z_err; 1704 size_t min_accept; 1705 1706 if ( ( buff == NULL ) || ( src == NULL ) ) 1707 return ( -1 ); 1708 1709 buff->zctrl.avail_in = len; 1710 buff->zctrl.next_in = (unsigned char *)src; 1711 while ( buff->zctrl.avail_in > 0 ) { 1712 /* 1713 ** Extend the buffer prior to deflate call if a reasonable amount 1714 ** of output buffer space is not available. 1715 */ 1716 min_accept = buff->zctrl.avail_in / DFLT_ZLIB_RATIO; 1717 if ( buff->zctrl.avail_out <= min_accept ) { 1718 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 ) 1719 return ( -1 ); 1720 } 1721 1722 z_err = deflate( &buff->zctrl, Z_NO_FLUSH ); 1723 if ( z_err != Z_OK ) { 1724 xmlChar msg[500]; 1725 xmlStrPrintf(msg, 500, 1726 "xmlZMemBuffAppend: %s %d %s - %d", 1727 "Compression error while appending", 1728 len, "bytes to buffer. ZLIB error", z_err ); 1729 xmlIOErr(XML_IO_WRITE, (const char *) msg); 1730 return ( -1 ); 1731 } 1732 } 1733 1734 buff->crc = crc32( buff->crc, (unsigned char *)src, len ); 1735 1736 return ( len ); 1737 } 1738 1739 /** 1740 * xmlZMemBuffGetContent 1741 * @buff: Compressed memory content buffer 1742 * @data_ref: Pointer reference to point to compressed content 1743 * 1744 * Flushes the compression buffers, appends gzip file trailers and 1745 * returns the compressed content and length of the compressed data. 1746 * NOTE: The gzip trailer code here is plagiarized from zlib source. 1747 * 1748 * Returns the length of the compressed data or -1 on error. 1749 */ 1750 static int 1751 xmlZMemBuffGetContent( xmlZMemBuffPtr buff, char ** data_ref ) { 1752 1753 int zlgth = -1; 1754 int z_err; 1755 1756 if ( ( buff == NULL ) || ( data_ref == NULL ) ) 1757 return ( -1 ); 1758 1759 /* Need to loop until compression output buffers are flushed */ 1760 1761 do 1762 { 1763 z_err = deflate( &buff->zctrl, Z_FINISH ); 1764 if ( z_err == Z_OK ) { 1765 /* In this case Z_OK means more buffer space needed */ 1766 1767 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 ) 1768 return ( -1 ); 1769 } 1770 } 1771 while ( z_err == Z_OK ); 1772 1773 /* If the compression state is not Z_STREAM_END, some error occurred */ 1774 1775 if ( z_err == Z_STREAM_END ) { 1776 1777 /* Need to append the gzip data trailer */ 1778 1779 if ( buff->zctrl.avail_out < ( 2 * sizeof( unsigned long ) ) ) { 1780 if ( xmlZMemBuffExtend(buff, (2 * sizeof(unsigned long))) == -1 ) 1781 return ( -1 ); 1782 } 1783 1784 /* 1785 ** For whatever reason, the CRC and length data are pushed out 1786 ** in reverse byte order. So a memcpy can't be used here. 1787 */ 1788 1789 append_reverse_ulong( buff, buff->crc ); 1790 append_reverse_ulong( buff, buff->zctrl.total_in ); 1791 1792 zlgth = buff->zctrl.next_out - buff->zbuff; 1793 *data_ref = (char *)buff->zbuff; 1794 } 1795 1796 else { 1797 xmlChar msg[500]; 1798 xmlStrPrintf(msg, 500, 1799 "xmlZMemBuffGetContent: %s - %d\n", 1800 "Error flushing zlib buffers. Error code", z_err ); 1801 xmlIOErr(XML_IO_WRITE, (const char *) msg); 1802 } 1803 1804 return ( zlgth ); 1805 } 1806 #endif /* LIBXML_OUTPUT_ENABLED */ 1807 #endif /* HAVE_ZLIB_H */ 1808 1809 #ifdef LIBXML_OUTPUT_ENABLED 1810 /** 1811 * xmlFreeHTTPWriteCtxt 1812 * @ctxt: Context to cleanup 1813 * 1814 * Free allocated memory and reclaim system resources. 1815 * 1816 * No return value. 1817 */ 1818 static void 1819 xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt ) 1820 { 1821 if ( ctxt->uri != NULL ) 1822 xmlFree( ctxt->uri ); 1823 1824 if ( ctxt->doc_buff != NULL ) { 1825 1826 #ifdef HAVE_ZLIB_H 1827 if ( ctxt->compression > 0 ) { 1828 xmlFreeZMemBuff( ctxt->doc_buff ); 1829 } 1830 else 1831 #endif 1832 { 1833 xmlOutputBufferClose( ctxt->doc_buff ); 1834 } 1835 } 1836 1837 xmlFree( ctxt ); 1838 return; 1839 } 1840 #endif /* LIBXML_OUTPUT_ENABLED */ 1841 1842 1843 /** 1844 * xmlIOHTTPMatch: 1845 * @filename: the URI for matching 1846 * 1847 * check if the URI matches an HTTP one 1848 * 1849 * Returns 1 if matches, 0 otherwise 1850 */ 1851 int 1852 xmlIOHTTPMatch (const char *filename) { 1853 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "http://", 7)) 1854 return(1); 1855 return(0); 1856 } 1857 1858 /** 1859 * xmlIOHTTPOpen: 1860 * @filename: the URI for matching 1861 * 1862 * open an HTTP I/O channel 1863 * 1864 * Returns an I/O context or NULL in case of error 1865 */ 1866 void * 1867 xmlIOHTTPOpen (const char *filename) { 1868 return(xmlNanoHTTPOpen(filename, NULL)); 1869 } 1870 1871 #ifdef LIBXML_OUTPUT_ENABLED 1872 /** 1873 * xmlIOHTTPOpenW: 1874 * @post_uri: The destination URI for the document 1875 * @compression: The compression desired for the document. 1876 * 1877 * Open a temporary buffer to collect the document for a subsequent HTTP POST 1878 * request. Non-static as is called from the output buffer creation routine. 1879 * 1880 * Returns an I/O context or NULL in case of error. 1881 */ 1882 1883 void * 1884 xmlIOHTTPOpenW(const char *post_uri, int compression ATTRIBUTE_UNUSED) 1885 { 1886 1887 xmlIOHTTPWriteCtxtPtr ctxt = NULL; 1888 1889 if (post_uri == NULL) 1890 return (NULL); 1891 1892 ctxt = xmlMalloc(sizeof(xmlIOHTTPWriteCtxt)); 1893 if (ctxt == NULL) { 1894 xmlIOErrMemory("creating HTTP output context"); 1895 return (NULL); 1896 } 1897 1898 (void) memset(ctxt, 0, sizeof(xmlIOHTTPWriteCtxt)); 1899 1900 ctxt->uri = (char *) xmlStrdup((const xmlChar *)post_uri); 1901 if (ctxt->uri == NULL) { 1902 xmlIOErrMemory("copying URI"); 1903 xmlFreeHTTPWriteCtxt(ctxt); 1904 return (NULL); 1905 } 1906 1907 /* 1908 * ** Since the document length is required for an HTTP post, 1909 * ** need to put the document into a buffer. A memory buffer 1910 * ** is being used to avoid pushing the data to disk and back. 1911 */ 1912 1913 #ifdef HAVE_ZLIB_H 1914 if ((compression > 0) && (compression <= 9)) { 1915 1916 ctxt->compression = compression; 1917 ctxt->doc_buff = xmlCreateZMemBuff(compression); 1918 } else 1919 #endif 1920 { 1921 /* Any character conversions should have been done before this */ 1922 1923 ctxt->doc_buff = xmlAllocOutputBufferInternal(NULL); 1924 } 1925 1926 if (ctxt->doc_buff == NULL) { 1927 xmlFreeHTTPWriteCtxt(ctxt); 1928 ctxt = NULL; 1929 } 1930 1931 return (ctxt); 1932 } 1933 #endif /* LIBXML_OUTPUT_ENABLED */ 1934 1935 #ifdef LIBXML_OUTPUT_ENABLED 1936 /** 1937 * xmlIOHTTPDfltOpenW 1938 * @post_uri: The destination URI for this document. 1939 * 1940 * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent 1941 * HTTP post command. This function should generally not be used as 1942 * the open callback is short circuited in xmlOutputBufferCreateFile. 1943 * 1944 * Returns a pointer to the new IO context. 1945 */ 1946 static void * 1947 xmlIOHTTPDfltOpenW( const char * post_uri ) { 1948 return ( xmlIOHTTPOpenW( post_uri, 0 ) ); 1949 } 1950 #endif /* LIBXML_OUTPUT_ENABLED */ 1951 1952 /** 1953 * xmlIOHTTPRead: 1954 * @context: the I/O context 1955 * @buffer: where to drop data 1956 * @len: number of bytes to write 1957 * 1958 * Read @len bytes to @buffer from the I/O channel. 1959 * 1960 * Returns the number of bytes written 1961 */ 1962 int 1963 xmlIOHTTPRead(void * context, char * buffer, int len) { 1964 if ((buffer == NULL) || (len < 0)) return(-1); 1965 return(xmlNanoHTTPRead(context, &buffer[0], len)); 1966 } 1967 1968 #ifdef LIBXML_OUTPUT_ENABLED 1969 /** 1970 * xmlIOHTTPWrite 1971 * @context: previously opened writing context 1972 * @buffer: data to output to temporary buffer 1973 * @len: bytes to output 1974 * 1975 * Collect data from memory buffer into a temporary file for later 1976 * processing. 1977 * 1978 * Returns number of bytes written. 1979 */ 1980 1981 static int 1982 xmlIOHTTPWrite( void * context, const char * buffer, int len ) { 1983 1984 xmlIOHTTPWriteCtxtPtr ctxt = context; 1985 1986 if ( ( ctxt == NULL ) || ( ctxt->doc_buff == NULL ) || ( buffer == NULL ) ) 1987 return ( -1 ); 1988 1989 if ( len > 0 ) { 1990 1991 /* Use gzwrite or fwrite as previously setup in the open call */ 1992 1993 #ifdef HAVE_ZLIB_H 1994 if ( ctxt->compression > 0 ) 1995 len = xmlZMemBuffAppend( ctxt->doc_buff, buffer, len ); 1996 1997 else 1998 #endif 1999 len = xmlOutputBufferWrite( ctxt->doc_buff, len, buffer ); 2000 2001 if ( len < 0 ) { 2002 xmlChar msg[500]; 2003 xmlStrPrintf(msg, 500, 2004 "xmlIOHTTPWrite: %s\n%s '%s'.\n", 2005 "Error appending to internal buffer.", 2006 "Error sending document to URI", 2007 ctxt->uri ); 2008 xmlIOErr(XML_IO_WRITE, (const char *) msg); 2009 } 2010 } 2011 2012 return ( len ); 2013 } 2014 #endif /* LIBXML_OUTPUT_ENABLED */ 2015 2016 2017 /** 2018 * xmlIOHTTPClose: 2019 * @context: the I/O context 2020 * 2021 * Close an HTTP I/O channel 2022 * 2023 * Returns 0 2024 */ 2025 int 2026 xmlIOHTTPClose (void * context) { 2027 xmlNanoHTTPClose(context); 2028 return 0; 2029 } 2030 2031 #ifdef LIBXML_OUTPUT_ENABLED 2032 /** 2033 * xmlIOHTTCloseWrite 2034 * @context: The I/O context 2035 * @http_mthd: The HTTP method to be used when sending the data 2036 * 2037 * Close the transmit HTTP I/O channel and actually send the data. 2038 */ 2039 static int 2040 xmlIOHTTPCloseWrite( void * context, const char * http_mthd ) { 2041 2042 int close_rc = -1; 2043 int http_rtn = 0; 2044 int content_lgth = 0; 2045 xmlIOHTTPWriteCtxtPtr ctxt = context; 2046 2047 char * http_content = NULL; 2048 char * content_encoding = NULL; 2049 char * content_type = (char *) "text/xml"; 2050 void * http_ctxt = NULL; 2051 2052 if ( ( ctxt == NULL ) || ( http_mthd == NULL ) ) 2053 return ( -1 ); 2054 2055 /* Retrieve the content from the appropriate buffer */ 2056 2057 #ifdef HAVE_ZLIB_H 2058 2059 if ( ctxt->compression > 0 ) { 2060 content_lgth = xmlZMemBuffGetContent( ctxt->doc_buff, &http_content ); 2061 content_encoding = (char *) "Content-Encoding: gzip"; 2062 } 2063 else 2064 #endif 2065 { 2066 /* Pull the data out of the memory output buffer */ 2067 2068 xmlOutputBufferPtr dctxt = ctxt->doc_buff; 2069 http_content = (char *) xmlBufContent(dctxt->buffer); 2070 content_lgth = xmlBufUse(dctxt->buffer); 2071 } 2072 2073 if ( http_content == NULL ) { 2074 xmlChar msg[500]; 2075 xmlStrPrintf(msg, 500, 2076 "xmlIOHTTPCloseWrite: %s '%s' %s '%s'.\n", 2077 "Error retrieving content.\nUnable to", 2078 http_mthd, "data to URI", ctxt->uri ); 2079 xmlIOErr(XML_IO_WRITE, (const char *) msg); 2080 } 2081 2082 else { 2083 2084 http_ctxt = xmlNanoHTTPMethod( ctxt->uri, http_mthd, http_content, 2085 &content_type, content_encoding, 2086 content_lgth ); 2087 2088 if ( http_ctxt != NULL ) { 2089 #ifdef DEBUG_HTTP 2090 /* If testing/debugging - dump reply with request content */ 2091 2092 FILE * tst_file = NULL; 2093 char buffer[ 4096 ]; 2094 char * dump_name = NULL; 2095 int avail; 2096 2097 xmlGenericError( xmlGenericErrorContext, 2098 "xmlNanoHTTPCloseWrite: HTTP %s to\n%s returned %d.\n", 2099 http_mthd, ctxt->uri, 2100 xmlNanoHTTPReturnCode( http_ctxt ) ); 2101 2102 /* 2103 ** Since either content or reply may be gzipped, 2104 ** dump them to separate files instead of the 2105 ** standard error context. 2106 */ 2107 2108 dump_name = tempnam( NULL, "lxml" ); 2109 if ( dump_name != NULL ) { 2110 (void)snprintf( buffer, sizeof(buffer), "%s.content", dump_name ); 2111 2112 tst_file = fopen( buffer, "wb" ); 2113 if ( tst_file != NULL ) { 2114 xmlGenericError( xmlGenericErrorContext, 2115 "Transmitted content saved in file: %s\n", buffer ); 2116 2117 fwrite( http_content, sizeof( char ), 2118 content_lgth, tst_file ); 2119 fclose( tst_file ); 2120 } 2121 2122 (void)snprintf( buffer, sizeof(buffer), "%s.reply", dump_name ); 2123 tst_file = fopen( buffer, "wb" ); 2124 if ( tst_file != NULL ) { 2125 xmlGenericError( xmlGenericErrorContext, 2126 "Reply content saved in file: %s\n", buffer ); 2127 2128 2129 while ( (avail = xmlNanoHTTPRead( http_ctxt, 2130 buffer, sizeof( buffer ) )) > 0 ) { 2131 2132 fwrite( buffer, sizeof( char ), avail, tst_file ); 2133 } 2134 2135 fclose( tst_file ); 2136 } 2137 2138 free( dump_name ); 2139 } 2140 #endif /* DEBUG_HTTP */ 2141 2142 http_rtn = xmlNanoHTTPReturnCode( http_ctxt ); 2143 if ( ( http_rtn >= 200 ) && ( http_rtn < 300 ) ) 2144 close_rc = 0; 2145 else { 2146 xmlChar msg[500]; 2147 xmlStrPrintf(msg, 500, 2148 "xmlIOHTTPCloseWrite: HTTP '%s' of %d %s\n'%s' %s %d\n", 2149 http_mthd, content_lgth, 2150 "bytes to URI", ctxt->uri, 2151 "failed. HTTP return code:", http_rtn ); 2152 xmlIOErr(XML_IO_WRITE, (const char *) msg); 2153 } 2154 2155 xmlNanoHTTPClose( http_ctxt ); 2156 xmlFree( content_type ); 2157 } 2158 } 2159 2160 /* Final cleanups */ 2161 2162 xmlFreeHTTPWriteCtxt( ctxt ); 2163 2164 return ( close_rc ); 2165 } 2166 2167 /** 2168 * xmlIOHTTPClosePut 2169 * 2170 * @context: The I/O context 2171 * 2172 * Close the transmit HTTP I/O channel and actually send data using a PUT 2173 * HTTP method. 2174 */ 2175 static int 2176 xmlIOHTTPClosePut( void * ctxt ) { 2177 return ( xmlIOHTTPCloseWrite( ctxt, "PUT" ) ); 2178 } 2179 2180 2181 /** 2182 * xmlIOHTTPClosePost 2183 * 2184 * @context: The I/O context 2185 * 2186 * Close the transmit HTTP I/O channel and actually send data using a POST 2187 * HTTP method. 2188 */ 2189 static int 2190 xmlIOHTTPClosePost( void * ctxt ) { 2191 return ( xmlIOHTTPCloseWrite( ctxt, "POST" ) ); 2192 } 2193 #endif /* LIBXML_OUTPUT_ENABLED */ 2194 2195 #endif /* LIBXML_HTTP_ENABLED */ 2196 2197 #ifdef LIBXML_FTP_ENABLED 2198 /************************************************************************ 2199 * * 2200 * I/O for FTP file accesses * 2201 * * 2202 ************************************************************************/ 2203 /** 2204 * xmlIOFTPMatch: 2205 * @filename: the URI for matching 2206 * 2207 * check if the URI matches an FTP one 2208 * 2209 * Returns 1 if matches, 0 otherwise 2210 */ 2211 int 2212 xmlIOFTPMatch (const char *filename) { 2213 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "ftp://", 6)) 2214 return(1); 2215 return(0); 2216 } 2217 2218 /** 2219 * xmlIOFTPOpen: 2220 * @filename: the URI for matching 2221 * 2222 * open an FTP I/O channel 2223 * 2224 * Returns an I/O context or NULL in case of error 2225 */ 2226 void * 2227 xmlIOFTPOpen (const char *filename) { 2228 return(xmlNanoFTPOpen(filename)); 2229 } 2230 2231 /** 2232 * xmlIOFTPRead: 2233 * @context: the I/O context 2234 * @buffer: where to drop data 2235 * @len: number of bytes to write 2236 * 2237 * Read @len bytes to @buffer from the I/O channel. 2238 * 2239 * Returns the number of bytes written 2240 */ 2241 int 2242 xmlIOFTPRead(void * context, char * buffer, int len) { 2243 if ((buffer == NULL) || (len < 0)) return(-1); 2244 return(xmlNanoFTPRead(context, &buffer[0], len)); 2245 } 2246 2247 /** 2248 * xmlIOFTPClose: 2249 * @context: the I/O context 2250 * 2251 * Close an FTP I/O channel 2252 * 2253 * Returns 0 2254 */ 2255 int 2256 xmlIOFTPClose (void * context) { 2257 return ( xmlNanoFTPClose(context) ); 2258 } 2259 #endif /* LIBXML_FTP_ENABLED */ 2260 2261 2262 /** 2263 * xmlRegisterInputCallbacks: 2264 * @matchFunc: the xmlInputMatchCallback 2265 * @openFunc: the xmlInputOpenCallback 2266 * @readFunc: the xmlInputReadCallback 2267 * @closeFunc: the xmlInputCloseCallback 2268 * 2269 * Register a new set of I/O callback for handling parser input. 2270 * 2271 * Returns the registered handler number or -1 in case of error 2272 */ 2273 int 2274 xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc, 2275 xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc, 2276 xmlInputCloseCallback closeFunc) { 2277 if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) { 2278 return(-1); 2279 } 2280 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc; 2281 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc; 2282 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc; 2283 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc; 2284 xmlInputCallbackInitialized = 1; 2285 return(xmlInputCallbackNr++); 2286 } 2287 2288 #ifdef LIBXML_OUTPUT_ENABLED 2289 /** 2290 * xmlRegisterOutputCallbacks: 2291 * @matchFunc: the xmlOutputMatchCallback 2292 * @openFunc: the xmlOutputOpenCallback 2293 * @writeFunc: the xmlOutputWriteCallback 2294 * @closeFunc: the xmlOutputCloseCallback 2295 * 2296 * Register a new set of I/O callback for handling output. 2297 * 2298 * Returns the registered handler number or -1 in case of error 2299 */ 2300 int 2301 xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc, 2302 xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc, 2303 xmlOutputCloseCallback closeFunc) { 2304 if (xmlOutputCallbackNr >= MAX_OUTPUT_CALLBACK) { 2305 return(-1); 2306 } 2307 xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc; 2308 xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc; 2309 xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc; 2310 xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc; 2311 xmlOutputCallbackInitialized = 1; 2312 return(xmlOutputCallbackNr++); 2313 } 2314 #endif /* LIBXML_OUTPUT_ENABLED */ 2315 2316 /** 2317 * xmlRegisterDefaultInputCallbacks: 2318 * 2319 * Registers the default compiled-in I/O handlers. 2320 */ 2321 void 2322 xmlRegisterDefaultInputCallbacks(void) { 2323 if (xmlInputCallbackInitialized) 2324 return; 2325 2326 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__) 2327 xmlInitPlatformSpecificIo(); 2328 #endif 2329 2330 xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen, 2331 xmlFileRead, xmlFileClose); 2332 #ifdef HAVE_ZLIB_H 2333 xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen, 2334 xmlGzfileRead, xmlGzfileClose); 2335 #endif /* HAVE_ZLIB_H */ 2336 #ifdef LIBXML_LZMA_ENABLED 2337 xmlRegisterInputCallbacks(xmlXzfileMatch, xmlXzfileOpen, 2338 xmlXzfileRead, xmlXzfileClose); 2339 #endif /* LIBXML_LZMA_ENABLED */ 2340 2341 #ifdef LIBXML_HTTP_ENABLED 2342 xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen, 2343 xmlIOHTTPRead, xmlIOHTTPClose); 2344 #endif /* LIBXML_HTTP_ENABLED */ 2345 2346 #ifdef LIBXML_FTP_ENABLED 2347 xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen, 2348 xmlIOFTPRead, xmlIOFTPClose); 2349 #endif /* LIBXML_FTP_ENABLED */ 2350 xmlInputCallbackInitialized = 1; 2351 } 2352 2353 #ifdef LIBXML_OUTPUT_ENABLED 2354 /** 2355 * xmlRegisterDefaultOutputCallbacks: 2356 * 2357 * Registers the default compiled-in I/O handlers. 2358 */ 2359 void 2360 xmlRegisterDefaultOutputCallbacks (void) { 2361 if (xmlOutputCallbackInitialized) 2362 return; 2363 2364 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__) 2365 xmlInitPlatformSpecificIo(); 2366 #endif 2367 2368 xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW, 2369 xmlFileWrite, xmlFileClose); 2370 2371 #ifdef LIBXML_HTTP_ENABLED 2372 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW, 2373 xmlIOHTTPWrite, xmlIOHTTPClosePut); 2374 #endif 2375 2376 /********************************* 2377 No way a-priori to distinguish between gzipped files from 2378 uncompressed ones except opening if existing then closing 2379 and saving with same compression ratio ... a pain. 2380 2381 #ifdef HAVE_ZLIB_H 2382 xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen, 2383 xmlGzfileWrite, xmlGzfileClose); 2384 #endif 2385 2386 Nor FTP PUT .... 2387 #ifdef LIBXML_FTP_ENABLED 2388 xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen, 2389 xmlIOFTPWrite, xmlIOFTPClose); 2390 #endif 2391 **********************************/ 2392 xmlOutputCallbackInitialized = 1; 2393 } 2394 2395 #ifdef LIBXML_HTTP_ENABLED 2396 /** 2397 * xmlRegisterHTTPPostCallbacks: 2398 * 2399 * By default, libxml submits HTTP output requests using the "PUT" method. 2400 * Calling this method changes the HTTP output method to use the "POST" 2401 * method instead. 2402 * 2403 */ 2404 void 2405 xmlRegisterHTTPPostCallbacks( void ) { 2406 2407 /* Register defaults if not done previously */ 2408 2409 if ( xmlOutputCallbackInitialized == 0 ) 2410 xmlRegisterDefaultOutputCallbacks( ); 2411 2412 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW, 2413 xmlIOHTTPWrite, xmlIOHTTPClosePost); 2414 return; 2415 } 2416 #endif 2417 #endif /* LIBXML_OUTPUT_ENABLED */ 2418 2419 /** 2420 * xmlAllocParserInputBuffer: 2421 * @enc: the charset encoding if known 2422 * 2423 * Create a buffered parser input for progressive parsing 2424 * 2425 * Returns the new parser input or NULL 2426 */ 2427 xmlParserInputBufferPtr 2428 xmlAllocParserInputBuffer(xmlCharEncoding enc) { 2429 xmlParserInputBufferPtr ret; 2430 2431 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer)); 2432 if (ret == NULL) { 2433 xmlIOErrMemory("creating input buffer"); 2434 return(NULL); 2435 } 2436 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer)); 2437 ret->buffer = xmlBufCreateSize(2 * xmlDefaultBufferSize); 2438 if (ret->buffer == NULL) { 2439 xmlFree(ret); 2440 return(NULL); 2441 } 2442 xmlBufSetAllocationScheme(ret->buffer, XML_BUFFER_ALLOC_DOUBLEIT); 2443 ret->encoder = xmlGetCharEncodingHandler(enc); 2444 if (ret->encoder != NULL) 2445 ret->raw = xmlBufCreateSize(2 * xmlDefaultBufferSize); 2446 else 2447 ret->raw = NULL; 2448 ret->readcallback = NULL; 2449 ret->closecallback = NULL; 2450 ret->context = NULL; 2451 ret->compressed = -1; 2452 ret->rawconsumed = 0; 2453 2454 return(ret); 2455 } 2456 2457 #ifdef LIBXML_OUTPUT_ENABLED 2458 /** 2459 * xmlAllocOutputBuffer: 2460 * @encoder: the encoding converter or NULL 2461 * 2462 * Create a buffered parser output 2463 * 2464 * Returns the new parser output or NULL 2465 */ 2466 xmlOutputBufferPtr 2467 xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) { 2468 xmlOutputBufferPtr ret; 2469 2470 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer)); 2471 if (ret == NULL) { 2472 xmlIOErrMemory("creating output buffer"); 2473 return(NULL); 2474 } 2475 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer)); 2476 ret->buffer = xmlBufCreate(); 2477 if (ret->buffer == NULL) { 2478 xmlFree(ret); 2479 return(NULL); 2480 } 2481 2482 /* try to avoid a performance problem with Windows realloc() */ 2483 if (xmlBufGetAllocationScheme(ret->buffer) == XML_BUFFER_ALLOC_EXACT) 2484 xmlBufSetAllocationScheme(ret->buffer, XML_BUFFER_ALLOC_DOUBLEIT); 2485 2486 ret->encoder = encoder; 2487 if (encoder != NULL) { 2488 ret->conv = xmlBufCreateSize(4000); 2489 if (ret->conv == NULL) { 2490 xmlFree(ret); 2491 return(NULL); 2492 } 2493 2494 /* 2495 * This call is designed to initiate the encoder state 2496 */ 2497 xmlCharEncOutput(ret, 1); 2498 } else 2499 ret->conv = NULL; 2500 ret->writecallback = NULL; 2501 ret->closecallback = NULL; 2502 ret->context = NULL; 2503 ret->written = 0; 2504 2505 return(ret); 2506 } 2507 2508 /** 2509 * xmlAllocOutputBufferInternal: 2510 * @encoder: the encoding converter or NULL 2511 * 2512 * Create a buffered parser output 2513 * 2514 * Returns the new parser output or NULL 2515 */ 2516 xmlOutputBufferPtr 2517 xmlAllocOutputBufferInternal(xmlCharEncodingHandlerPtr encoder) { 2518 xmlOutputBufferPtr ret; 2519 2520 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer)); 2521 if (ret == NULL) { 2522 xmlIOErrMemory("creating output buffer"); 2523 return(NULL); 2524 } 2525 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer)); 2526 ret->buffer = xmlBufCreate(); 2527 if (ret->buffer == NULL) { 2528 xmlFree(ret); 2529 return(NULL); 2530 } 2531 2532 2533 /* 2534 * For conversion buffers we use the special IO handling 2535 */ 2536 xmlBufSetAllocationScheme(ret->buffer, XML_BUFFER_ALLOC_IO); 2537 2538 ret->encoder = encoder; 2539 if (encoder != NULL) { 2540 ret->conv = xmlBufCreateSize(4000); 2541 if (ret->conv == NULL) { 2542 xmlFree(ret); 2543 return(NULL); 2544 } 2545 2546 /* 2547 * This call is designed to initiate the encoder state 2548 */ 2549 xmlCharEncOutput(ret, 1); 2550 } else 2551 ret->conv = NULL; 2552 ret->writecallback = NULL; 2553 ret->closecallback = NULL; 2554 ret->context = NULL; 2555 ret->written = 0; 2556 2557 return(ret); 2558 } 2559 2560 #endif /* LIBXML_OUTPUT_ENABLED */ 2561 2562 /** 2563 * xmlFreeParserInputBuffer: 2564 * @in: a buffered parser input 2565 * 2566 * Free up the memory used by a buffered parser input 2567 */ 2568 void 2569 xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) { 2570 if (in == NULL) return; 2571 2572 if (in->raw) { 2573 xmlBufFree(in->raw); 2574 in->raw = NULL; 2575 } 2576 if (in->encoder != NULL) { 2577 xmlCharEncCloseFunc(in->encoder); 2578 } 2579 if (in->closecallback != NULL) { 2580 in->closecallback(in->context); 2581 } 2582 if (in->buffer != NULL) { 2583 xmlBufFree(in->buffer); 2584 in->buffer = NULL; 2585 } 2586 2587 xmlFree(in); 2588 } 2589 2590 #ifdef LIBXML_OUTPUT_ENABLED 2591 /** 2592 * xmlOutputBufferClose: 2593 * @out: a buffered output 2594 * 2595 * flushes and close the output I/O channel 2596 * and free up all the associated resources 2597 * 2598 * Returns the number of byte written or -1 in case of error. 2599 */ 2600 int 2601 xmlOutputBufferClose(xmlOutputBufferPtr out) 2602 { 2603 int written; 2604 int err_rc = 0; 2605 2606 if (out == NULL) 2607 return (-1); 2608 if (out->writecallback != NULL) 2609 xmlOutputBufferFlush(out); 2610 if (out->closecallback != NULL) { 2611 err_rc = out->closecallback(out->context); 2612 } 2613 written = out->written; 2614 if (out->conv) { 2615 xmlBufFree(out->conv); 2616 out->conv = NULL; 2617 } 2618 if (out->encoder != NULL) { 2619 xmlCharEncCloseFunc(out->encoder); 2620 } 2621 if (out->buffer != NULL) { 2622 xmlBufFree(out->buffer); 2623 out->buffer = NULL; 2624 } 2625 2626 if (out->error) 2627 err_rc = -1; 2628 xmlFree(out); 2629 return ((err_rc == 0) ? written : err_rc); 2630 } 2631 #endif /* LIBXML_OUTPUT_ENABLED */ 2632 2633 xmlParserInputBufferPtr 2634 __xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) { 2635 xmlParserInputBufferPtr ret; 2636 int i = 0; 2637 void *context = NULL; 2638 2639 if (xmlInputCallbackInitialized == 0) 2640 xmlRegisterDefaultInputCallbacks(); 2641 2642 if (URI == NULL) return(NULL); 2643 2644 /* 2645 * Try to find one of the input accept method accepting that scheme 2646 * Go in reverse to give precedence to user defined handlers. 2647 */ 2648 if (context == NULL) { 2649 for (i = xmlInputCallbackNr - 1;i >= 0;i--) { 2650 if ((xmlInputCallbackTable[i].matchcallback != NULL) && 2651 (xmlInputCallbackTable[i].matchcallback(URI) != 0)) { 2652 context = xmlInputCallbackTable[i].opencallback(URI); 2653 if (context != NULL) { 2654 break; 2655 } 2656 } 2657 } 2658 } 2659 if (context == NULL) { 2660 return(NULL); 2661 } 2662 2663 /* 2664 * Allocate the Input buffer front-end. 2665 */ 2666 ret = xmlAllocParserInputBuffer(enc); 2667 if (ret != NULL) { 2668 ret->context = context; 2669 ret->readcallback = xmlInputCallbackTable[i].readcallback; 2670 ret->closecallback = xmlInputCallbackTable[i].closecallback; 2671 #ifdef HAVE_ZLIB_H 2672 if ((xmlInputCallbackTable[i].opencallback == xmlGzfileOpen) && 2673 (strcmp(URI, "-") != 0)) { 2674 #if defined(ZLIB_VERNUM) && ZLIB_VERNUM >= 0x1230 2675 ret->compressed = !gzdirect(context); 2676 #else 2677 if (((z_stream *)context)->avail_in > 4) { 2678 char *cptr, buff4[4]; 2679 cptr = (char *) ((z_stream *)context)->next_in; 2680 if (gzread(context, buff4, 4) == 4) { 2681 if (strncmp(buff4, cptr, 4) == 0) 2682 ret->compressed = 0; 2683 else 2684 ret->compressed = 1; 2685 gzrewind(context); 2686 } 2687 } 2688 #endif 2689 } 2690 #endif 2691 #ifdef LIBXML_LZMA_ENABLED 2692 if ((xmlInputCallbackTable[i].opencallback == xmlXzfileOpen) && 2693 (strcmp(URI, "-") != 0)) { 2694 ret->compressed = __libxml2_xzcompressed(context); 2695 } 2696 #endif 2697 } 2698 else 2699 xmlInputCallbackTable[i].closecallback (context); 2700 2701 return(ret); 2702 } 2703 2704 /** 2705 * xmlParserInputBufferCreateFilename: 2706 * @URI: a C string containing the URI or filename 2707 * @enc: the charset encoding if known 2708 * 2709 * Create a buffered parser input for the progressive parsing of a file 2710 * If filename is "-' then we use stdin as the input. 2711 * Automatic support for ZLIB/Compress compressed document is provided 2712 * by default if found at compile-time. 2713 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE 2714 * 2715 * Returns the new parser input or NULL 2716 */ 2717 xmlParserInputBufferPtr 2718 xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) { 2719 if ((xmlParserInputBufferCreateFilenameValue)) { 2720 return xmlParserInputBufferCreateFilenameValue(URI, enc); 2721 } 2722 return __xmlParserInputBufferCreateFilename(URI, enc); 2723 } 2724 2725 #ifdef LIBXML_OUTPUT_ENABLED 2726 xmlOutputBufferPtr 2727 __xmlOutputBufferCreateFilename(const char *URI, 2728 xmlCharEncodingHandlerPtr encoder, 2729 int compression ATTRIBUTE_UNUSED) { 2730 xmlOutputBufferPtr ret; 2731 xmlURIPtr puri; 2732 int i = 0; 2733 void *context = NULL; 2734 char *unescaped = NULL; 2735 #ifdef HAVE_ZLIB_H 2736 int is_file_uri = 1; 2737 #endif 2738 2739 if (xmlOutputCallbackInitialized == 0) 2740 xmlRegisterDefaultOutputCallbacks(); 2741 2742 if (URI == NULL) return(NULL); 2743 2744 puri = xmlParseURI(URI); 2745 if (puri != NULL) { 2746 #ifdef HAVE_ZLIB_H 2747 if ((puri->scheme != NULL) && 2748 (!xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file"))) 2749 is_file_uri = 0; 2750 #endif 2751 /* 2752 * try to limit the damages of the URI unescaping code. 2753 */ 2754 if ((puri->scheme == NULL) || 2755 (xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file"))) 2756 unescaped = xmlURIUnescapeString(URI, 0, NULL); 2757 xmlFreeURI(puri); 2758 } 2759 2760 /* 2761 * Try to find one of the output accept method accepting that scheme 2762 * Go in reverse to give precedence to user defined handlers. 2763 * try with an unescaped version of the URI 2764 */ 2765 if (unescaped != NULL) { 2766 #ifdef HAVE_ZLIB_H 2767 if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) { 2768 context = xmlGzfileOpenW(unescaped, compression); 2769 if (context != NULL) { 2770 ret = xmlAllocOutputBufferInternal(encoder); 2771 if (ret != NULL) { 2772 ret->context = context; 2773 ret->writecallback = xmlGzfileWrite; 2774 ret->closecallback = xmlGzfileClose; 2775 } 2776 xmlFree(unescaped); 2777 return(ret); 2778 } 2779 } 2780 #endif 2781 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) { 2782 if ((xmlOutputCallbackTable[i].matchcallback != NULL) && 2783 (xmlOutputCallbackTable[i].matchcallback(unescaped) != 0)) { 2784 #if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H) 2785 /* Need to pass compression parameter into HTTP open calls */ 2786 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch) 2787 context = xmlIOHTTPOpenW(unescaped, compression); 2788 else 2789 #endif 2790 context = xmlOutputCallbackTable[i].opencallback(unescaped); 2791 if (context != NULL) 2792 break; 2793 } 2794 } 2795 xmlFree(unescaped); 2796 } 2797 2798 /* 2799 * If this failed try with a non-escaped URI this may be a strange 2800 * filename 2801 */ 2802 if (context == NULL) { 2803 #ifdef HAVE_ZLIB_H 2804 if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) { 2805 context = xmlGzfileOpenW(URI, compression); 2806 if (context != NULL) { 2807 ret = xmlAllocOutputBufferInternal(encoder); 2808 if (ret != NULL) { 2809 ret->context = context; 2810 ret->writecallback = xmlGzfileWrite; 2811 ret->closecallback = xmlGzfileClose; 2812 } 2813 return(ret); 2814 } 2815 } 2816 #endif 2817 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) { 2818 if ((xmlOutputCallbackTable[i].matchcallback != NULL) && 2819 (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) { 2820 #if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H) 2821 /* Need to pass compression parameter into HTTP open calls */ 2822 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch) 2823 context = xmlIOHTTPOpenW(URI, compression); 2824 else 2825 #endif 2826 context = xmlOutputCallbackTable[i].opencallback(URI); 2827 if (context != NULL) 2828 break; 2829 } 2830 } 2831 } 2832 2833 if (context == NULL) { 2834 return(NULL); 2835 } 2836 2837 /* 2838 * Allocate the Output buffer front-end. 2839 */ 2840 ret = xmlAllocOutputBufferInternal(encoder); 2841 if (ret != NULL) { 2842 ret->context = context; 2843 ret->writecallback = xmlOutputCallbackTable[i].writecallback; 2844 ret->closecallback = xmlOutputCallbackTable[i].closecallback; 2845 } 2846 return(ret); 2847 } 2848 2849 /** 2850 * xmlOutputBufferCreateFilename: 2851 * @URI: a C string containing the URI or filename 2852 * @encoder: the encoding converter or NULL 2853 * @compression: the compression ration (0 none, 9 max). 2854 * 2855 * Create a buffered output for the progressive saving of a file 2856 * If filename is "-' then we use stdout as the output. 2857 * Automatic support for ZLIB/Compress compressed document is provided 2858 * by default if found at compile-time. 2859 * TODO: currently if compression is set, the library only support 2860 * writing to a local file. 2861 * 2862 * Returns the new output or NULL 2863 */ 2864 xmlOutputBufferPtr 2865 xmlOutputBufferCreateFilename(const char *URI, 2866 xmlCharEncodingHandlerPtr encoder, 2867 int compression ATTRIBUTE_UNUSED) { 2868 if ((xmlOutputBufferCreateFilenameValue)) { 2869 return xmlOutputBufferCreateFilenameValue(URI, encoder, compression); 2870 } 2871 return __xmlOutputBufferCreateFilename(URI, encoder, compression); 2872 } 2873 #endif /* LIBXML_OUTPUT_ENABLED */ 2874 2875 /** 2876 * xmlParserInputBufferCreateFile: 2877 * @file: a FILE* 2878 * @enc: the charset encoding if known 2879 * 2880 * Create a buffered parser input for the progressive parsing of a FILE * 2881 * buffered C I/O 2882 * 2883 * Returns the new parser input or NULL 2884 */ 2885 xmlParserInputBufferPtr 2886 xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) { 2887 xmlParserInputBufferPtr ret; 2888 2889 if (xmlInputCallbackInitialized == 0) 2890 xmlRegisterDefaultInputCallbacks(); 2891 2892 if (file == NULL) return(NULL); 2893 2894 ret = xmlAllocParserInputBuffer(enc); 2895 if (ret != NULL) { 2896 ret->context = file; 2897 ret->readcallback = xmlFileRead; 2898 ret->closecallback = xmlFileFlush; 2899 } 2900 2901 return(ret); 2902 } 2903 2904 #ifdef LIBXML_OUTPUT_ENABLED 2905 /** 2906 * xmlOutputBufferCreateFile: 2907 * @file: a FILE* 2908 * @encoder: the encoding converter or NULL 2909 * 2910 * Create a buffered output for the progressive saving to a FILE * 2911 * buffered C I/O 2912 * 2913 * Returns the new parser output or NULL 2914 */ 2915 xmlOutputBufferPtr 2916 xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) { 2917 xmlOutputBufferPtr ret; 2918 2919 if (xmlOutputCallbackInitialized == 0) 2920 xmlRegisterDefaultOutputCallbacks(); 2921 2922 if (file == NULL) return(NULL); 2923 2924 ret = xmlAllocOutputBufferInternal(encoder); 2925 if (ret != NULL) { 2926 ret->context = file; 2927 ret->writecallback = xmlFileWrite; 2928 ret->closecallback = xmlFileFlush; 2929 } 2930 2931 return(ret); 2932 } 2933 2934 /** 2935 * xmlOutputBufferCreateBuffer: 2936 * @buffer: a xmlBufferPtr 2937 * @encoder: the encoding converter or NULL 2938 * 2939 * Create a buffered output for the progressive saving to a xmlBuffer 2940 * 2941 * Returns the new parser output or NULL 2942 */ 2943 xmlOutputBufferPtr 2944 xmlOutputBufferCreateBuffer(xmlBufferPtr buffer, 2945 xmlCharEncodingHandlerPtr encoder) { 2946 xmlOutputBufferPtr ret; 2947 2948 if (buffer == NULL) return(NULL); 2949 2950 ret = xmlOutputBufferCreateIO((xmlOutputWriteCallback) 2951 xmlBufferWrite, 2952 (xmlOutputCloseCallback) 2953 NULL, (void *) buffer, encoder); 2954 2955 return(ret); 2956 } 2957 2958 /** 2959 * xmlOutputBufferGetContent: 2960 * @out: an xmlOutputBufferPtr 2961 * 2962 * Gives a pointer to the data currently held in the output buffer 2963 * 2964 * Returns a pointer to the data or NULL in case of error 2965 */ 2966 const xmlChar * 2967 xmlOutputBufferGetContent(xmlOutputBufferPtr out) { 2968 if ((out == NULL) || (out->buffer == NULL)) 2969 return(NULL); 2970 2971 return(xmlBufContent(out->buffer)); 2972 } 2973 2974 /** 2975 * xmlOutputBufferGetSize: 2976 * @out: an xmlOutputBufferPtr 2977 * 2978 * Gives the length of the data currently held in the output buffer 2979 * 2980 * Returns 0 in case or error or no data is held, the size otherwise 2981 */ 2982 size_t 2983 xmlOutputBufferGetSize(xmlOutputBufferPtr out) { 2984 if ((out == NULL) || (out->buffer == NULL)) 2985 return(0); 2986 2987 return(xmlBufUse(out->buffer)); 2988 } 2989 2990 2991 #endif /* LIBXML_OUTPUT_ENABLED */ 2992 2993 /** 2994 * xmlParserInputBufferCreateFd: 2995 * @fd: a file descriptor number 2996 * @enc: the charset encoding if known 2997 * 2998 * Create a buffered parser input for the progressive parsing for the input 2999 * from a file descriptor 3000 * 3001 * Returns the new parser input or NULL 3002 */ 3003 xmlParserInputBufferPtr 3004 xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) { 3005 xmlParserInputBufferPtr ret; 3006 3007 if (fd < 0) return(NULL); 3008 3009 ret = xmlAllocParserInputBuffer(enc); 3010 if (ret != NULL) { 3011 ret->context = (void *) (long) fd; 3012 ret->readcallback = xmlFdRead; 3013 ret->closecallback = xmlFdClose; 3014 } 3015 3016 return(ret); 3017 } 3018 3019 /** 3020 * xmlParserInputBufferCreateMem: 3021 * @mem: the memory input 3022 * @size: the length of the memory block 3023 * @enc: the charset encoding if known 3024 * 3025 * Create a buffered parser input for the progressive parsing for the input 3026 * from a memory area. 3027 * 3028 * Returns the new parser input or NULL 3029 */ 3030 xmlParserInputBufferPtr 3031 xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) { 3032 xmlParserInputBufferPtr ret; 3033 int errcode; 3034 3035 if (size <= 0) return(NULL); 3036 if (mem == NULL) return(NULL); 3037 3038 ret = xmlAllocParserInputBuffer(enc); 3039 if (ret != NULL) { 3040 ret->context = (void *) mem; 3041 ret->readcallback = (xmlInputReadCallback) xmlNop; 3042 ret->closecallback = NULL; 3043 errcode = xmlBufAdd(ret->buffer, (const xmlChar *) mem, size); 3044 if (errcode != 0) { 3045 xmlFree(ret); 3046 return(NULL); 3047 } 3048 } 3049 3050 return(ret); 3051 } 3052 3053 /** 3054 * xmlParserInputBufferCreateStatic: 3055 * @mem: the memory input 3056 * @size: the length of the memory block 3057 * @enc: the charset encoding if known 3058 * 3059 * Create a buffered parser input for the progressive parsing for the input 3060 * from an immutable memory area. This will not copy the memory area to 3061 * the buffer, but the memory is expected to be available until the end of 3062 * the parsing, this is useful for example when using mmap'ed file. 3063 * 3064 * Returns the new parser input or NULL 3065 */ 3066 xmlParserInputBufferPtr 3067 xmlParserInputBufferCreateStatic(const char *mem, int size, 3068 xmlCharEncoding enc) { 3069 xmlParserInputBufferPtr ret; 3070 3071 if (size <= 0) return(NULL); 3072 if (mem == NULL) return(NULL); 3073 3074 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer)); 3075 if (ret == NULL) { 3076 xmlIOErrMemory("creating input buffer"); 3077 return(NULL); 3078 } 3079 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer)); 3080 ret->buffer = xmlBufCreateStatic((void *)mem, (size_t) size); 3081 if (ret->buffer == NULL) { 3082 xmlFree(ret); 3083 return(NULL); 3084 } 3085 ret->encoder = xmlGetCharEncodingHandler(enc); 3086 if (ret->encoder != NULL) 3087 ret->raw = xmlBufCreateSize(2 * xmlDefaultBufferSize); 3088 else 3089 ret->raw = NULL; 3090 ret->compressed = -1; 3091 ret->context = (void *) mem; 3092 ret->readcallback = NULL; 3093 ret->closecallback = NULL; 3094 3095 return(ret); 3096 } 3097 3098 #ifdef LIBXML_OUTPUT_ENABLED 3099 /** 3100 * xmlOutputBufferCreateFd: 3101 * @fd: a file descriptor number 3102 * @encoder: the encoding converter or NULL 3103 * 3104 * Create a buffered output for the progressive saving 3105 * to a file descriptor 3106 * 3107 * Returns the new parser output or NULL 3108 */ 3109 xmlOutputBufferPtr 3110 xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) { 3111 xmlOutputBufferPtr ret; 3112 3113 if (fd < 0) return(NULL); 3114 3115 ret = xmlAllocOutputBufferInternal(encoder); 3116 if (ret != NULL) { 3117 ret->context = (void *) (long) fd; 3118 ret->writecallback = xmlFdWrite; 3119 ret->closecallback = NULL; 3120 } 3121 3122 return(ret); 3123 } 3124 #endif /* LIBXML_OUTPUT_ENABLED */ 3125 3126 /** 3127 * xmlParserInputBufferCreateIO: 3128 * @ioread: an I/O read function 3129 * @ioclose: an I/O close function 3130 * @ioctx: an I/O handler 3131 * @enc: the charset encoding if known 3132 * 3133 * Create a buffered parser input for the progressive parsing for the input 3134 * from an I/O handler 3135 * 3136 * Returns the new parser input or NULL 3137 */ 3138 xmlParserInputBufferPtr 3139 xmlParserInputBufferCreateIO(xmlInputReadCallback ioread, 3140 xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) { 3141 xmlParserInputBufferPtr ret; 3142 3143 if (ioread == NULL) return(NULL); 3144 3145 ret = xmlAllocParserInputBuffer(enc); 3146 if (ret != NULL) { 3147 ret->context = (void *) ioctx; 3148 ret->readcallback = ioread; 3149 ret->closecallback = ioclose; 3150 } 3151 3152 return(ret); 3153 } 3154 3155 #ifdef LIBXML_OUTPUT_ENABLED 3156 /** 3157 * xmlOutputBufferCreateIO: 3158 * @iowrite: an I/O write function 3159 * @ioclose: an I/O close function 3160 * @ioctx: an I/O handler 3161 * @encoder: the charset encoding if known 3162 * 3163 * Create a buffered output for the progressive saving 3164 * to an I/O handler 3165 * 3166 * Returns the new parser output or NULL 3167 */ 3168 xmlOutputBufferPtr 3169 xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite, 3170 xmlOutputCloseCallback ioclose, void *ioctx, 3171 xmlCharEncodingHandlerPtr encoder) { 3172 xmlOutputBufferPtr ret; 3173 3174 if (iowrite == NULL) return(NULL); 3175 3176 ret = xmlAllocOutputBufferInternal(encoder); 3177 if (ret != NULL) { 3178 ret->context = (void *) ioctx; 3179 ret->writecallback = iowrite; 3180 ret->closecallback = ioclose; 3181 } 3182 3183 return(ret); 3184 } 3185 #endif /* LIBXML_OUTPUT_ENABLED */ 3186 3187 /** 3188 * xmlParserInputBufferCreateFilenameDefault: 3189 * @func: function pointer to the new ParserInputBufferCreateFilenameFunc 3190 * 3191 * Registers a callback for URI input file handling 3192 * 3193 * Returns the old value of the registration function 3194 */ 3195 xmlParserInputBufferCreateFilenameFunc 3196 xmlParserInputBufferCreateFilenameDefault(xmlParserInputBufferCreateFilenameFunc func) 3197 { 3198 xmlParserInputBufferCreateFilenameFunc old = xmlParserInputBufferCreateFilenameValue; 3199 if (old == NULL) { 3200 old = __xmlParserInputBufferCreateFilename; 3201 } 3202 3203 xmlParserInputBufferCreateFilenameValue = func; 3204 return(old); 3205 } 3206 3207 /** 3208 * xmlOutputBufferCreateFilenameDefault: 3209 * @func: function pointer to the new OutputBufferCreateFilenameFunc 3210 * 3211 * Registers a callback for URI output file handling 3212 * 3213 * Returns the old value of the registration function 3214 */ 3215 xmlOutputBufferCreateFilenameFunc 3216 xmlOutputBufferCreateFilenameDefault(xmlOutputBufferCreateFilenameFunc func) 3217 { 3218 xmlOutputBufferCreateFilenameFunc old = xmlOutputBufferCreateFilenameValue; 3219 #ifdef LIBXML_OUTPUT_ENABLED 3220 if (old == NULL) { 3221 old = __xmlOutputBufferCreateFilename; 3222 } 3223 #endif 3224 xmlOutputBufferCreateFilenameValue = func; 3225 return(old); 3226 } 3227 3228 /** 3229 * xmlParserInputBufferPush: 3230 * @in: a buffered parser input 3231 * @len: the size in bytes of the array. 3232 * @buf: an char array 3233 * 3234 * Push the content of the arry in the input buffer 3235 * This routine handle the I18N transcoding to internal UTF-8 3236 * This is used when operating the parser in progressive (push) mode. 3237 * 3238 * Returns the number of chars read and stored in the buffer, or -1 3239 * in case of error. 3240 */ 3241 int 3242 xmlParserInputBufferPush(xmlParserInputBufferPtr in, 3243 int len, const char *buf) { 3244 int nbchars = 0; 3245 int ret; 3246 3247 if (len < 0) return(0); 3248 if ((in == NULL) || (in->error)) return(-1); 3249 if (in->encoder != NULL) { 3250 unsigned int use; 3251 3252 /* 3253 * Store the data in the incoming raw buffer 3254 */ 3255 if (in->raw == NULL) { 3256 in->raw = xmlBufCreate(); 3257 } 3258 ret = xmlBufAdd(in->raw, (const xmlChar *) buf, len); 3259 if (ret != 0) 3260 return(-1); 3261 3262 /* 3263 * convert as much as possible to the parser reading buffer. 3264 */ 3265 use = xmlBufUse(in->raw); 3266 nbchars = xmlCharEncInput(in, 1); 3267 if (nbchars < 0) { 3268 xmlIOErr(XML_IO_ENCODER, NULL); 3269 in->error = XML_IO_ENCODER; 3270 return(-1); 3271 } 3272 in->rawconsumed += (use - xmlBufUse(in->raw)); 3273 } else { 3274 nbchars = len; 3275 ret = xmlBufAdd(in->buffer, (xmlChar *) buf, nbchars); 3276 if (ret != 0) 3277 return(-1); 3278 } 3279 #ifdef DEBUG_INPUT 3280 xmlGenericError(xmlGenericErrorContext, 3281 "I/O: pushed %d chars, buffer %d/%d\n", 3282 nbchars, xmlBufUse(in->buffer), xmlBufLength(in->buffer)); 3283 #endif 3284 return(nbchars); 3285 } 3286 3287 /** 3288 * endOfInput: 3289 * 3290 * When reading from an Input channel indicated end of file or error 3291 * don't reread from it again. 3292 */ 3293 static int 3294 endOfInput (void * context ATTRIBUTE_UNUSED, 3295 char * buffer ATTRIBUTE_UNUSED, 3296 int len ATTRIBUTE_UNUSED) { 3297 return(0); 3298 } 3299 3300 /** 3301 * xmlParserInputBufferGrow: 3302 * @in: a buffered parser input 3303 * @len: indicative value of the amount of chars to read 3304 * 3305 * Grow up the content of the input buffer, the old data are preserved 3306 * This routine handle the I18N transcoding to internal UTF-8 3307 * This routine is used when operating the parser in normal (pull) mode 3308 * 3309 * TODO: one should be able to remove one extra copy by copying directly 3310 * onto in->buffer or in->raw 3311 * 3312 * Returns the number of chars read and stored in the buffer, or -1 3313 * in case of error. 3314 */ 3315 int 3316 xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) { 3317 char *buffer = NULL; 3318 int res = 0; 3319 int nbchars = 0; 3320 3321 if ((in == NULL) || (in->error)) return(-1); 3322 if ((len <= MINLEN) && (len != 4)) 3323 len = MINLEN; 3324 3325 if (xmlBufAvail(in->buffer) <= 0) { 3326 xmlIOErr(XML_IO_BUFFER_FULL, NULL); 3327 in->error = XML_IO_BUFFER_FULL; 3328 return(-1); 3329 } 3330 3331 if (xmlBufGrow(in->buffer, len + 1) < 0) { 3332 xmlIOErrMemory("growing input buffer"); 3333 in->error = XML_ERR_NO_MEMORY; 3334 return(-1); 3335 } 3336 buffer = (char *)xmlBufEnd(in->buffer); 3337 3338 /* 3339 * Call the read method for this I/O type. 3340 */ 3341 if (in->readcallback != NULL) { 3342 res = in->readcallback(in->context, &buffer[0], len); 3343 if (res <= 0) 3344 in->readcallback = endOfInput; 3345 } else { 3346 xmlIOErr(XML_IO_NO_INPUT, NULL); 3347 in->error = XML_IO_NO_INPUT; 3348 return(-1); 3349 } 3350 if (res < 0) { 3351 return(-1); 3352 } 3353 3354 /* 3355 * try to establish compressed status of input if not done already 3356 */ 3357 if (in->compressed == -1) { 3358 #ifdef LIBXML_LZMA_ENABLED 3359 if (in->readcallback == xmlXzfileRead) 3360 in->compressed = __libxml2_xzcompressed(in->context); 3361 #endif 3362 } 3363 3364 len = res; 3365 if (in->encoder != NULL) { 3366 unsigned int use; 3367 3368 /* 3369 * Store the data in the incoming raw buffer 3370 */ 3371 if (in->raw == NULL) { 3372 in->raw = xmlBufCreate(); 3373 } 3374 res = xmlBufAdd(in->raw, (const xmlChar *) buffer, len); 3375 if (res != 0) 3376 return(-1); 3377 3378 /* 3379 * convert as much as possible to the parser reading buffer. 3380 */ 3381 use = xmlBufUse(in->raw); 3382 nbchars = xmlCharEncInput(in, 1); 3383 if (nbchars < 0) { 3384 xmlIOErr(XML_IO_ENCODER, NULL); 3385 in->error = XML_IO_ENCODER; 3386 return(-1); 3387 } 3388 in->rawconsumed += (use - xmlBufUse(in->raw)); 3389 } else { 3390 nbchars = len; 3391 xmlBufAddLen(in->buffer, nbchars); 3392 } 3393 #ifdef DEBUG_INPUT 3394 xmlGenericError(xmlGenericErrorContext, 3395 "I/O: read %d chars, buffer %d\n", 3396 nbchars, xmlBufUse(in->buffer)); 3397 #endif 3398 return(nbchars); 3399 } 3400 3401 /** 3402 * xmlParserInputBufferRead: 3403 * @in: a buffered parser input 3404 * @len: indicative value of the amount of chars to read 3405 * 3406 * Refresh the content of the input buffer, the old data are considered 3407 * consumed 3408 * This routine handle the I18N transcoding to internal UTF-8 3409 * 3410 * Returns the number of chars read and stored in the buffer, or -1 3411 * in case of error. 3412 */ 3413 int 3414 xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) { 3415 if ((in == NULL) || (in->error)) return(-1); 3416 if (in->readcallback != NULL) 3417 return(xmlParserInputBufferGrow(in, len)); 3418 else if (xmlBufGetAllocationScheme(in->buffer) == XML_BUFFER_ALLOC_IMMUTABLE) 3419 return(0); 3420 else 3421 return(-1); 3422 } 3423 3424 #ifdef LIBXML_OUTPUT_ENABLED 3425 /** 3426 * xmlOutputBufferWrite: 3427 * @out: a buffered parser output 3428 * @len: the size in bytes of the array. 3429 * @buf: an char array 3430 * 3431 * Write the content of the array in the output I/O buffer 3432 * This routine handle the I18N transcoding from internal UTF-8 3433 * The buffer is lossless, i.e. will store in case of partial 3434 * or delayed writes. 3435 * 3436 * Returns the number of chars immediately written, or -1 3437 * in case of error. 3438 */ 3439 int 3440 xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) { 3441 int nbchars = 0; /* number of chars to output to I/O */ 3442 int ret; /* return from function call */ 3443 int written = 0; /* number of char written to I/O so far */ 3444 int chunk; /* number of byte curreent processed from buf */ 3445 3446 if ((out == NULL) || (out->error)) return(-1); 3447 if (len < 0) return(0); 3448 if (out->error) return(-1); 3449 3450 do { 3451 chunk = len; 3452 if (chunk > 4 * MINLEN) 3453 chunk = 4 * MINLEN; 3454 3455 /* 3456 * first handle encoding stuff. 3457 */ 3458 if (out->encoder != NULL) { 3459 /* 3460 * Store the data in the incoming raw buffer 3461 */ 3462 if (out->conv == NULL) { 3463 out->conv = xmlBufCreate(); 3464 } 3465 ret = xmlBufAdd(out->buffer, (const xmlChar *) buf, chunk); 3466 if (ret != 0) 3467 return(-1); 3468 3469 if ((xmlBufUse(out->buffer) < MINLEN) && (chunk == len)) 3470 goto done; 3471 3472 /* 3473 * convert as much as possible to the parser reading buffer. 3474 */ 3475 ret = xmlCharEncOutput(out, 0); 3476 if ((ret < 0) && (ret != -3)) { 3477 xmlIOErr(XML_IO_ENCODER, NULL); 3478 out->error = XML_IO_ENCODER; 3479 return(-1); 3480 } 3481 nbchars = ret >= 0 ? ret : 0; 3482 } else { 3483 ret = xmlBufAdd(out->buffer, (const xmlChar *) buf, chunk); 3484 if (ret != 0) 3485 return(-1); 3486 nbchars = chunk; 3487 } 3488 buf += chunk; 3489 len -= chunk; 3490 3491 if (out->writecallback) { 3492 if ((nbchars < MINLEN) && (len <= 0)) 3493 goto done; 3494 3495 /* 3496 * second write the stuff to the I/O channel 3497 */ 3498 if (out->encoder != NULL) { 3499 ret = out->writecallback(out->context, 3500 (const char *)xmlBufContent(out->conv), nbchars); 3501 if (ret >= 0) 3502 xmlBufShrink(out->conv, ret); 3503 } else { 3504 ret = out->writecallback(out->context, 3505 (const char *)xmlBufContent(out->buffer), nbchars); 3506 if (ret >= 0) 3507 xmlBufShrink(out->buffer, ret); 3508 } 3509 if (ret < 0) { 3510 xmlIOErr(XML_IO_WRITE, NULL); 3511 out->error = XML_IO_WRITE; 3512 return(ret); 3513 } 3514 if (out->written > INT_MAX - ret) 3515 out->written = INT_MAX; 3516 else 3517 out->written += ret; 3518 } 3519 written += nbchars; 3520 } while (len > 0); 3521 3522 done: 3523 #ifdef DEBUG_INPUT 3524 xmlGenericError(xmlGenericErrorContext, 3525 "I/O: wrote %d chars\n", written); 3526 #endif 3527 return(written); 3528 } 3529 3530 /** 3531 * xmlEscapeContent: 3532 * @out: a pointer to an array of bytes to store the result 3533 * @outlen: the length of @out 3534 * @in: a pointer to an array of unescaped UTF-8 bytes 3535 * @inlen: the length of @in 3536 * 3537 * Take a block of UTF-8 chars in and escape them. 3538 * Returns 0 if success, or -1 otherwise 3539 * The value of @inlen after return is the number of octets consumed 3540 * if the return value is positive, else unpredictable. 3541 * The value of @outlen after return is the number of octets consumed. 3542 */ 3543 static int 3544 xmlEscapeContent(unsigned char* out, int *outlen, 3545 const xmlChar* in, int *inlen) { 3546 unsigned char* outstart = out; 3547 const unsigned char* base = in; 3548 unsigned char* outend = out + *outlen; 3549 const unsigned char* inend; 3550 3551 inend = in + (*inlen); 3552 3553 while ((in < inend) && (out < outend)) { 3554 if (*in == '<') { 3555 if (outend - out < 4) break; 3556 *out++ = '&'; 3557 *out++ = 'l'; 3558 *out++ = 't'; 3559 *out++ = ';'; 3560 } else if (*in == '>') { 3561 if (outend - out < 4) break; 3562 *out++ = '&'; 3563 *out++ = 'g'; 3564 *out++ = 't'; 3565 *out++ = ';'; 3566 } else if (*in == '&') { 3567 if (outend - out < 5) break; 3568 *out++ = '&'; 3569 *out++ = 'a'; 3570 *out++ = 'm'; 3571 *out++ = 'p'; 3572 *out++ = ';'; 3573 } else if (*in == '\r') { 3574 if (outend - out < 5) break; 3575 *out++ = '&'; 3576 *out++ = '#'; 3577 *out++ = '1'; 3578 *out++ = '3'; 3579 *out++ = ';'; 3580 } else { 3581 *out++ = (unsigned char) *in; 3582 } 3583 ++in; 3584 } 3585 *outlen = out - outstart; 3586 *inlen = in - base; 3587 return(0); 3588 } 3589 3590 /** 3591 * xmlOutputBufferWriteEscape: 3592 * @out: a buffered parser output 3593 * @str: a zero terminated UTF-8 string 3594 * @escaping: an optional escaping function (or NULL) 3595 * 3596 * Write the content of the string in the output I/O buffer 3597 * This routine escapes the caracters and then handle the I18N 3598 * transcoding from internal UTF-8 3599 * The buffer is lossless, i.e. will store in case of partial 3600 * or delayed writes. 3601 * 3602 * Returns the number of chars immediately written, or -1 3603 * in case of error. 3604 */ 3605 int 3606 xmlOutputBufferWriteEscape(xmlOutputBufferPtr out, const xmlChar *str, 3607 xmlCharEncodingOutputFunc escaping) { 3608 int nbchars = 0; /* number of chars to output to I/O */ 3609 int ret; /* return from function call */ 3610 int written = 0; /* number of char written to I/O so far */ 3611 int oldwritten=0;/* loop guard */ 3612 int chunk; /* number of byte currently processed from str */ 3613 int len; /* number of bytes in str */ 3614 int cons; /* byte from str consumed */ 3615 3616 if ((out == NULL) || (out->error) || (str == NULL) || 3617 (out->buffer == NULL) || 3618 (xmlBufGetAllocationScheme(out->buffer) == XML_BUFFER_ALLOC_IMMUTABLE)) 3619 return(-1); 3620 len = strlen((const char *)str); 3621 if (len < 0) return(0); 3622 if (out->error) return(-1); 3623 if (escaping == NULL) escaping = xmlEscapeContent; 3624 3625 do { 3626 oldwritten = written; 3627 3628 /* 3629 * how many bytes to consume and how many bytes to store. 3630 */ 3631 cons = len; 3632 chunk = xmlBufAvail(out->buffer) - 1; 3633 3634 /* 3635 * make sure we have enough room to save first, if this is 3636 * not the case force a flush, but make sure we stay in the loop 3637 */ 3638 if (chunk < 40) { 3639 if (xmlBufGrow(out->buffer, 100) < 0) 3640 return(-1); 3641 oldwritten = -1; 3642 continue; 3643 } 3644 3645 /* 3646 * first handle encoding stuff. 3647 */ 3648 if (out->encoder != NULL) { 3649 /* 3650 * Store the data in the incoming raw buffer 3651 */ 3652 if (out->conv == NULL) { 3653 out->conv = xmlBufCreate(); 3654 } 3655 ret = escaping(xmlBufEnd(out->buffer) , 3656 &chunk, str, &cons); 3657 if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */ 3658 return(-1); 3659 xmlBufAddLen(out->buffer, chunk); 3660 3661 if ((xmlBufUse(out->buffer) < MINLEN) && (cons == len)) 3662 goto done; 3663 3664 /* 3665 * convert as much as possible to the output buffer. 3666 */ 3667 ret = xmlCharEncOutput(out, 0); 3668 if ((ret < 0) && (ret != -3)) { 3669 xmlIOErr(XML_IO_ENCODER, NULL); 3670 out->error = XML_IO_ENCODER; 3671 return(-1); 3672 } 3673 nbchars = ret >= 0 ? ret : 0; 3674 } else { 3675 ret = escaping(xmlBufEnd(out->buffer), &chunk, str, &cons); 3676 if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */ 3677 return(-1); 3678 xmlBufAddLen(out->buffer, chunk); 3679 nbchars = chunk; 3680 } 3681 str += cons; 3682 len -= cons; 3683 3684 if (out->writecallback) { 3685 if ((nbchars < MINLEN) && (len <= 0)) 3686 goto done; 3687 3688 /* 3689 * second write the stuff to the I/O channel 3690 */ 3691 if (out->encoder != NULL) { 3692 ret = out->writecallback(out->context, 3693 (const char *)xmlBufContent(out->conv), nbchars); 3694 if (ret >= 0) 3695 xmlBufShrink(out->conv, ret); 3696 } else { 3697 ret = out->writecallback(out->context, 3698 (const char *)xmlBufContent(out->buffer), nbchars); 3699 if (ret >= 0) 3700 xmlBufShrink(out->buffer, ret); 3701 } 3702 if (ret < 0) { 3703 xmlIOErr(XML_IO_WRITE, NULL); 3704 out->error = XML_IO_WRITE; 3705 return(ret); 3706 } 3707 if (out->written > INT_MAX - ret) 3708 out->written = INT_MAX; 3709 else 3710 out->written += ret; 3711 } else if (xmlBufAvail(out->buffer) < MINLEN) { 3712 xmlBufGrow(out->buffer, MINLEN); 3713 } 3714 written += nbchars; 3715 } while ((len > 0) && (oldwritten != written)); 3716 3717 done: 3718 #ifdef DEBUG_INPUT 3719 xmlGenericError(xmlGenericErrorContext, 3720 "I/O: wrote %d chars\n", written); 3721 #endif 3722 return(written); 3723 } 3724 3725 /** 3726 * xmlOutputBufferWriteString: 3727 * @out: a buffered parser output 3728 * @str: a zero terminated C string 3729 * 3730 * Write the content of the string in the output I/O buffer 3731 * This routine handle the I18N transcoding from internal UTF-8 3732 * The buffer is lossless, i.e. will store in case of partial 3733 * or delayed writes. 3734 * 3735 * Returns the number of chars immediately written, or -1 3736 * in case of error. 3737 */ 3738 int 3739 xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) { 3740 int len; 3741 3742 if ((out == NULL) || (out->error)) return(-1); 3743 if (str == NULL) 3744 return(-1); 3745 len = strlen(str); 3746 3747 if (len > 0) 3748 return(xmlOutputBufferWrite(out, len, str)); 3749 return(len); 3750 } 3751 3752 /** 3753 * xmlOutputBufferFlush: 3754 * @out: a buffered output 3755 * 3756 * flushes the output I/O channel 3757 * 3758 * Returns the number of byte written or -1 in case of error. 3759 */ 3760 int 3761 xmlOutputBufferFlush(xmlOutputBufferPtr out) { 3762 int nbchars = 0, ret = 0; 3763 3764 if ((out == NULL) || (out->error)) return(-1); 3765 /* 3766 * first handle encoding stuff. 3767 */ 3768 if ((out->conv != NULL) && (out->encoder != NULL)) { 3769 /* 3770 * convert as much as possible to the parser output buffer. 3771 */ 3772 do { 3773 nbchars = xmlCharEncOutput(out, 0); 3774 if (nbchars < 0) { 3775 xmlIOErr(XML_IO_ENCODER, NULL); 3776 out->error = XML_IO_ENCODER; 3777 return(-1); 3778 } 3779 } while (nbchars); 3780 } 3781 3782 /* 3783 * second flush the stuff to the I/O channel 3784 */ 3785 if ((out->conv != NULL) && (out->encoder != NULL) && 3786 (out->writecallback != NULL)) { 3787 ret = out->writecallback(out->context, 3788 (const char *)xmlBufContent(out->conv), 3789 xmlBufUse(out->conv)); 3790 if (ret >= 0) 3791 xmlBufShrink(out->conv, ret); 3792 } else if (out->writecallback != NULL) { 3793 ret = out->writecallback(out->context, 3794 (const char *)xmlBufContent(out->buffer), 3795 xmlBufUse(out->buffer)); 3796 if (ret >= 0) 3797 xmlBufShrink(out->buffer, ret); 3798 } 3799 if (ret < 0) { 3800 xmlIOErr(XML_IO_FLUSH, NULL); 3801 out->error = XML_IO_FLUSH; 3802 return(ret); 3803 } 3804 if (out->written > INT_MAX - ret) 3805 out->written = INT_MAX; 3806 else 3807 out->written += ret; 3808 3809 #ifdef DEBUG_INPUT 3810 xmlGenericError(xmlGenericErrorContext, 3811 "I/O: flushed %d chars\n", ret); 3812 #endif 3813 return(ret); 3814 } 3815 #endif /* LIBXML_OUTPUT_ENABLED */ 3816 3817 /** 3818 * xmlParserGetDirectory: 3819 * @filename: the path to a file 3820 * 3821 * lookup the directory for that file 3822 * 3823 * Returns a new allocated string containing the directory, or NULL. 3824 */ 3825 char * 3826 xmlParserGetDirectory(const char *filename) { 3827 char *ret = NULL; 3828 char dir[1024]; 3829 char *cur; 3830 3831 #ifdef _WIN32_WCE /* easy way by now ... wince does not have dirs! */ 3832 return NULL; 3833 #endif 3834 3835 if (xmlInputCallbackInitialized == 0) 3836 xmlRegisterDefaultInputCallbacks(); 3837 3838 if (filename == NULL) return(NULL); 3839 3840 #if defined(WIN32) && !defined(__CYGWIN__) 3841 # define IS_XMLPGD_SEP(ch) ((ch=='/')||(ch=='\\')) 3842 #else 3843 # define IS_XMLPGD_SEP(ch) (ch=='/') 3844 #endif 3845 3846 strncpy(dir, filename, 1023); 3847 dir[1023] = 0; 3848 cur = &dir[strlen(dir)]; 3849 while (cur > dir) { 3850 if (IS_XMLPGD_SEP(*cur)) break; 3851 cur --; 3852 } 3853 if (IS_XMLPGD_SEP(*cur)) { 3854 if (cur == dir) dir[1] = 0; 3855 else *cur = 0; 3856 ret = xmlMemStrdup(dir); 3857 } else { 3858 if (getcwd(dir, 1024) != NULL) { 3859 dir[1023] = 0; 3860 ret = xmlMemStrdup(dir); 3861 } 3862 } 3863 return(ret); 3864 #undef IS_XMLPGD_SEP 3865 } 3866 3867 /**************************************************************** 3868 * * 3869 * External entities loading * 3870 * * 3871 ****************************************************************/ 3872 3873 /** 3874 * xmlCheckHTTPInput: 3875 * @ctxt: an XML parser context 3876 * @ret: an XML parser input 3877 * 3878 * Check an input in case it was created from an HTTP stream, in that 3879 * case it will handle encoding and update of the base URL in case of 3880 * redirection. It also checks for HTTP errors in which case the input 3881 * is cleanly freed up and an appropriate error is raised in context 3882 * 3883 * Returns the input or NULL in case of HTTP error. 3884 */ 3885 xmlParserInputPtr 3886 xmlCheckHTTPInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr ret) { 3887 #ifdef LIBXML_HTTP_ENABLED 3888 if ((ret != NULL) && (ret->buf != NULL) && 3889 (ret->buf->readcallback == xmlIOHTTPRead) && 3890 (ret->buf->context != NULL)) { 3891 const char *encoding; 3892 const char *redir; 3893 const char *mime; 3894 int code; 3895 3896 code = xmlNanoHTTPReturnCode(ret->buf->context); 3897 if (code >= 400) { 3898 /* fatal error */ 3899 if (ret->filename != NULL) 3900 __xmlLoaderErr(ctxt, "failed to load HTTP resource \"%s\"\n", 3901 (const char *) ret->filename); 3902 else 3903 __xmlLoaderErr(ctxt, "failed to load HTTP resource\n", NULL); 3904 xmlFreeInputStream(ret); 3905 ret = NULL; 3906 } else { 3907 3908 mime = xmlNanoHTTPMimeType(ret->buf->context); 3909 if ((xmlStrstr(BAD_CAST mime, BAD_CAST "/xml")) || 3910 (xmlStrstr(BAD_CAST mime, BAD_CAST "+xml"))) { 3911 encoding = xmlNanoHTTPEncoding(ret->buf->context); 3912 if (encoding != NULL) { 3913 xmlCharEncodingHandlerPtr handler; 3914 3915 handler = xmlFindCharEncodingHandler(encoding); 3916 if (handler != NULL) { 3917 xmlSwitchInputEncoding(ctxt, ret, handler); 3918 } else { 3919 __xmlErrEncoding(ctxt, XML_ERR_UNKNOWN_ENCODING, 3920 "Unknown encoding %s", 3921 BAD_CAST encoding, NULL); 3922 } 3923 if (ret->encoding == NULL) 3924 ret->encoding = xmlStrdup(BAD_CAST encoding); 3925 } 3926 #if 0 3927 } else if (xmlStrstr(BAD_CAST mime, BAD_CAST "html")) { 3928 #endif 3929 } 3930 redir = xmlNanoHTTPRedir(ret->buf->context); 3931 if (redir != NULL) { 3932 if (ret->filename != NULL) 3933 xmlFree((xmlChar *) ret->filename); 3934 if (ret->directory != NULL) { 3935 xmlFree((xmlChar *) ret->directory); 3936 ret->directory = NULL; 3937 } 3938 ret->filename = 3939 (char *) xmlStrdup((const xmlChar *) redir); 3940 } 3941 } 3942 } 3943 #endif 3944 return(ret); 3945 } 3946 3947 static int xmlNoNetExists(const char *URL) { 3948 const char *path; 3949 3950 if (URL == NULL) 3951 return(0); 3952 3953 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17)) 3954 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__) 3955 path = &URL[17]; 3956 #else 3957 path = &URL[16]; 3958 #endif 3959 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) { 3960 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__) 3961 path = &URL[8]; 3962 #else 3963 path = &URL[7]; 3964 #endif 3965 } else 3966 path = URL; 3967 3968 return xmlCheckFilename(path); 3969 } 3970 3971 #ifdef LIBXML_CATALOG_ENABLED 3972 3973 /** 3974 * xmlResolveResourceFromCatalog: 3975 * @URL: the URL for the entity to load 3976 * @ID: the System ID for the entity to load 3977 * @ctxt: the context in which the entity is called or NULL 3978 * 3979 * Resolves the URL and ID against the appropriate catalog. 3980 * This function is used by xmlDefaultExternalEntityLoader and 3981 * xmlNoNetExternalEntityLoader. 3982 * 3983 * Returns a new allocated URL, or NULL. 3984 */ 3985 static xmlChar * 3986 xmlResolveResourceFromCatalog(const char *URL, const char *ID, 3987 xmlParserCtxtPtr ctxt) { 3988 xmlChar *resource = NULL; 3989 xmlCatalogAllow pref; 3990 3991 /* 3992 * If the resource doesn't exists as a file, 3993 * try to load it from the resource pointed in the catalogs 3994 */ 3995 pref = xmlCatalogGetDefaults(); 3996 3997 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) { 3998 /* 3999 * Do a local lookup 4000 */ 4001 if ((ctxt != NULL) && (ctxt->catalogs != NULL) && 4002 ((pref == XML_CATA_ALLOW_ALL) || 4003 (pref == XML_CATA_ALLOW_DOCUMENT))) { 4004 resource = xmlCatalogLocalResolve(ctxt->catalogs, 4005 (const xmlChar *)ID, 4006 (const xmlChar *)URL); 4007 } 4008 /* 4009 * Try a global lookup 4010 */ 4011 if ((resource == NULL) && 4012 ((pref == XML_CATA_ALLOW_ALL) || 4013 (pref == XML_CATA_ALLOW_GLOBAL))) { 4014 resource = xmlCatalogResolve((const xmlChar *)ID, 4015 (const xmlChar *)URL); 4016 } 4017 if ((resource == NULL) && (URL != NULL)) 4018 resource = xmlStrdup((const xmlChar *) URL); 4019 4020 /* 4021 * TODO: do an URI lookup on the reference 4022 */ 4023 if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) { 4024 xmlChar *tmp = NULL; 4025 4026 if ((ctxt != NULL) && (ctxt->catalogs != NULL) && 4027 ((pref == XML_CATA_ALLOW_ALL) || 4028 (pref == XML_CATA_ALLOW_DOCUMENT))) { 4029 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource); 4030 } 4031 if ((tmp == NULL) && 4032 ((pref == XML_CATA_ALLOW_ALL) || 4033 (pref == XML_CATA_ALLOW_GLOBAL))) { 4034 tmp = xmlCatalogResolveURI(resource); 4035 } 4036 4037 if (tmp != NULL) { 4038 xmlFree(resource); 4039 resource = tmp; 4040 } 4041 } 4042 } 4043 4044 return resource; 4045 } 4046 4047 #endif 4048 4049 /** 4050 * xmlDefaultExternalEntityLoader: 4051 * @URL: the URL for the entity to load 4052 * @ID: the System ID for the entity to load 4053 * @ctxt: the context in which the entity is called or NULL 4054 * 4055 * By default we don't load external entitites, yet. 4056 * 4057 * Returns a new allocated xmlParserInputPtr, or NULL. 4058 */ 4059 static xmlParserInputPtr 4060 xmlDefaultExternalEntityLoader(const char *URL, const char *ID, 4061 xmlParserCtxtPtr ctxt) 4062 { 4063 xmlParserInputPtr ret = NULL; 4064 xmlChar *resource = NULL; 4065 4066 #ifdef DEBUG_EXTERNAL_ENTITIES 4067 xmlGenericError(xmlGenericErrorContext, 4068 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL); 4069 #endif 4070 if ((ctxt != NULL) && (ctxt->options & XML_PARSE_NONET)) { 4071 int options = ctxt->options; 4072 4073 ctxt->options -= XML_PARSE_NONET; 4074 ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt); 4075 ctxt->options = options; 4076 return(ret); 4077 } 4078 #ifdef LIBXML_CATALOG_ENABLED 4079 resource = xmlResolveResourceFromCatalog(URL, ID, ctxt); 4080 #endif 4081 4082 if (resource == NULL) 4083 resource = (xmlChar *) URL; 4084 4085 if (resource == NULL) { 4086 if (ID == NULL) 4087 ID = "NULL"; 4088 __xmlLoaderErr(ctxt, "failed to load external entity \"%s\"\n", ID); 4089 return (NULL); 4090 } 4091 ret = xmlNewInputFromFile(ctxt, (const char *) resource); 4092 if ((resource != NULL) && (resource != (xmlChar *) URL)) 4093 xmlFree(resource); 4094 return (ret); 4095 } 4096 4097 static xmlExternalEntityLoader xmlCurrentExternalEntityLoader = 4098 xmlDefaultExternalEntityLoader; 4099 4100 /** 4101 * xmlSetExternalEntityLoader: 4102 * @f: the new entity resolver function 4103 * 4104 * Changes the defaultexternal entity resolver function for the application 4105 */ 4106 void 4107 xmlSetExternalEntityLoader(xmlExternalEntityLoader f) { 4108 xmlCurrentExternalEntityLoader = f; 4109 } 4110 4111 /** 4112 * xmlGetExternalEntityLoader: 4113 * 4114 * Get the default external entity resolver function for the application 4115 * 4116 * Returns the xmlExternalEntityLoader function pointer 4117 */ 4118 xmlExternalEntityLoader 4119 xmlGetExternalEntityLoader(void) { 4120 return(xmlCurrentExternalEntityLoader); 4121 } 4122 4123 /** 4124 * xmlLoadExternalEntity: 4125 * @URL: the URL for the entity to load 4126 * @ID: the Public ID for the entity to load 4127 * @ctxt: the context in which the entity is called or NULL 4128 * 4129 * Load an external entity, note that the use of this function for 4130 * unparsed entities may generate problems 4131 * 4132 * Returns the xmlParserInputPtr or NULL 4133 */ 4134 xmlParserInputPtr 4135 xmlLoadExternalEntity(const char *URL, const char *ID, 4136 xmlParserCtxtPtr ctxt) { 4137 if ((URL != NULL) && (xmlNoNetExists(URL) == 0)) { 4138 char *canonicFilename; 4139 xmlParserInputPtr ret; 4140 4141 canonicFilename = (char *) xmlCanonicPath((const xmlChar *) URL); 4142 if (canonicFilename == NULL) { 4143 xmlIOErrMemory("building canonical path\n"); 4144 return(NULL); 4145 } 4146 4147 ret = xmlCurrentExternalEntityLoader(canonicFilename, ID, ctxt); 4148 xmlFree(canonicFilename); 4149 return(ret); 4150 } 4151 return(xmlCurrentExternalEntityLoader(URL, ID, ctxt)); 4152 } 4153 4154 /************************************************************************ 4155 * * 4156 * Disabling Network access * 4157 * * 4158 ************************************************************************/ 4159 4160 /** 4161 * xmlNoNetExternalEntityLoader: 4162 * @URL: the URL for the entity to load 4163 * @ID: the System ID for the entity to load 4164 * @ctxt: the context in which the entity is called or NULL 4165 * 4166 * A specific entity loader disabling network accesses, though still 4167 * allowing local catalog accesses for resolution. 4168 * 4169 * Returns a new allocated xmlParserInputPtr, or NULL. 4170 */ 4171 xmlParserInputPtr 4172 xmlNoNetExternalEntityLoader(const char *URL, const char *ID, 4173 xmlParserCtxtPtr ctxt) { 4174 xmlParserInputPtr input = NULL; 4175 xmlChar *resource = NULL; 4176 4177 #ifdef LIBXML_CATALOG_ENABLED 4178 resource = xmlResolveResourceFromCatalog(URL, ID, ctxt); 4179 #endif 4180 4181 if (resource == NULL) 4182 resource = (xmlChar *) URL; 4183 4184 if (resource != NULL) { 4185 if ((!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "ftp://", 6)) || 4186 (!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "http://", 7))) { 4187 xmlIOErr(XML_IO_NETWORK_ATTEMPT, (const char *) resource); 4188 if (resource != (xmlChar *) URL) 4189 xmlFree(resource); 4190 return(NULL); 4191 } 4192 } 4193 input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt); 4194 if (resource != (xmlChar *) URL) 4195 xmlFree(resource); 4196 return(input); 4197 } 4198 4199 #define bottom_xmlIO 4200 #include "elfgcchack.h"