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