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