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