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