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