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