1 /* 2 * xmlIO.c : implementation of the I/O interfaces used by the parser 3 * 4 * See Copyright for the status of this software. 5 * 6 * daniel@veillard.com 7 * 8 * 14 Nov 2000 ht - for VMS, truncated name of long functions to under 32 char 9 */ 10 11 #define IN_LIBXML 12 #include "libxml.h" 13 14 #include <string.h> 15 #include <stddef.h> 16 #ifdef HAVE_ERRNO_H 17 #include <errno.h> 18 #endif 19 20 21 #ifdef HAVE_SYS_TYPES_H 22 #include <sys/types.h> 23 #endif 24 #ifdef HAVE_SYS_STAT_H 25 #include <sys/stat.h> 26 #endif 27 #ifdef HAVE_FCNTL_H 28 #include <fcntl.h> 29 #endif 30 #ifdef HAVE_UNISTD_H 31 #include <unistd.h> 32 #endif 33 #ifdef HAVE_STDLIB_H 34 #include <stdlib.h> 35 #endif 36 #ifdef LIBXML_ZLIB_ENABLED 37 #include <zlib.h> 38 #endif 39 #ifdef LIBXML_LZMA_ENABLED 40 #include <lzma.h> 41 #endif 42 43 #if defined(_WIN32) && !defined(__CYGWIN__) 44 #ifdef __REACTOS__ 45 #include <winnls.h> 46 #else /* __REACTOS__ */ 47 #define WIN32_LEAN_AND_MEAN 48 #include <windows.h> 49 #endif /* __REACTOS__ */ 50 #endif 51 52 #if defined(_WIN32_WCE) 53 #include <winnls.h> /* for CP_UTF8 */ 54 #endif 55 56 #ifndef S_ISDIR 57 # ifdef _S_ISDIR 58 # define S_ISDIR(x) _S_ISDIR(x) 59 # elif defined(S_IFDIR) 60 # ifdef S_IFMT 61 # define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) 62 # elif defined(_S_IFMT) 63 # define S_ISDIR(m) (((m) & _S_IFMT) == S_IFDIR) 64 # endif 65 # endif 66 #endif 67 68 #include <libxml/xmlmemory.h> 69 #include <libxml/parser.h> 70 #include <libxml/parserInternals.h> 71 #include <libxml/xmlIO.h> 72 #include <libxml/uri.h> 73 #include <libxml/nanohttp.h> 74 #include <libxml/nanoftp.h> 75 #include <libxml/xmlerror.h> 76 #ifdef LIBXML_CATALOG_ENABLED 77 #include <libxml/catalog.h> 78 #endif 79 #include <libxml/globals.h> 80 81 #include "buf.h" 82 #include "enc.h" 83 84 /* #define VERBOSE_FAILURE */ 85 /* #define DEBUG_EXTERNAL_ENTITIES */ 86 /* #define DEBUG_INPUT */ 87 88 #ifdef DEBUG_INPUT 89 #define MINLEN 40 90 #else 91 #define MINLEN 4000 92 #endif 93 94 /* 95 * Input I/O callback sets 96 */ 97 typedef struct _xmlInputCallback { 98 xmlInputMatchCallback matchcallback; 99 xmlInputOpenCallback opencallback; 100 xmlInputReadCallback readcallback; 101 xmlInputCloseCallback closecallback; 102 } xmlInputCallback; 103 104 #define MAX_INPUT_CALLBACK 15 105 106 static xmlInputCallback xmlInputCallbackTable[MAX_INPUT_CALLBACK]; 107 static int xmlInputCallbackNr = 0; 108 static int xmlInputCallbackInitialized = 0; 109 110 #ifdef LIBXML_OUTPUT_ENABLED 111 /* 112 * Output I/O callback sets 113 */ 114 typedef struct _xmlOutputCallback { 115 xmlOutputMatchCallback matchcallback; 116 xmlOutputOpenCallback opencallback; 117 xmlOutputWriteCallback writecallback; 118 xmlOutputCloseCallback closecallback; 119 } xmlOutputCallback; 120 121 #define MAX_OUTPUT_CALLBACK 15 122 123 static xmlOutputCallback xmlOutputCallbackTable[MAX_OUTPUT_CALLBACK]; 124 static int xmlOutputCallbackNr = 0; 125 static int xmlOutputCallbackInitialized = 0; 126 127 xmlOutputBufferPtr 128 xmlAllocOutputBufferInternal(xmlCharEncodingHandlerPtr encoder); 129 #endif /* LIBXML_OUTPUT_ENABLED */ 130 131 /************************************************************************ 132 * * 133 * Tree memory error handler * 134 * * 135 ************************************************************************/ 136 137 static const char *IOerr[] = { 138 "Unknown IO error", /* UNKNOWN */ 139 "Permission denied", /* EACCES */ 140 "Resource temporarily unavailable",/* EAGAIN */ 141 "Bad file descriptor", /* EBADF */ 142 "Bad message", /* EBADMSG */ 143 "Resource busy", /* EBUSY */ 144 "Operation canceled", /* ECANCELED */ 145 "No child processes", /* ECHILD */ 146 "Resource deadlock avoided",/* EDEADLK */ 147 "Domain error", /* EDOM */ 148 "File exists", /* EEXIST */ 149 "Bad address", /* EFAULT */ 150 "File too large", /* EFBIG */ 151 "Operation in progress", /* EINPROGRESS */ 152 "Interrupted function call",/* EINTR */ 153 "Invalid argument", /* EINVAL */ 154 "Input/output error", /* EIO */ 155 "Is a directory", /* EISDIR */ 156 "Too many open files", /* EMFILE */ 157 "Too many links", /* EMLINK */ 158 "Inappropriate message buffer length",/* EMSGSIZE */ 159 "Filename too long", /* ENAMETOOLONG */ 160 "Too many open files in system",/* ENFILE */ 161 "No such device", /* ENODEV */ 162 "No such file or directory",/* ENOENT */ 163 "Exec format error", /* ENOEXEC */ 164 "No locks available", /* ENOLCK */ 165 "Not enough space", /* ENOMEM */ 166 "No space left on device", /* ENOSPC */ 167 "Function not implemented", /* ENOSYS */ 168 "Not a directory", /* ENOTDIR */ 169 "Directory not empty", /* ENOTEMPTY */ 170 "Not supported", /* ENOTSUP */ 171 "Inappropriate I/O control operation",/* ENOTTY */ 172 "No such device or address",/* ENXIO */ 173 "Operation not permitted", /* EPERM */ 174 "Broken pipe", /* EPIPE */ 175 "Result too large", /* ERANGE */ 176 "Read-only file system", /* EROFS */ 177 "Invalid seek", /* ESPIPE */ 178 "No such process", /* ESRCH */ 179 "Operation timed out", /* ETIMEDOUT */ 180 "Improper link", /* EXDEV */ 181 "Attempt to load network entity %s", /* XML_IO_NETWORK_ATTEMPT */ 182 "encoder error", /* XML_IO_ENCODER */ 183 "flush error", 184 "write error", 185 "no input", 186 "buffer full", 187 "loading error", 188 "not a socket", /* ENOTSOCK */ 189 "already connected", /* EISCONN */ 190 "connection refused", /* ECONNREFUSED */ 191 "unreachable network", /* ENETUNREACH */ 192 "address in use", /* EADDRINUSE */ 193 "already in use", /* EALREADY */ 194 "unknown address family", /* EAFNOSUPPORT */ 195 }; 196 197 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__) 198 /** 199 * __xmlIOWin32UTF8ToWChar: 200 * @u8String: uft-8 string 201 * 202 * Convert a string from utf-8 to wchar (WINDOWS ONLY!) 203 */ 204 static wchar_t * 205 __xmlIOWin32UTF8ToWChar(const char *u8String) 206 { 207 wchar_t *wString = NULL; 208 209 if (u8String) { 210 int wLen = 211 MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, u8String, 212 -1, NULL, 0); 213 if (wLen) { 214 wString = xmlMalloc(wLen * sizeof(wchar_t)); 215 if (wString) { 216 if (MultiByteToWideChar 217 (CP_UTF8, 0, u8String, -1, wString, wLen) == 0) { 218 xmlFree(wString); 219 wString = NULL; 220 } 221 } 222 } 223 } 224 225 return wString; 226 } 227 #endif 228 229 /** 230 * xmlIOErrMemory: 231 * @extra: extra 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 xmlBufFree(ret->buffer); 2391 xmlFree(ret); 2392 return(NULL); 2393 } 2394 2395 /* 2396 * This call is designed to initiate the encoder state 2397 */ 2398 xmlCharEncOutput(ret, 1); 2399 } else 2400 ret->conv = NULL; 2401 ret->writecallback = NULL; 2402 ret->closecallback = NULL; 2403 ret->context = NULL; 2404 ret->written = 0; 2405 2406 return(ret); 2407 } 2408 2409 /** 2410 * xmlAllocOutputBufferInternal: 2411 * @encoder: the encoding converter or NULL 2412 * 2413 * Create a buffered parser output 2414 * 2415 * Returns the new parser output or NULL 2416 */ 2417 xmlOutputBufferPtr 2418 xmlAllocOutputBufferInternal(xmlCharEncodingHandlerPtr encoder) { 2419 xmlOutputBufferPtr ret; 2420 2421 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer)); 2422 if (ret == NULL) { 2423 xmlIOErrMemory("creating output buffer"); 2424 return(NULL); 2425 } 2426 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer)); 2427 ret->buffer = xmlBufCreate(); 2428 if (ret->buffer == NULL) { 2429 xmlFree(ret); 2430 return(NULL); 2431 } 2432 2433 2434 /* 2435 * For conversion buffers we use the special IO handling 2436 */ 2437 xmlBufSetAllocationScheme(ret->buffer, XML_BUFFER_ALLOC_IO); 2438 2439 ret->encoder = encoder; 2440 if (encoder != NULL) { 2441 ret->conv = xmlBufCreateSize(4000); 2442 if (ret->conv == NULL) { 2443 xmlBufFree(ret->buffer); 2444 xmlFree(ret); 2445 return(NULL); 2446 } 2447 2448 /* 2449 * This call is designed to initiate the encoder state 2450 */ 2451 xmlCharEncOutput(ret, 1); 2452 } else 2453 ret->conv = NULL; 2454 ret->writecallback = NULL; 2455 ret->closecallback = NULL; 2456 ret->context = NULL; 2457 ret->written = 0; 2458 2459 return(ret); 2460 } 2461 2462 #endif /* LIBXML_OUTPUT_ENABLED */ 2463 2464 /** 2465 * xmlFreeParserInputBuffer: 2466 * @in: a buffered parser input 2467 * 2468 * Free up the memory used by a buffered parser input 2469 */ 2470 void 2471 xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) { 2472 if (in == NULL) return; 2473 2474 if (in->raw) { 2475 xmlBufFree(in->raw); 2476 in->raw = NULL; 2477 } 2478 if (in->encoder != NULL) { 2479 xmlCharEncCloseFunc(in->encoder); 2480 } 2481 if (in->closecallback != NULL) { 2482 in->closecallback(in->context); 2483 } 2484 if (in->buffer != NULL) { 2485 xmlBufFree(in->buffer); 2486 in->buffer = NULL; 2487 } 2488 2489 xmlFree(in); 2490 } 2491 2492 #ifdef LIBXML_OUTPUT_ENABLED 2493 /** 2494 * xmlOutputBufferClose: 2495 * @out: a buffered output 2496 * 2497 * flushes and close the output I/O channel 2498 * and free up all the associated resources 2499 * 2500 * Returns the number of byte written or -1 in case of error. 2501 */ 2502 int 2503 xmlOutputBufferClose(xmlOutputBufferPtr out) 2504 { 2505 int written; 2506 int err_rc = 0; 2507 2508 if (out == NULL) 2509 return (-1); 2510 if (out->writecallback != NULL) 2511 xmlOutputBufferFlush(out); 2512 if (out->closecallback != NULL) { 2513 err_rc = out->closecallback(out->context); 2514 } 2515 written = out->written; 2516 if (out->conv) { 2517 xmlBufFree(out->conv); 2518 out->conv = NULL; 2519 } 2520 if (out->encoder != NULL) { 2521 xmlCharEncCloseFunc(out->encoder); 2522 } 2523 if (out->buffer != NULL) { 2524 xmlBufFree(out->buffer); 2525 out->buffer = NULL; 2526 } 2527 2528 if (out->error) 2529 err_rc = -1; 2530 xmlFree(out); 2531 return ((err_rc == 0) ? written : err_rc); 2532 } 2533 #endif /* LIBXML_OUTPUT_ENABLED */ 2534 2535 xmlParserInputBufferPtr 2536 __xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) { 2537 xmlParserInputBufferPtr ret; 2538 int i = 0; 2539 void *context = NULL; 2540 2541 if (xmlInputCallbackInitialized == 0) 2542 xmlRegisterDefaultInputCallbacks(); 2543 2544 if (URI == NULL) return(NULL); 2545 2546 /* 2547 * Try to find one of the input accept method accepting that scheme 2548 * Go in reverse to give precedence to user defined handlers. 2549 */ 2550 if (context == NULL) { 2551 for (i = xmlInputCallbackNr - 1;i >= 0;i--) { 2552 if ((xmlInputCallbackTable[i].matchcallback != NULL) && 2553 (xmlInputCallbackTable[i].matchcallback(URI) != 0)) { 2554 context = xmlInputCallbackTable[i].opencallback(URI); 2555 if (context != NULL) { 2556 break; 2557 } 2558 } 2559 } 2560 } 2561 if (context == NULL) { 2562 return(NULL); 2563 } 2564 2565 /* 2566 * Allocate the Input buffer front-end. 2567 */ 2568 ret = xmlAllocParserInputBuffer(enc); 2569 if (ret != NULL) { 2570 ret->context = context; 2571 ret->readcallback = xmlInputCallbackTable[i].readcallback; 2572 ret->closecallback = xmlInputCallbackTable[i].closecallback; 2573 #ifdef LIBXML_ZLIB_ENABLED 2574 if ((xmlInputCallbackTable[i].opencallback == xmlGzfileOpen) && 2575 (strcmp(URI, "-") != 0)) { 2576 #if defined(ZLIB_VERNUM) && ZLIB_VERNUM >= 0x1230 2577 ret->compressed = !gzdirect(context); 2578 #else 2579 if (((z_stream *)context)->avail_in > 4) { 2580 char *cptr, buff4[4]; 2581 cptr = (char *) ((z_stream *)context)->next_in; 2582 if (gzread(context, buff4, 4) == 4) { 2583 if (strncmp(buff4, cptr, 4) == 0) 2584 ret->compressed = 0; 2585 else 2586 ret->compressed = 1; 2587 gzrewind(context); 2588 } 2589 } 2590 #endif 2591 } 2592 #endif 2593 #ifdef LIBXML_LZMA_ENABLED 2594 if ((xmlInputCallbackTable[i].opencallback == xmlXzfileOpen) && 2595 (strcmp(URI, "-") != 0)) { 2596 ret->compressed = __libxml2_xzcompressed(context); 2597 } 2598 #endif 2599 } 2600 else 2601 xmlInputCallbackTable[i].closecallback (context); 2602 2603 return(ret); 2604 } 2605 2606 /** 2607 * xmlParserInputBufferCreateFilename: 2608 * @URI: a C string containing the URI or filename 2609 * @enc: the charset encoding if known 2610 * 2611 * Create a buffered parser input for the progressive parsing of a file 2612 * If filename is "-' then we use stdin as the input. 2613 * Automatic support for ZLIB/Compress compressed document is provided 2614 * by default if found at compile-time. 2615 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE 2616 * 2617 * Returns the new parser input or NULL 2618 */ 2619 xmlParserInputBufferPtr 2620 xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) { 2621 if ((xmlParserInputBufferCreateFilenameValue)) { 2622 return xmlParserInputBufferCreateFilenameValue(URI, enc); 2623 } 2624 return __xmlParserInputBufferCreateFilename(URI, enc); 2625 } 2626 2627 #ifdef LIBXML_OUTPUT_ENABLED 2628 xmlOutputBufferPtr 2629 __xmlOutputBufferCreateFilename(const char *URI, 2630 xmlCharEncodingHandlerPtr encoder, 2631 int compression ATTRIBUTE_UNUSED) { 2632 xmlOutputBufferPtr ret; 2633 xmlURIPtr puri; 2634 int i = 0; 2635 void *context = NULL; 2636 char *unescaped = NULL; 2637 #ifdef LIBXML_ZLIB_ENABLED 2638 int is_file_uri = 1; 2639 #endif 2640 2641 if (xmlOutputCallbackInitialized == 0) 2642 xmlRegisterDefaultOutputCallbacks(); 2643 2644 if (URI == NULL) return(NULL); 2645 2646 puri = xmlParseURI(URI); 2647 if (puri != NULL) { 2648 #ifdef LIBXML_ZLIB_ENABLED 2649 if ((puri->scheme != NULL) && 2650 (!xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file"))) 2651 is_file_uri = 0; 2652 #endif 2653 /* 2654 * try to limit the damages of the URI unescaping code. 2655 */ 2656 if ((puri->scheme == NULL) || 2657 (xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file"))) 2658 unescaped = xmlURIUnescapeString(URI, 0, NULL); 2659 xmlFreeURI(puri); 2660 } 2661 2662 /* 2663 * Try to find one of the output accept method accepting that scheme 2664 * Go in reverse to give precedence to user defined handlers. 2665 * try with an unescaped version of the URI 2666 */ 2667 if (unescaped != NULL) { 2668 #ifdef LIBXML_ZLIB_ENABLED 2669 if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) { 2670 context = xmlGzfileOpenW(unescaped, compression); 2671 if (context != NULL) { 2672 ret = xmlAllocOutputBufferInternal(encoder); 2673 if (ret != NULL) { 2674 ret->context = context; 2675 ret->writecallback = xmlGzfileWrite; 2676 ret->closecallback = xmlGzfileClose; 2677 } 2678 xmlFree(unescaped); 2679 return(ret); 2680 } 2681 } 2682 #endif 2683 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) { 2684 if ((xmlOutputCallbackTable[i].matchcallback != NULL) && 2685 (xmlOutputCallbackTable[i].matchcallback(unescaped) != 0)) { 2686 #if defined(LIBXML_HTTP_ENABLED) && defined(LIBXML_ZLIB_ENABLED) 2687 /* Need to pass compression parameter into HTTP open calls */ 2688 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch) 2689 context = xmlIOHTTPOpenW(unescaped, compression); 2690 else 2691 #endif 2692 context = xmlOutputCallbackTable[i].opencallback(unescaped); 2693 if (context != NULL) 2694 break; 2695 } 2696 } 2697 xmlFree(unescaped); 2698 } 2699 2700 /* 2701 * If this failed try with a non-escaped URI this may be a strange 2702 * filename 2703 */ 2704 if (context == NULL) { 2705 #ifdef LIBXML_ZLIB_ENABLED 2706 if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) { 2707 context = xmlGzfileOpenW(URI, compression); 2708 if (context != NULL) { 2709 ret = xmlAllocOutputBufferInternal(encoder); 2710 if (ret != NULL) { 2711 ret->context = context; 2712 ret->writecallback = xmlGzfileWrite; 2713 ret->closecallback = xmlGzfileClose; 2714 } 2715 return(ret); 2716 } 2717 } 2718 #endif 2719 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) { 2720 if ((xmlOutputCallbackTable[i].matchcallback != NULL) && 2721 (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) { 2722 #if defined(LIBXML_HTTP_ENABLED) && defined(LIBXML_ZLIB_ENABLED) 2723 /* Need to pass compression parameter into HTTP open calls */ 2724 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch) 2725 context = xmlIOHTTPOpenW(URI, compression); 2726 else 2727 #endif 2728 context = xmlOutputCallbackTable[i].opencallback(URI); 2729 if (context != NULL) 2730 break; 2731 } 2732 } 2733 } 2734 2735 if (context == NULL) { 2736 return(NULL); 2737 } 2738 2739 /* 2740 * Allocate the Output buffer front-end. 2741 */ 2742 ret = xmlAllocOutputBufferInternal(encoder); 2743 if (ret != NULL) { 2744 ret->context = context; 2745 ret->writecallback = xmlOutputCallbackTable[i].writecallback; 2746 ret->closecallback = xmlOutputCallbackTable[i].closecallback; 2747 } 2748 return(ret); 2749 } 2750 2751 /** 2752 * xmlOutputBufferCreateFilename: 2753 * @URI: a C string containing the URI or filename 2754 * @encoder: the encoding converter or NULL 2755 * @compression: the compression ration (0 none, 9 max). 2756 * 2757 * Create a buffered output for the progressive saving of a file 2758 * If filename is "-' then we use stdout as the output. 2759 * Automatic support for ZLIB/Compress compressed document is provided 2760 * by default if found at compile-time. 2761 * TODO: currently if compression is set, the library only support 2762 * writing to a local file. 2763 * 2764 * Returns the new output or NULL 2765 */ 2766 xmlOutputBufferPtr 2767 xmlOutputBufferCreateFilename(const char *URI, 2768 xmlCharEncodingHandlerPtr encoder, 2769 int compression ATTRIBUTE_UNUSED) { 2770 if ((xmlOutputBufferCreateFilenameValue)) { 2771 return xmlOutputBufferCreateFilenameValue(URI, encoder, compression); 2772 } 2773 return __xmlOutputBufferCreateFilename(URI, encoder, compression); 2774 } 2775 #endif /* LIBXML_OUTPUT_ENABLED */ 2776 2777 /** 2778 * xmlParserInputBufferCreateFile: 2779 * @file: a FILE* 2780 * @enc: the charset encoding if known 2781 * 2782 * Create a buffered parser input for the progressive parsing of a FILE * 2783 * buffered C I/O 2784 * 2785 * Returns the new parser input or NULL 2786 */ 2787 xmlParserInputBufferPtr 2788 xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) { 2789 xmlParserInputBufferPtr ret; 2790 2791 if (xmlInputCallbackInitialized == 0) 2792 xmlRegisterDefaultInputCallbacks(); 2793 2794 if (file == NULL) return(NULL); 2795 2796 ret = xmlAllocParserInputBuffer(enc); 2797 if (ret != NULL) { 2798 ret->context = file; 2799 ret->readcallback = xmlFileRead; 2800 ret->closecallback = xmlFileFlush; 2801 } 2802 2803 return(ret); 2804 } 2805 2806 #ifdef LIBXML_OUTPUT_ENABLED 2807 /** 2808 * xmlOutputBufferCreateFile: 2809 * @file: a FILE* 2810 * @encoder: the encoding converter or NULL 2811 * 2812 * Create a buffered output for the progressive saving to a FILE * 2813 * buffered C I/O 2814 * 2815 * Returns the new parser output or NULL 2816 */ 2817 xmlOutputBufferPtr 2818 xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) { 2819 xmlOutputBufferPtr ret; 2820 2821 if (xmlOutputCallbackInitialized == 0) 2822 xmlRegisterDefaultOutputCallbacks(); 2823 2824 if (file == NULL) return(NULL); 2825 2826 ret = xmlAllocOutputBufferInternal(encoder); 2827 if (ret != NULL) { 2828 ret->context = file; 2829 ret->writecallback = xmlFileWrite; 2830 ret->closecallback = xmlFileFlush; 2831 } 2832 2833 return(ret); 2834 } 2835 2836 /** 2837 * xmlOutputBufferCreateBuffer: 2838 * @buffer: a xmlBufferPtr 2839 * @encoder: the encoding converter or NULL 2840 * 2841 * Create a buffered output for the progressive saving to a xmlBuffer 2842 * 2843 * Returns the new parser output or NULL 2844 */ 2845 xmlOutputBufferPtr 2846 xmlOutputBufferCreateBuffer(xmlBufferPtr buffer, 2847 xmlCharEncodingHandlerPtr encoder) { 2848 xmlOutputBufferPtr ret; 2849 2850 if (buffer == NULL) return(NULL); 2851 2852 ret = xmlOutputBufferCreateIO(xmlBufferWrite, NULL, (void *) buffer, 2853 encoder); 2854 2855 return(ret); 2856 } 2857 2858 /** 2859 * xmlOutputBufferGetContent: 2860 * @out: an xmlOutputBufferPtr 2861 * 2862 * Gives a pointer to the data currently held in the output buffer 2863 * 2864 * Returns a pointer to the data or NULL in case of error 2865 */ 2866 const xmlChar * 2867 xmlOutputBufferGetContent(xmlOutputBufferPtr out) { 2868 if ((out == NULL) || (out->buffer == NULL)) 2869 return(NULL); 2870 2871 return(xmlBufContent(out->buffer)); 2872 } 2873 2874 /** 2875 * xmlOutputBufferGetSize: 2876 * @out: an xmlOutputBufferPtr 2877 * 2878 * Gives the length of the data currently held in the output buffer 2879 * 2880 * Returns 0 in case or error or no data is held, the size otherwise 2881 */ 2882 size_t 2883 xmlOutputBufferGetSize(xmlOutputBufferPtr out) { 2884 if ((out == NULL) || (out->buffer == NULL)) 2885 return(0); 2886 2887 return(xmlBufUse(out->buffer)); 2888 } 2889 2890 2891 #endif /* LIBXML_OUTPUT_ENABLED */ 2892 2893 /** 2894 * xmlParserInputBufferCreateFd: 2895 * @fd: a file descriptor number 2896 * @enc: the charset encoding if known 2897 * 2898 * Create a buffered parser input for the progressive parsing for the input 2899 * from a file descriptor 2900 * 2901 * Returns the new parser input or NULL 2902 */ 2903 xmlParserInputBufferPtr 2904 xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) { 2905 xmlParserInputBufferPtr ret; 2906 2907 if (fd < 0) return(NULL); 2908 2909 ret = xmlAllocParserInputBuffer(enc); 2910 if (ret != NULL) { 2911 ret->context = (void *) (ptrdiff_t) fd; 2912 ret->readcallback = xmlFdRead; 2913 ret->closecallback = xmlFdClose; 2914 } 2915 2916 return(ret); 2917 } 2918 2919 /** 2920 * xmlParserInputBufferCreateMem: 2921 * @mem: the memory input 2922 * @size: the length of the memory block 2923 * @enc: the charset encoding if known 2924 * 2925 * Create a buffered parser input for the progressive parsing for the input 2926 * from a memory area. 2927 * 2928 * Returns the new parser input or NULL 2929 */ 2930 xmlParserInputBufferPtr 2931 xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) { 2932 xmlParserInputBufferPtr ret; 2933 int errcode; 2934 2935 if (size < 0) return(NULL); 2936 if (mem == NULL) return(NULL); 2937 2938 ret = xmlAllocParserInputBuffer(enc); 2939 if (ret != NULL) { 2940 ret->context = (void *) mem; 2941 ret->readcallback = xmlInputReadCallbackNop; 2942 ret->closecallback = NULL; 2943 errcode = xmlBufAdd(ret->buffer, (const xmlChar *) mem, size); 2944 if (errcode != 0) { 2945 xmlFree(ret); 2946 return(NULL); 2947 } 2948 } 2949 2950 return(ret); 2951 } 2952 2953 /** 2954 * xmlParserInputBufferCreateStatic: 2955 * @mem: the memory input 2956 * @size: the length of the memory block 2957 * @enc: the charset encoding if known 2958 * 2959 * Create a buffered parser input for the progressive parsing for the input 2960 * from an immutable memory area. This will not copy the memory area to 2961 * the buffer, but the memory is expected to be available until the end of 2962 * the parsing, this is useful for example when using mmap'ed file. 2963 * 2964 * Returns the new parser input or NULL 2965 */ 2966 xmlParserInputBufferPtr 2967 xmlParserInputBufferCreateStatic(const char *mem, int size, 2968 xmlCharEncoding enc) { 2969 xmlParserInputBufferPtr ret; 2970 2971 if (size < 0) return(NULL); 2972 if (mem == NULL) return(NULL); 2973 2974 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer)); 2975 if (ret == NULL) { 2976 xmlIOErrMemory("creating input buffer"); 2977 return(NULL); 2978 } 2979 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer)); 2980 ret->buffer = xmlBufCreateStatic((void *)mem, (size_t) size); 2981 if (ret->buffer == NULL) { 2982 xmlFree(ret); 2983 return(NULL); 2984 } 2985 ret->encoder = xmlGetCharEncodingHandler(enc); 2986 if (ret->encoder != NULL) 2987 ret->raw = xmlBufCreateSize(2 * xmlDefaultBufferSize); 2988 else 2989 ret->raw = NULL; 2990 ret->compressed = -1; 2991 ret->context = (void *) mem; 2992 ret->readcallback = NULL; 2993 ret->closecallback = NULL; 2994 2995 return(ret); 2996 } 2997 2998 #ifdef LIBXML_OUTPUT_ENABLED 2999 /** 3000 * xmlOutputBufferCreateFd: 3001 * @fd: a file descriptor number 3002 * @encoder: the encoding converter or NULL 3003 * 3004 * Create a buffered output for the progressive saving 3005 * to a file descriptor 3006 * 3007 * Returns the new parser output or NULL 3008 */ 3009 xmlOutputBufferPtr 3010 xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) { 3011 xmlOutputBufferPtr ret; 3012 3013 if (fd < 0) return(NULL); 3014 3015 ret = xmlAllocOutputBufferInternal(encoder); 3016 if (ret != NULL) { 3017 ret->context = (void *) (ptrdiff_t) fd; 3018 ret->writecallback = xmlFdWrite; 3019 ret->closecallback = NULL; 3020 } 3021 3022 return(ret); 3023 } 3024 #endif /* LIBXML_OUTPUT_ENABLED */ 3025 3026 /** 3027 * xmlParserInputBufferCreateIO: 3028 * @ioread: an I/O read function 3029 * @ioclose: an I/O close function 3030 * @ioctx: an I/O handler 3031 * @enc: the charset encoding if known 3032 * 3033 * Create a buffered parser input for the progressive parsing for the input 3034 * from an I/O handler 3035 * 3036 * Returns the new parser input or NULL 3037 */ 3038 xmlParserInputBufferPtr 3039 xmlParserInputBufferCreateIO(xmlInputReadCallback ioread, 3040 xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) { 3041 xmlParserInputBufferPtr ret; 3042 3043 if (ioread == NULL) return(NULL); 3044 3045 ret = xmlAllocParserInputBuffer(enc); 3046 if (ret != NULL) { 3047 ret->context = (void *) ioctx; 3048 ret->readcallback = ioread; 3049 ret->closecallback = ioclose; 3050 } 3051 3052 return(ret); 3053 } 3054 3055 #ifdef LIBXML_OUTPUT_ENABLED 3056 /** 3057 * xmlOutputBufferCreateIO: 3058 * @iowrite: an I/O write function 3059 * @ioclose: an I/O close function 3060 * @ioctx: an I/O handler 3061 * @encoder: the charset encoding if known 3062 * 3063 * Create a buffered output for the progressive saving 3064 * to an I/O handler 3065 * 3066 * Returns the new parser output or NULL 3067 */ 3068 xmlOutputBufferPtr 3069 xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite, 3070 xmlOutputCloseCallback ioclose, void *ioctx, 3071 xmlCharEncodingHandlerPtr encoder) { 3072 xmlOutputBufferPtr ret; 3073 3074 if (iowrite == NULL) return(NULL); 3075 3076 ret = xmlAllocOutputBufferInternal(encoder); 3077 if (ret != NULL) { 3078 ret->context = (void *) ioctx; 3079 ret->writecallback = iowrite; 3080 ret->closecallback = ioclose; 3081 } 3082 3083 return(ret); 3084 } 3085 #endif /* LIBXML_OUTPUT_ENABLED */ 3086 3087 /** 3088 * xmlParserInputBufferCreateFilenameDefault: 3089 * @func: function pointer to the new ParserInputBufferCreateFilenameFunc 3090 * 3091 * Registers a callback for URI input file handling 3092 * 3093 * Returns the old value of the registration function 3094 */ 3095 xmlParserInputBufferCreateFilenameFunc 3096 xmlParserInputBufferCreateFilenameDefault(xmlParserInputBufferCreateFilenameFunc func) 3097 { 3098 xmlParserInputBufferCreateFilenameFunc old = xmlParserInputBufferCreateFilenameValue; 3099 if (old == NULL) { 3100 old = __xmlParserInputBufferCreateFilename; 3101 } 3102 3103 xmlParserInputBufferCreateFilenameValue = func; 3104 return(old); 3105 } 3106 3107 /** 3108 * xmlOutputBufferCreateFilenameDefault: 3109 * @func: function pointer to the new OutputBufferCreateFilenameFunc 3110 * 3111 * Registers a callback for URI output file handling 3112 * 3113 * Returns the old value of the registration function 3114 */ 3115 xmlOutputBufferCreateFilenameFunc 3116 xmlOutputBufferCreateFilenameDefault(xmlOutputBufferCreateFilenameFunc func) 3117 { 3118 xmlOutputBufferCreateFilenameFunc old = xmlOutputBufferCreateFilenameValue; 3119 #ifdef LIBXML_OUTPUT_ENABLED 3120 if (old == NULL) { 3121 old = __xmlOutputBufferCreateFilename; 3122 } 3123 #endif 3124 xmlOutputBufferCreateFilenameValue = func; 3125 return(old); 3126 } 3127 3128 /** 3129 * xmlParserInputBufferPush: 3130 * @in: a buffered parser input 3131 * @len: the size in bytes of the array. 3132 * @buf: an char array 3133 * 3134 * Push the content of the arry in the input buffer 3135 * This routine handle the I18N transcoding to internal UTF-8 3136 * This is used when operating the parser in progressive (push) mode. 3137 * 3138 * Returns the number of chars read and stored in the buffer, or -1 3139 * in case of error. 3140 */ 3141 int 3142 xmlParserInputBufferPush(xmlParserInputBufferPtr in, 3143 int len, const char *buf) { 3144 int nbchars = 0; 3145 int ret; 3146 3147 if (len < 0) return(0); 3148 if ((in == NULL) || (in->error)) return(-1); 3149 if (in->encoder != NULL) { 3150 unsigned int use; 3151 3152 /* 3153 * Store the data in the incoming raw buffer 3154 */ 3155 if (in->raw == NULL) { 3156 in->raw = xmlBufCreate(); 3157 } 3158 ret = xmlBufAdd(in->raw, (const xmlChar *) buf, len); 3159 if (ret != 0) 3160 return(-1); 3161 3162 /* 3163 * convert as much as possible to the parser reading buffer. 3164 */ 3165 use = xmlBufUse(in->raw); 3166 nbchars = xmlCharEncInput(in, 1); 3167 if (nbchars < 0) { 3168 xmlIOErr(XML_IO_ENCODER, NULL); 3169 in->error = XML_IO_ENCODER; 3170 return(-1); 3171 } 3172 in->rawconsumed += (use - xmlBufUse(in->raw)); 3173 } else { 3174 nbchars = len; 3175 ret = xmlBufAdd(in->buffer, (xmlChar *) buf, nbchars); 3176 if (ret != 0) 3177 return(-1); 3178 } 3179 #ifdef DEBUG_INPUT 3180 xmlGenericError(xmlGenericErrorContext, 3181 "I/O: pushed %d chars, buffer %d/%d\n", 3182 nbchars, xmlBufUse(in->buffer), xmlBufLength(in->buffer)); 3183 #endif 3184 return(nbchars); 3185 } 3186 3187 /** 3188 * endOfInput: 3189 * 3190 * When reading from an Input channel indicated end of file or error 3191 * don't reread from it again. 3192 */ 3193 static int 3194 endOfInput (void * context ATTRIBUTE_UNUSED, 3195 char * buffer ATTRIBUTE_UNUSED, 3196 int len ATTRIBUTE_UNUSED) { 3197 return(0); 3198 } 3199 3200 /** 3201 * xmlParserInputBufferGrow: 3202 * @in: a buffered parser input 3203 * @len: indicative value of the amount of chars to read 3204 * 3205 * Grow up the content of the input buffer, the old data are preserved 3206 * This routine handle the I18N transcoding to internal UTF-8 3207 * This routine is used when operating the parser in normal (pull) mode 3208 * 3209 * TODO: one should be able to remove one extra copy by copying directly 3210 * onto in->buffer or in->raw 3211 * 3212 * Returns the number of chars read and stored in the buffer, or -1 3213 * in case of error. 3214 */ 3215 int 3216 xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) { 3217 char *buffer = NULL; 3218 int res = 0; 3219 int nbchars = 0; 3220 3221 if ((in == NULL) || (in->error)) return(-1); 3222 if ((len <= MINLEN) && (len != 4)) 3223 len = MINLEN; 3224 3225 if (xmlBufAvail(in->buffer) <= 0) { 3226 xmlIOErr(XML_IO_BUFFER_FULL, NULL); 3227 in->error = XML_IO_BUFFER_FULL; 3228 return(-1); 3229 } 3230 3231 if (xmlBufGrow(in->buffer, len + 1) < 0) { 3232 xmlIOErrMemory("growing input buffer"); 3233 in->error = XML_ERR_NO_MEMORY; 3234 return(-1); 3235 } 3236 buffer = (char *)xmlBufEnd(in->buffer); 3237 3238 /* 3239 * Call the read method for this I/O type. 3240 */ 3241 if (in->readcallback != NULL) { 3242 res = in->readcallback(in->context, &buffer[0], len); 3243 if (res <= 0) 3244 in->readcallback = endOfInput; 3245 } else { 3246 xmlIOErr(XML_IO_NO_INPUT, NULL); 3247 in->error = XML_IO_NO_INPUT; 3248 return(-1); 3249 } 3250 if (res < 0) { 3251 return(-1); 3252 } 3253 3254 /* 3255 * try to establish compressed status of input if not done already 3256 */ 3257 if (in->compressed == -1) { 3258 #ifdef LIBXML_LZMA_ENABLED 3259 if (in->readcallback == xmlXzfileRead) 3260 in->compressed = __libxml2_xzcompressed(in->context); 3261 #endif 3262 } 3263 3264 len = res; 3265 if (in->encoder != NULL) { 3266 unsigned int use; 3267 3268 /* 3269 * Store the data in the incoming raw buffer 3270 */ 3271 if (in->raw == NULL) { 3272 in->raw = xmlBufCreate(); 3273 } 3274 res = xmlBufAdd(in->raw, (const xmlChar *) buffer, len); 3275 if (res != 0) 3276 return(-1); 3277 3278 /* 3279 * convert as much as possible to the parser reading buffer. 3280 */ 3281 use = xmlBufUse(in->raw); 3282 nbchars = xmlCharEncInput(in, 1); 3283 if (nbchars < 0) { 3284 xmlIOErr(XML_IO_ENCODER, NULL); 3285 in->error = XML_IO_ENCODER; 3286 return(-1); 3287 } 3288 in->rawconsumed += (use - xmlBufUse(in->raw)); 3289 } else { 3290 nbchars = len; 3291 xmlBufAddLen(in->buffer, nbchars); 3292 } 3293 #ifdef DEBUG_INPUT 3294 xmlGenericError(xmlGenericErrorContext, 3295 "I/O: read %d chars, buffer %d\n", 3296 nbchars, xmlBufUse(in->buffer)); 3297 #endif 3298 return(nbchars); 3299 } 3300 3301 /** 3302 * xmlParserInputBufferRead: 3303 * @in: a buffered parser input 3304 * @len: indicative value of the amount of chars to read 3305 * 3306 * Refresh the content of the input buffer, the old data are considered 3307 * consumed 3308 * This routine handle the I18N transcoding to internal UTF-8 3309 * 3310 * Returns the number of chars read and stored in the buffer, or -1 3311 * in case of error. 3312 */ 3313 int 3314 xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) { 3315 if ((in == NULL) || (in->error)) return(-1); 3316 if (in->readcallback != NULL) 3317 return(xmlParserInputBufferGrow(in, len)); 3318 else if (xmlBufGetAllocationScheme(in->buffer) == XML_BUFFER_ALLOC_IMMUTABLE) 3319 return(0); 3320 else 3321 return(-1); 3322 } 3323 3324 #ifdef LIBXML_OUTPUT_ENABLED 3325 /** 3326 * xmlOutputBufferWrite: 3327 * @out: a buffered parser output 3328 * @len: the size in bytes of the array. 3329 * @buf: an char array 3330 * 3331 * Write the content of the array in the output I/O buffer 3332 * This routine handle the I18N transcoding from internal UTF-8 3333 * The buffer is lossless, i.e. will store in case of partial 3334 * or delayed writes. 3335 * 3336 * Returns the number of chars immediately written, or -1 3337 * in case of error. 3338 */ 3339 int 3340 xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) { 3341 int nbchars = 0; /* number of chars to output to I/O */ 3342 int ret; /* return from function call */ 3343 int written = 0; /* number of char written to I/O so far */ 3344 int chunk; /* number of byte current processed from buf */ 3345 3346 if ((out == NULL) || (out->error)) return(-1); 3347 if (len < 0) return(0); 3348 if (out->error) return(-1); 3349 3350 do { 3351 chunk = len; 3352 if (chunk > 4 * MINLEN) 3353 chunk = 4 * MINLEN; 3354 3355 /* 3356 * first handle encoding stuff. 3357 */ 3358 if (out->encoder != NULL) { 3359 /* 3360 * Store the data in the incoming raw buffer 3361 */ 3362 if (out->conv == NULL) { 3363 out->conv = xmlBufCreate(); 3364 } 3365 ret = xmlBufAdd(out->buffer, (const xmlChar *) buf, chunk); 3366 if (ret != 0) 3367 return(-1); 3368 3369 if ((xmlBufUse(out->buffer) < MINLEN) && (chunk == len)) 3370 goto done; 3371 3372 /* 3373 * convert as much as possible to the parser reading buffer. 3374 */ 3375 ret = xmlCharEncOutput(out, 0); 3376 if ((ret < 0) && (ret != -3)) { 3377 xmlIOErr(XML_IO_ENCODER, NULL); 3378 out->error = XML_IO_ENCODER; 3379 return(-1); 3380 } 3381 if (out->writecallback) 3382 nbchars = xmlBufUse(out->conv); 3383 else 3384 nbchars = ret; 3385 } else { 3386 ret = xmlBufAdd(out->buffer, (const xmlChar *) buf, chunk); 3387 if (ret != 0) 3388 return(-1); 3389 if (out->writecallback) 3390 nbchars = xmlBufUse(out->buffer); 3391 else 3392 nbchars = chunk; 3393 } 3394 buf += chunk; 3395 len -= chunk; 3396 3397 if (out->writecallback) { 3398 if ((nbchars < MINLEN) && (len <= 0)) 3399 goto done; 3400 3401 /* 3402 * second write the stuff to the I/O channel 3403 */ 3404 if (out->encoder != NULL) { 3405 ret = out->writecallback(out->context, 3406 (const char *)xmlBufContent(out->conv), nbchars); 3407 if (ret >= 0) 3408 xmlBufShrink(out->conv, ret); 3409 } else { 3410 ret = out->writecallback(out->context, 3411 (const char *)xmlBufContent(out->buffer), nbchars); 3412 if (ret >= 0) 3413 xmlBufShrink(out->buffer, ret); 3414 } 3415 if (ret < 0) { 3416 xmlIOErr(XML_IO_WRITE, NULL); 3417 out->error = XML_IO_WRITE; 3418 return(ret); 3419 } 3420 if (out->written > INT_MAX - ret) 3421 out->written = INT_MAX; 3422 else 3423 out->written += ret; 3424 } 3425 written += nbchars; 3426 } while (len > 0); 3427 3428 done: 3429 #ifdef DEBUG_INPUT 3430 xmlGenericError(xmlGenericErrorContext, 3431 "I/O: wrote %d chars\n", written); 3432 #endif 3433 return(written); 3434 } 3435 3436 /** 3437 * xmlEscapeContent: 3438 * @out: a pointer to an array of bytes to store the result 3439 * @outlen: the length of @out 3440 * @in: a pointer to an array of unescaped UTF-8 bytes 3441 * @inlen: the length of @in 3442 * 3443 * Take a block of UTF-8 chars in and escape them. 3444 * Returns 0 if success, or -1 otherwise 3445 * The value of @inlen after return is the number of octets consumed 3446 * if the return value is positive, else unpredictable. 3447 * The value of @outlen after return is the number of octets consumed. 3448 */ 3449 static int 3450 xmlEscapeContent(unsigned char* out, int *outlen, 3451 const xmlChar* in, int *inlen) { 3452 unsigned char* outstart = out; 3453 const unsigned char* base = in; 3454 unsigned char* outend = out + *outlen; 3455 const unsigned char* inend; 3456 3457 inend = in + (*inlen); 3458 3459 while ((in < inend) && (out < outend)) { 3460 if (*in == '<') { 3461 if (outend - out < 4) break; 3462 *out++ = '&'; 3463 *out++ = 'l'; 3464 *out++ = 't'; 3465 *out++ = ';'; 3466 } else if (*in == '>') { 3467 if (outend - out < 4) break; 3468 *out++ = '&'; 3469 *out++ = 'g'; 3470 *out++ = 't'; 3471 *out++ = ';'; 3472 } else if (*in == '&') { 3473 if (outend - out < 5) break; 3474 *out++ = '&'; 3475 *out++ = 'a'; 3476 *out++ = 'm'; 3477 *out++ = 'p'; 3478 *out++ = ';'; 3479 } else if (*in == '\r') { 3480 if (outend - out < 5) break; 3481 *out++ = '&'; 3482 *out++ = '#'; 3483 *out++ = '1'; 3484 *out++ = '3'; 3485 *out++ = ';'; 3486 } else { 3487 *out++ = (unsigned char) *in; 3488 } 3489 ++in; 3490 } 3491 *outlen = out - outstart; 3492 *inlen = in - base; 3493 return(0); 3494 } 3495 3496 /** 3497 * xmlOutputBufferWriteEscape: 3498 * @out: a buffered parser output 3499 * @str: a zero terminated UTF-8 string 3500 * @escaping: an optional escaping function (or NULL) 3501 * 3502 * Write the content of the string in the output I/O buffer 3503 * This routine escapes the characters and then handle the I18N 3504 * transcoding from internal UTF-8 3505 * The buffer is lossless, i.e. will store in case of partial 3506 * or delayed writes. 3507 * 3508 * Returns the number of chars immediately written, or -1 3509 * in case of error. 3510 */ 3511 int 3512 xmlOutputBufferWriteEscape(xmlOutputBufferPtr out, const xmlChar *str, 3513 xmlCharEncodingOutputFunc escaping) { 3514 int nbchars = 0; /* number of chars to output to I/O */ 3515 int ret; /* return from function call */ 3516 int written = 0; /* number of char written to I/O so far */ 3517 int oldwritten=0;/* loop guard */ 3518 int chunk; /* number of byte currently processed from str */ 3519 int len; /* number of bytes in str */ 3520 int cons; /* byte from str consumed */ 3521 3522 if ((out == NULL) || (out->error) || (str == NULL) || 3523 (out->buffer == NULL) || 3524 (xmlBufGetAllocationScheme(out->buffer) == XML_BUFFER_ALLOC_IMMUTABLE)) 3525 return(-1); 3526 len = strlen((const char *)str); 3527 if (len < 0) return(0); 3528 if (out->error) return(-1); 3529 if (escaping == NULL) escaping = xmlEscapeContent; 3530 3531 do { 3532 oldwritten = written; 3533 3534 /* 3535 * how many bytes to consume and how many bytes to store. 3536 */ 3537 cons = len; 3538 chunk = xmlBufAvail(out->buffer) - 1; 3539 3540 /* 3541 * make sure we have enough room to save first, if this is 3542 * not the case force a flush, but make sure we stay in the loop 3543 */ 3544 if (chunk < 40) { 3545 if (xmlBufGrow(out->buffer, 100) < 0) 3546 return(-1); 3547 oldwritten = -1; 3548 continue; 3549 } 3550 3551 /* 3552 * first handle encoding stuff. 3553 */ 3554 if (out->encoder != NULL) { 3555 /* 3556 * Store the data in the incoming raw buffer 3557 */ 3558 if (out->conv == NULL) { 3559 out->conv = xmlBufCreate(); 3560 } 3561 ret = escaping(xmlBufEnd(out->buffer) , 3562 &chunk, str, &cons); 3563 if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */ 3564 return(-1); 3565 xmlBufAddLen(out->buffer, chunk); 3566 3567 if ((xmlBufUse(out->buffer) < MINLEN) && (cons == len)) 3568 goto done; 3569 3570 /* 3571 * convert as much as possible to the output buffer. 3572 */ 3573 ret = xmlCharEncOutput(out, 0); 3574 if ((ret < 0) && (ret != -3)) { 3575 xmlIOErr(XML_IO_ENCODER, NULL); 3576 out->error = XML_IO_ENCODER; 3577 return(-1); 3578 } 3579 if (out->writecallback) 3580 nbchars = xmlBufUse(out->conv); 3581 else 3582 nbchars = ret; 3583 } else { 3584 ret = escaping(xmlBufEnd(out->buffer), &chunk, str, &cons); 3585 if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */ 3586 return(-1); 3587 xmlBufAddLen(out->buffer, chunk); 3588 if (out->writecallback) 3589 nbchars = xmlBufUse(out->buffer); 3590 else 3591 nbchars = chunk; 3592 } 3593 str += cons; 3594 len -= cons; 3595 3596 if (out->writecallback) { 3597 if ((nbchars < MINLEN) && (len <= 0)) 3598 goto done; 3599 3600 /* 3601 * second write the stuff to the I/O channel 3602 */ 3603 if (out->encoder != NULL) { 3604 ret = out->writecallback(out->context, 3605 (const char *)xmlBufContent(out->conv), nbchars); 3606 if (ret >= 0) 3607 xmlBufShrink(out->conv, ret); 3608 } else { 3609 ret = out->writecallback(out->context, 3610 (const char *)xmlBufContent(out->buffer), nbchars); 3611 if (ret >= 0) 3612 xmlBufShrink(out->buffer, ret); 3613 } 3614 if (ret < 0) { 3615 xmlIOErr(XML_IO_WRITE, NULL); 3616 out->error = XML_IO_WRITE; 3617 return(ret); 3618 } 3619 if (out->written > INT_MAX - ret) 3620 out->written = INT_MAX; 3621 else 3622 out->written += ret; 3623 } else if (xmlBufAvail(out->buffer) < MINLEN) { 3624 xmlBufGrow(out->buffer, MINLEN); 3625 } 3626 written += nbchars; 3627 } while ((len > 0) && (oldwritten != written)); 3628 3629 done: 3630 #ifdef DEBUG_INPUT 3631 xmlGenericError(xmlGenericErrorContext, 3632 "I/O: wrote %d chars\n", written); 3633 #endif 3634 return(written); 3635 } 3636 3637 /** 3638 * xmlOutputBufferWriteString: 3639 * @out: a buffered parser output 3640 * @str: a zero terminated C string 3641 * 3642 * Write the content of the string in the output I/O buffer 3643 * This routine handle the I18N transcoding from internal UTF-8 3644 * The buffer is lossless, i.e. will store in case of partial 3645 * or delayed writes. 3646 * 3647 * Returns the number of chars immediately written, or -1 3648 * in case of error. 3649 */ 3650 int 3651 xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) { 3652 int len; 3653 3654 if ((out == NULL) || (out->error)) return(-1); 3655 if (str == NULL) 3656 return(-1); 3657 len = strlen(str); 3658 3659 if (len > 0) 3660 return(xmlOutputBufferWrite(out, len, str)); 3661 return(len); 3662 } 3663 3664 /** 3665 * xmlOutputBufferFlush: 3666 * @out: a buffered output 3667 * 3668 * flushes the output I/O channel 3669 * 3670 * Returns the number of byte written or -1 in case of error. 3671 */ 3672 int 3673 xmlOutputBufferFlush(xmlOutputBufferPtr out) { 3674 int nbchars = 0, ret = 0; 3675 3676 if ((out == NULL) || (out->error)) return(-1); 3677 /* 3678 * first handle encoding stuff. 3679 */ 3680 if ((out->conv != NULL) && (out->encoder != NULL)) { 3681 /* 3682 * convert as much as possible to the parser output buffer. 3683 */ 3684 do { 3685 nbchars = xmlCharEncOutput(out, 0); 3686 if (nbchars < 0) { 3687 xmlIOErr(XML_IO_ENCODER, NULL); 3688 out->error = XML_IO_ENCODER; 3689 return(-1); 3690 } 3691 } while (nbchars); 3692 } 3693 3694 /* 3695 * second flush the stuff to the I/O channel 3696 */ 3697 if ((out->conv != NULL) && (out->encoder != NULL) && 3698 (out->writecallback != NULL)) { 3699 ret = out->writecallback(out->context, 3700 (const char *)xmlBufContent(out->conv), 3701 xmlBufUse(out->conv)); 3702 if (ret >= 0) 3703 xmlBufShrink(out->conv, ret); 3704 } else if (out->writecallback != NULL) { 3705 ret = out->writecallback(out->context, 3706 (const char *)xmlBufContent(out->buffer), 3707 xmlBufUse(out->buffer)); 3708 if (ret >= 0) 3709 xmlBufShrink(out->buffer, ret); 3710 } 3711 if (ret < 0) { 3712 xmlIOErr(XML_IO_FLUSH, NULL); 3713 out->error = XML_IO_FLUSH; 3714 return(ret); 3715 } 3716 if (out->written > INT_MAX - ret) 3717 out->written = INT_MAX; 3718 else 3719 out->written += ret; 3720 3721 #ifdef DEBUG_INPUT 3722 xmlGenericError(xmlGenericErrorContext, 3723 "I/O: flushed %d chars\n", ret); 3724 #endif 3725 return(ret); 3726 } 3727 #endif /* LIBXML_OUTPUT_ENABLED */ 3728 3729 /** 3730 * xmlParserGetDirectory: 3731 * @filename: the path to a file 3732 * 3733 * lookup the directory for that file 3734 * 3735 * Returns a new allocated string containing the directory, or NULL. 3736 */ 3737 char * 3738 xmlParserGetDirectory(const char *filename) { 3739 char *ret = NULL; 3740 char dir[1024]; 3741 char *cur; 3742 3743 #ifdef _WIN32_WCE /* easy way by now ... wince does not have dirs! */ 3744 return NULL; 3745 #endif 3746 3747 if (xmlInputCallbackInitialized == 0) 3748 xmlRegisterDefaultInputCallbacks(); 3749 3750 if (filename == NULL) return(NULL); 3751 3752 #if defined(_WIN32) && !defined(__CYGWIN__) 3753 # define IS_XMLPGD_SEP(ch) ((ch=='/')||(ch=='\\')) 3754 #else 3755 # define IS_XMLPGD_SEP(ch) (ch=='/') 3756 #endif 3757 3758 strncpy(dir, filename, 1023); 3759 dir[1023] = 0; 3760 cur = &dir[strlen(dir)]; 3761 while (cur > dir) { 3762 if (IS_XMLPGD_SEP(*cur)) break; 3763 cur --; 3764 } 3765 if (IS_XMLPGD_SEP(*cur)) { 3766 if (cur == dir) dir[1] = 0; 3767 else *cur = 0; 3768 ret = xmlMemStrdup(dir); 3769 } else { 3770 if (getcwd(dir, 1024) != NULL) { 3771 dir[1023] = 0; 3772 ret = xmlMemStrdup(dir); 3773 } 3774 } 3775 return(ret); 3776 #undef IS_XMLPGD_SEP 3777 } 3778 3779 /**************************************************************** 3780 * * 3781 * External entities loading * 3782 * * 3783 ****************************************************************/ 3784 3785 /** 3786 * xmlCheckHTTPInput: 3787 * @ctxt: an XML parser context 3788 * @ret: an XML parser input 3789 * 3790 * Check an input in case it was created from an HTTP stream, in that 3791 * case it will handle encoding and update of the base URL in case of 3792 * redirection. It also checks for HTTP errors in which case the input 3793 * is cleanly freed up and an appropriate error is raised in context 3794 * 3795 * Returns the input or NULL in case of HTTP error. 3796 */ 3797 xmlParserInputPtr 3798 xmlCheckHTTPInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr ret) { 3799 #ifdef LIBXML_HTTP_ENABLED 3800 if ((ret != NULL) && (ret->buf != NULL) && 3801 (ret->buf->readcallback == xmlIOHTTPRead) && 3802 (ret->buf->context != NULL)) { 3803 const char *encoding; 3804 const char *redir; 3805 const char *mime; 3806 int code; 3807 3808 code = xmlNanoHTTPReturnCode(ret->buf->context); 3809 if (code >= 400) { 3810 /* fatal error */ 3811 if (ret->filename != NULL) 3812 __xmlLoaderErr(ctxt, "failed to load HTTP resource \"%s\"\n", 3813 (const char *) ret->filename); 3814 else 3815 __xmlLoaderErr(ctxt, "failed to load HTTP resource\n", NULL); 3816 xmlFreeInputStream(ret); 3817 ret = NULL; 3818 } else { 3819 3820 mime = xmlNanoHTTPMimeType(ret->buf->context); 3821 if ((xmlStrstr(BAD_CAST mime, BAD_CAST "/xml")) || 3822 (xmlStrstr(BAD_CAST mime, BAD_CAST "+xml"))) { 3823 encoding = xmlNanoHTTPEncoding(ret->buf->context); 3824 if (encoding != NULL) { 3825 xmlCharEncodingHandlerPtr handler; 3826 3827 handler = xmlFindCharEncodingHandler(encoding); 3828 if (handler != NULL) { 3829 xmlSwitchInputEncoding(ctxt, ret, handler); 3830 } else { 3831 __xmlErrEncoding(ctxt, XML_ERR_UNKNOWN_ENCODING, 3832 "Unknown encoding %s", 3833 BAD_CAST encoding, NULL); 3834 } 3835 if (ret->encoding == NULL) 3836 ret->encoding = xmlStrdup(BAD_CAST encoding); 3837 } 3838 #if 0 3839 } else if (xmlStrstr(BAD_CAST mime, BAD_CAST "html")) { 3840 #endif 3841 } 3842 redir = xmlNanoHTTPRedir(ret->buf->context); 3843 if (redir != NULL) { 3844 if (ret->filename != NULL) 3845 xmlFree((xmlChar *) ret->filename); 3846 if (ret->directory != NULL) { 3847 xmlFree((xmlChar *) ret->directory); 3848 ret->directory = NULL; 3849 } 3850 ret->filename = 3851 (char *) xmlStrdup((const xmlChar *) redir); 3852 } 3853 } 3854 } 3855 #endif 3856 return(ret); 3857 } 3858 3859 static int xmlNoNetExists(const char *URL) { 3860 const char *path; 3861 3862 if (URL == NULL) 3863 return(0); 3864 3865 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17)) 3866 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__) 3867 path = &URL[17]; 3868 #else 3869 path = &URL[16]; 3870 #endif 3871 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) { 3872 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__) 3873 path = &URL[8]; 3874 #else 3875 path = &URL[7]; 3876 #endif 3877 } else 3878 path = URL; 3879 3880 return xmlCheckFilename(path); 3881 } 3882 3883 #ifdef LIBXML_CATALOG_ENABLED 3884 3885 /** 3886 * xmlResolveResourceFromCatalog: 3887 * @URL: the URL for the entity to load 3888 * @ID: the System ID for the entity to load 3889 * @ctxt: the context in which the entity is called or NULL 3890 * 3891 * Resolves the URL and ID against the appropriate catalog. 3892 * This function is used by xmlDefaultExternalEntityLoader and 3893 * xmlNoNetExternalEntityLoader. 3894 * 3895 * Returns a new allocated URL, or NULL. 3896 */ 3897 static xmlChar * 3898 xmlResolveResourceFromCatalog(const char *URL, const char *ID, 3899 xmlParserCtxtPtr ctxt) { 3900 xmlChar *resource = NULL; 3901 xmlCatalogAllow pref; 3902 3903 /* 3904 * If the resource doesn't exists as a file, 3905 * try to load it from the resource pointed in the catalogs 3906 */ 3907 pref = xmlCatalogGetDefaults(); 3908 3909 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) { 3910 /* 3911 * Do a local lookup 3912 */ 3913 if ((ctxt != NULL) && (ctxt->catalogs != NULL) && 3914 ((pref == XML_CATA_ALLOW_ALL) || 3915 (pref == XML_CATA_ALLOW_DOCUMENT))) { 3916 resource = xmlCatalogLocalResolve(ctxt->catalogs, 3917 (const xmlChar *)ID, 3918 (const xmlChar *)URL); 3919 } 3920 /* 3921 * Try a global lookup 3922 */ 3923 if ((resource == NULL) && 3924 ((pref == XML_CATA_ALLOW_ALL) || 3925 (pref == XML_CATA_ALLOW_GLOBAL))) { 3926 resource = xmlCatalogResolve((const xmlChar *)ID, 3927 (const xmlChar *)URL); 3928 } 3929 if ((resource == NULL) && (URL != NULL)) 3930 resource = xmlStrdup((const xmlChar *) URL); 3931 3932 /* 3933 * TODO: do an URI lookup on the reference 3934 */ 3935 if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) { 3936 xmlChar *tmp = NULL; 3937 3938 if ((ctxt != NULL) && (ctxt->catalogs != NULL) && 3939 ((pref == XML_CATA_ALLOW_ALL) || 3940 (pref == XML_CATA_ALLOW_DOCUMENT))) { 3941 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource); 3942 } 3943 if ((tmp == NULL) && 3944 ((pref == XML_CATA_ALLOW_ALL) || 3945 (pref == XML_CATA_ALLOW_GLOBAL))) { 3946 tmp = xmlCatalogResolveURI(resource); 3947 } 3948 3949 if (tmp != NULL) { 3950 xmlFree(resource); 3951 resource = tmp; 3952 } 3953 } 3954 } 3955 3956 return resource; 3957 } 3958 3959 #endif 3960 3961 /** 3962 * xmlDefaultExternalEntityLoader: 3963 * @URL: the URL for the entity to load 3964 * @ID: the System ID for the entity to load 3965 * @ctxt: the context in which the entity is called or NULL 3966 * 3967 * By default we don't load external entities, yet. 3968 * 3969 * Returns a new allocated xmlParserInputPtr, or NULL. 3970 */ 3971 static xmlParserInputPtr 3972 xmlDefaultExternalEntityLoader(const char *URL, const char *ID, 3973 xmlParserCtxtPtr ctxt) 3974 { 3975 xmlParserInputPtr ret = NULL; 3976 xmlChar *resource = NULL; 3977 3978 #ifdef DEBUG_EXTERNAL_ENTITIES 3979 xmlGenericError(xmlGenericErrorContext, 3980 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL); 3981 #endif 3982 if ((ctxt != NULL) && (ctxt->options & XML_PARSE_NONET)) { 3983 int options = ctxt->options; 3984 3985 ctxt->options -= XML_PARSE_NONET; 3986 ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt); 3987 ctxt->options = options; 3988 return(ret); 3989 } 3990 #ifdef LIBXML_CATALOG_ENABLED 3991 resource = xmlResolveResourceFromCatalog(URL, ID, ctxt); 3992 #endif 3993 3994 if (resource == NULL) 3995 resource = (xmlChar *) URL; 3996 3997 if (resource == NULL) { 3998 if (ID == NULL) 3999 ID = "NULL"; 4000 __xmlLoaderErr(ctxt, "failed to load external entity \"%s\"\n", ID); 4001 return (NULL); 4002 } 4003 ret = xmlNewInputFromFile(ctxt, (const char *) resource); 4004 if ((resource != NULL) && (resource != (xmlChar *) URL)) 4005 xmlFree(resource); 4006 return (ret); 4007 } 4008 4009 static xmlExternalEntityLoader xmlCurrentExternalEntityLoader = 4010 xmlDefaultExternalEntityLoader; 4011 4012 /** 4013 * xmlSetExternalEntityLoader: 4014 * @f: the new entity resolver function 4015 * 4016 * Changes the defaultexternal entity resolver function for the application 4017 */ 4018 void 4019 xmlSetExternalEntityLoader(xmlExternalEntityLoader f) { 4020 xmlCurrentExternalEntityLoader = f; 4021 } 4022 4023 /** 4024 * xmlGetExternalEntityLoader: 4025 * 4026 * Get the default external entity resolver function for the application 4027 * 4028 * Returns the xmlExternalEntityLoader function pointer 4029 */ 4030 xmlExternalEntityLoader 4031 xmlGetExternalEntityLoader(void) { 4032 return(xmlCurrentExternalEntityLoader); 4033 } 4034 4035 /** 4036 * xmlLoadExternalEntity: 4037 * @URL: the URL for the entity to load 4038 * @ID: the Public ID for the entity to load 4039 * @ctxt: the context in which the entity is called or NULL 4040 * 4041 * Load an external entity, note that the use of this function for 4042 * unparsed entities may generate problems 4043 * 4044 * Returns the xmlParserInputPtr or NULL 4045 */ 4046 xmlParserInputPtr 4047 xmlLoadExternalEntity(const char *URL, const char *ID, 4048 xmlParserCtxtPtr ctxt) { 4049 if ((URL != NULL) && (xmlNoNetExists(URL) == 0)) { 4050 char *canonicFilename; 4051 xmlParserInputPtr ret; 4052 4053 canonicFilename = (char *) xmlCanonicPath((const xmlChar *) URL); 4054 if (canonicFilename == NULL) { 4055 xmlIOErrMemory("building canonical path\n"); 4056 return(NULL); 4057 } 4058 4059 ret = xmlCurrentExternalEntityLoader(canonicFilename, ID, ctxt); 4060 xmlFree(canonicFilename); 4061 return(ret); 4062 } 4063 return(xmlCurrentExternalEntityLoader(URL, ID, ctxt)); 4064 } 4065 4066 /************************************************************************ 4067 * * 4068 * Disabling Network access * 4069 * * 4070 ************************************************************************/ 4071 4072 /** 4073 * xmlNoNetExternalEntityLoader: 4074 * @URL: the URL for the entity to load 4075 * @ID: the System ID for the entity to load 4076 * @ctxt: the context in which the entity is called or NULL 4077 * 4078 * A specific entity loader disabling network accesses, though still 4079 * allowing local catalog accesses for resolution. 4080 * 4081 * Returns a new allocated xmlParserInputPtr, or NULL. 4082 */ 4083 xmlParserInputPtr 4084 xmlNoNetExternalEntityLoader(const char *URL, const char *ID, 4085 xmlParserCtxtPtr ctxt) { 4086 xmlParserInputPtr input = NULL; 4087 xmlChar *resource = NULL; 4088 4089 #ifdef LIBXML_CATALOG_ENABLED 4090 resource = xmlResolveResourceFromCatalog(URL, ID, ctxt); 4091 #endif 4092 4093 if (resource == NULL) 4094 resource = (xmlChar *) URL; 4095 4096 if (resource != NULL) { 4097 if ((!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "ftp://", 6)) || 4098 (!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "http://", 7))) { 4099 xmlIOErr(XML_IO_NETWORK_ATTEMPT, (const char *) resource); 4100 if (resource != (xmlChar *) URL) 4101 xmlFree(resource); 4102 return(NULL); 4103 } 4104 } 4105 input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt); 4106 if (resource != (xmlChar *) URL) 4107 xmlFree(resource); 4108 return(input); 4109 } 4110 4111 #define bottom_xmlIO 4112 #include "elfgcchack.h" 4113