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