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