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