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