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