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