Return to memory.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / main / streams |
1.1 ! misho 1: /* ! 2: +----------------------------------------------------------------------+ ! 3: | PHP Version 5 | ! 4: +----------------------------------------------------------------------+ ! 5: | Copyright (c) 1997-2012 The PHP Group | ! 6: +----------------------------------------------------------------------+ ! 7: | This source file is subject to version 3.01 of the PHP license, | ! 8: | that is bundled with this package in the file LICENSE, and is | ! 9: | available through the world-wide-web at the following url: | ! 10: | http://www.php.net/license/3_01.txt | ! 11: | If you did not receive a copy of the PHP license and are unable to | ! 12: | obtain it through the world-wide-web, please send a note to | ! 13: | license@php.net so we can mail you a copy immediately. | ! 14: +----------------------------------------------------------------------+ ! 15: | Author: Marcus Boerger <helly@php.net> | ! 16: +----------------------------------------------------------------------+ ! 17: */ ! 18: ! 19: /* $Id: memory.c 321634 2012-01-01 13:15:04Z felipe $ */ ! 20: ! 21: #define _GNU_SOURCE ! 22: #include "php.h" ! 23: ! 24: PHPAPI int php_url_decode(char *str, int len); ! 25: PHPAPI unsigned char *php_base64_decode(const unsigned char *str, int length, int *ret_length); ! 26: ! 27: /* Memory streams use a dynamic memory buffer to emulate a stream. ! 28: * You can use php_stream_memory_open to create a readonly stream ! 29: * from an existing memory buffer. ! 30: */ ! 31: ! 32: /* Temp streams are streams that uses memory streams as long their ! 33: * size is less than a given memory amount. When a write operation ! 34: * exceeds that limit the content is written to a temporary file. ! 35: */ ! 36: ! 37: /* {{{ ------- MEMORY stream implementation -------*/ ! 38: ! 39: typedef struct { ! 40: char *data; ! 41: size_t fpos; ! 42: size_t fsize; ! 43: size_t smax; ! 44: int mode; ! 45: php_stream **owner_ptr; ! 46: } php_stream_memory_data; ! 47: ! 48: ! 49: /* {{{ */ ! 50: static size_t php_stream_memory_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC) ! 51: { ! 52: php_stream_memory_data *ms = (php_stream_memory_data*)stream->abstract; ! 53: assert(ms != NULL); ! 54: ! 55: if (ms->mode & TEMP_STREAM_READONLY) { ! 56: return 0; ! 57: } ! 58: if (ms->fpos + count > ms->fsize) { ! 59: char *tmp; ! 60: ! 61: if (!ms->data) { ! 62: tmp = emalloc(ms->fpos + count); ! 63: } else { ! 64: tmp = erealloc(ms->data, ms->fpos + count); ! 65: } ! 66: if (!tmp) { ! 67: count = ms->fsize - ms->fpos + 1; ! 68: } else { ! 69: ms->data = tmp; ! 70: ms->fsize = ms->fpos + count; ! 71: } ! 72: } ! 73: if (!ms->data) ! 74: count = 0; ! 75: if (count) { ! 76: assert(buf!= NULL); ! 77: memcpy(ms->data+ms->fpos, (char*)buf, count); ! 78: ms->fpos += count; ! 79: } ! 80: return count; ! 81: } ! 82: /* }}} */ ! 83: ! 84: ! 85: /* {{{ */ ! 86: static size_t php_stream_memory_read(php_stream *stream, char *buf, size_t count TSRMLS_DC) ! 87: { ! 88: php_stream_memory_data *ms = (php_stream_memory_data*)stream->abstract; ! 89: assert(ms != NULL); ! 90: ! 91: if (ms->fpos + count >= ms->fsize) { ! 92: count = ms->fsize - ms->fpos; ! 93: stream->eof = 1; ! 94: } ! 95: if (count) { ! 96: assert(ms->data!= NULL); ! 97: assert(buf!= NULL); ! 98: memcpy(buf, ms->data+ms->fpos, count); ! 99: ms->fpos += count; ! 100: } ! 101: return count; ! 102: } ! 103: /* }}} */ ! 104: ! 105: ! 106: /* {{{ */ ! 107: static int php_stream_memory_close(php_stream *stream, int close_handle TSRMLS_DC) ! 108: { ! 109: php_stream_memory_data *ms = (php_stream_memory_data*)stream->abstract; ! 110: assert(ms != NULL); ! 111: ! 112: if (ms->data && close_handle && ms->mode != TEMP_STREAM_READONLY) { ! 113: efree(ms->data); ! 114: } ! 115: if (ms->owner_ptr) { ! 116: *ms->owner_ptr = NULL; ! 117: } ! 118: efree(ms); ! 119: return 0; ! 120: } ! 121: /* }}} */ ! 122: ! 123: ! 124: /* {{{ */ ! 125: static int php_stream_memory_flush(php_stream *stream TSRMLS_DC) ! 126: { ! 127: /* nothing to do here */ ! 128: return 0; ! 129: } ! 130: /* }}} */ ! 131: ! 132: ! 133: /* {{{ */ ! 134: static int php_stream_memory_seek(php_stream *stream, off_t offset, int whence, off_t *newoffs TSRMLS_DC) ! 135: { ! 136: php_stream_memory_data *ms = (php_stream_memory_data*)stream->abstract; ! 137: assert(ms != NULL); ! 138: ! 139: switch(whence) { ! 140: case SEEK_CUR: ! 141: if (offset < 0) { ! 142: if (ms->fpos < (size_t)(-offset)) { ! 143: ms->fpos = 0; ! 144: *newoffs = -1; ! 145: return -1; ! 146: } else { ! 147: ms->fpos = ms->fpos + offset; ! 148: *newoffs = ms->fpos; ! 149: stream->eof = 0; ! 150: return 0; ! 151: } ! 152: } else { ! 153: if (ms->fpos + (size_t)(offset) > ms->fsize) { ! 154: ms->fpos = ms->fsize; ! 155: *newoffs = -1; ! 156: return -1; ! 157: } else { ! 158: ms->fpos = ms->fpos + offset; ! 159: *newoffs = ms->fpos; ! 160: stream->eof = 0; ! 161: return 0; ! 162: } ! 163: } ! 164: case SEEK_SET: ! 165: if (ms->fsize < (size_t)(offset)) { ! 166: ms->fpos = ms->fsize; ! 167: *newoffs = -1; ! 168: return -1; ! 169: } else { ! 170: ms->fpos = offset; ! 171: *newoffs = ms->fpos; ! 172: stream->eof = 0; ! 173: return 0; ! 174: } ! 175: case SEEK_END: ! 176: if (offset > 0) { ! 177: ms->fpos = ms->fsize; ! 178: *newoffs = -1; ! 179: return -1; ! 180: } else if (ms->fsize < (size_t)(-offset)) { ! 181: ms->fpos = 0; ! 182: *newoffs = -1; ! 183: return -1; ! 184: } else { ! 185: ms->fpos = ms->fsize + offset; ! 186: *newoffs = ms->fpos; ! 187: stream->eof = 0; ! 188: return 0; ! 189: } ! 190: default: ! 191: *newoffs = ms->fpos; ! 192: return -1; ! 193: } ! 194: } ! 195: /* }}} */ ! 196: ! 197: /* {{{ */ ! 198: static int php_stream_memory_cast(php_stream *stream, int castas, void **ret TSRMLS_DC) ! 199: { ! 200: return FAILURE; ! 201: } ! 202: /* }}} */ ! 203: ! 204: static int php_stream_memory_stat(php_stream *stream, php_stream_statbuf *ssb TSRMLS_DC) /* {{{ */ ! 205: { ! 206: time_t timestamp = 0; ! 207: php_stream_memory_data *ms = (php_stream_memory_data*)stream->abstract; ! 208: assert(ms != NULL); ! 209: ! 210: memset(ssb, 0, sizeof(php_stream_statbuf)); ! 211: /* read-only across the board */ ! 212: ! 213: ssb->sb.st_mode = ms->mode & TEMP_STREAM_READONLY ? 0444 : 0666; ! 214: ! 215: ssb->sb.st_size = ms->fsize; ! 216: ssb->sb.st_mode |= S_IFREG; /* regular file */ ! 217: ! 218: #ifdef NETWARE ! 219: ssb->sb.st_mtime.tv_sec = timestamp; ! 220: ssb->sb.st_atime.tv_sec = timestamp; ! 221: ssb->sb.st_ctime.tv_sec = timestamp; ! 222: #else ! 223: ssb->sb.st_mtime = timestamp; ! 224: ssb->sb.st_atime = timestamp; ! 225: ssb->sb.st_ctime = timestamp; ! 226: #endif ! 227: ! 228: ssb->sb.st_nlink = 1; ! 229: ssb->sb.st_rdev = -1; ! 230: /* this is only for APC, so use /dev/null device - no chance of conflict there! */ ! 231: ssb->sb.st_dev = 0xC; ! 232: /* generate unique inode number for alias/filename, so no phars will conflict */ ! 233: ssb->sb.st_ino = 0; ! 234: ! 235: #ifndef PHP_WIN32 ! 236: ssb->sb.st_blksize = -1; ! 237: #endif ! 238: ! 239: #if !defined(PHP_WIN32) && !defined(__BEOS__) ! 240: ssb->sb.st_blocks = -1; ! 241: #endif ! 242: ! 243: return 0; ! 244: } ! 245: /* }}} */ ! 246: ! 247: static int php_stream_memory_set_option(php_stream *stream, int option, int value, void *ptrparam TSRMLS_DC) /* {{{ */ ! 248: { ! 249: php_stream_memory_data *ms = (php_stream_memory_data*)stream->abstract; ! 250: size_t newsize; ! 251: ! 252: switch(option) { ! 253: case PHP_STREAM_OPTION_TRUNCATE_API: ! 254: switch (value) { ! 255: case PHP_STREAM_TRUNCATE_SUPPORTED: ! 256: return PHP_STREAM_OPTION_RETURN_OK; ! 257: ! 258: case PHP_STREAM_TRUNCATE_SET_SIZE: ! 259: if (ms->mode & TEMP_STREAM_READONLY) { ! 260: return PHP_STREAM_OPTION_RETURN_ERR; ! 261: } ! 262: newsize = *(size_t*)ptrparam; ! 263: if (newsize <= ms->fsize) { ! 264: if (newsize < ms->fpos) { ! 265: ms->fpos = newsize; ! 266: } ! 267: } else { ! 268: ms->data = erealloc(ms->data, newsize); ! 269: memset(ms->data+ms->fsize, 0, newsize - ms->fsize); ! 270: ms->fsize = newsize; ! 271: } ! 272: ms->fsize = newsize; ! 273: return PHP_STREAM_OPTION_RETURN_OK; ! 274: } ! 275: default: ! 276: return PHP_STREAM_OPTION_RETURN_NOTIMPL; ! 277: } ! 278: } ! 279: /* }}} */ ! 280: ! 281: PHPAPI php_stream_ops php_stream_memory_ops = { ! 282: php_stream_memory_write, php_stream_memory_read, ! 283: php_stream_memory_close, php_stream_memory_flush, ! 284: "MEMORY", ! 285: php_stream_memory_seek, ! 286: php_stream_memory_cast, ! 287: php_stream_memory_stat, ! 288: php_stream_memory_set_option ! 289: }; ! 290: ! 291: ! 292: /* {{{ */ ! 293: PHPAPI php_stream *_php_stream_memory_create(int mode STREAMS_DC TSRMLS_DC) ! 294: { ! 295: php_stream_memory_data *self; ! 296: php_stream *stream; ! 297: ! 298: self = emalloc(sizeof(*self)); ! 299: self->data = NULL; ! 300: self->fpos = 0; ! 301: self->fsize = 0; ! 302: self->smax = ~0u; ! 303: self->mode = mode; ! 304: self->owner_ptr = NULL; ! 305: ! 306: stream = php_stream_alloc_rel(&php_stream_memory_ops, self, 0, mode & TEMP_STREAM_READONLY ? "rb" : "w+b"); ! 307: stream->flags |= PHP_STREAM_FLAG_NO_BUFFER; ! 308: return stream; ! 309: } ! 310: /* }}} */ ! 311: ! 312: ! 313: /* {{{ */ ! 314: PHPAPI php_stream *_php_stream_memory_open(int mode, char *buf, size_t length STREAMS_DC TSRMLS_DC) ! 315: { ! 316: php_stream *stream; ! 317: php_stream_memory_data *ms; ! 318: ! 319: if ((stream = php_stream_memory_create_rel(mode)) != NULL) { ! 320: ms = (php_stream_memory_data*)stream->abstract; ! 321: ! 322: if (mode == TEMP_STREAM_READONLY || mode == TEMP_STREAM_TAKE_BUFFER) { ! 323: /* use the buffer directly */ ! 324: ms->data = buf; ! 325: ms->fsize = length; ! 326: } else { ! 327: if (length) { ! 328: assert(buf != NULL); ! 329: php_stream_write(stream, buf, length); ! 330: } ! 331: } ! 332: } ! 333: return stream; ! 334: } ! 335: /* }}} */ ! 336: ! 337: ! 338: /* {{{ */ ! 339: PHPAPI char *_php_stream_memory_get_buffer(php_stream *stream, size_t *length STREAMS_DC TSRMLS_DC) ! 340: { ! 341: php_stream_memory_data *ms = (php_stream_memory_data*)stream->abstract; ! 342: ! 343: assert(ms != NULL); ! 344: assert(length != 0); ! 345: ! 346: *length = ms->fsize; ! 347: return ms->data; ! 348: } ! 349: /* }}} */ ! 350: ! 351: /* }}} */ ! 352: ! 353: /* {{{ ------- TEMP stream implementation -------*/ ! 354: ! 355: typedef struct { ! 356: php_stream *innerstream; ! 357: size_t smax; ! 358: int mode; ! 359: zval* meta; ! 360: } php_stream_temp_data; ! 361: ! 362: ! 363: /* {{{ */ ! 364: static size_t php_stream_temp_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC) ! 365: { ! 366: php_stream_temp_data *ts = (php_stream_temp_data*)stream->abstract; ! 367: assert(ts != NULL); ! 368: ! 369: if (!ts->innerstream) { ! 370: return -1; ! 371: } ! 372: if (php_stream_is(ts->innerstream, PHP_STREAM_IS_MEMORY)) { ! 373: size_t memsize; ! 374: char *membuf = php_stream_memory_get_buffer(ts->innerstream, &memsize); ! 375: ! 376: if (memsize + count >= ts->smax) { ! 377: php_stream *file = php_stream_fopen_tmpfile(); ! 378: php_stream_write(file, membuf, memsize); ! 379: php_stream_close(ts->innerstream); ! 380: ts->innerstream = file; ! 381: } ! 382: } ! 383: return php_stream_write(ts->innerstream, buf, count); ! 384: } ! 385: /* }}} */ ! 386: ! 387: ! 388: /* {{{ */ ! 389: static size_t php_stream_temp_read(php_stream *stream, char *buf, size_t count TSRMLS_DC) ! 390: { ! 391: php_stream_temp_data *ts = (php_stream_temp_data*)stream->abstract; ! 392: size_t got; ! 393: ! 394: assert(ts != NULL); ! 395: ! 396: if (!ts->innerstream) { ! 397: return -1; ! 398: } ! 399: ! 400: got = php_stream_read(ts->innerstream, buf, count); ! 401: ! 402: stream->eof = ts->innerstream->eof; ! 403: ! 404: return got; ! 405: } ! 406: /* }}} */ ! 407: ! 408: ! 409: /* {{{ */ ! 410: static int php_stream_temp_close(php_stream *stream, int close_handle TSRMLS_DC) ! 411: { ! 412: php_stream_temp_data *ts = (php_stream_temp_data*)stream->abstract; ! 413: int ret; ! 414: ! 415: assert(ts != NULL); ! 416: ! 417: if (ts->innerstream) { ! 418: ret = php_stream_free(ts->innerstream, PHP_STREAM_FREE_CLOSE | (close_handle ? 0 : PHP_STREAM_FREE_PRESERVE_HANDLE)); ! 419: } else { ! 420: ret = 0; ! 421: } ! 422: ! 423: if (ts->meta) { ! 424: zval_ptr_dtor(&ts->meta); ! 425: } ! 426: ! 427: efree(ts); ! 428: ! 429: return ret; ! 430: } ! 431: /* }}} */ ! 432: ! 433: ! 434: /* {{{ */ ! 435: static int php_stream_temp_flush(php_stream *stream TSRMLS_DC) ! 436: { ! 437: php_stream_temp_data *ts = (php_stream_temp_data*)stream->abstract; ! 438: assert(ts != NULL); ! 439: ! 440: return ts->innerstream ? php_stream_flush(ts->innerstream) : -1; ! 441: } ! 442: /* }}} */ ! 443: ! 444: ! 445: /* {{{ */ ! 446: static int php_stream_temp_seek(php_stream *stream, off_t offset, int whence, off_t *newoffs TSRMLS_DC) ! 447: { ! 448: php_stream_temp_data *ts = (php_stream_temp_data*)stream->abstract; ! 449: int ret; ! 450: ! 451: assert(ts != NULL); ! 452: ! 453: if (!ts->innerstream) { ! 454: *newoffs = -1; ! 455: return -1; ! 456: } ! 457: ret = php_stream_seek(ts->innerstream, offset, whence); ! 458: *newoffs = php_stream_tell(ts->innerstream); ! 459: stream->eof = ts->innerstream->eof; ! 460: ! 461: return ret; ! 462: } ! 463: /* }}} */ ! 464: ! 465: /* {{{ */ ! 466: static int php_stream_temp_cast(php_stream *stream, int castas, void **ret TSRMLS_DC) ! 467: { ! 468: php_stream_temp_data *ts = (php_stream_temp_data*)stream->abstract; ! 469: php_stream *file; ! 470: size_t memsize; ! 471: char *membuf; ! 472: off_t pos; ! 473: ! 474: assert(ts != NULL); ! 475: ! 476: if (!ts->innerstream) { ! 477: return FAILURE; ! 478: } ! 479: if (php_stream_is(ts->innerstream, PHP_STREAM_IS_STDIO)) { ! 480: return php_stream_cast(ts->innerstream, castas, ret, 0); ! 481: } ! 482: ! 483: /* we are still using a memory based backing. If they are if we can be ! 484: * a FILE*, say yes because we can perform the conversion. ! 485: * If they actually want to perform the conversion, we need to switch ! 486: * the memory stream to a tmpfile stream */ ! 487: ! 488: if (ret == NULL && castas == PHP_STREAM_AS_STDIO) { ! 489: return SUCCESS; ! 490: } ! 491: ! 492: /* say "no" to other stream forms */ ! 493: if (ret == NULL) { ! 494: return FAILURE; ! 495: } ! 496: ! 497: /* perform the conversion and then pass the request on to the innerstream */ ! 498: membuf = php_stream_memory_get_buffer(ts->innerstream, &memsize); ! 499: file = php_stream_fopen_tmpfile(); ! 500: php_stream_write(file, membuf, memsize); ! 501: pos = php_stream_tell(ts->innerstream); ! 502: ! 503: php_stream_close(ts->innerstream); ! 504: ts->innerstream = file; ! 505: php_stream_seek(ts->innerstream, pos, SEEK_SET); ! 506: ! 507: return php_stream_cast(ts->innerstream, castas, ret, 1); ! 508: } ! 509: /* }}} */ ! 510: ! 511: static int php_stream_temp_stat(php_stream *stream, php_stream_statbuf *ssb TSRMLS_DC) /* {{{ */ ! 512: { ! 513: php_stream_temp_data *ts = (php_stream_temp_data*)stream->abstract; ! 514: ! 515: if (!ts || !ts->innerstream) { ! 516: return -1; ! 517: } ! 518: return php_stream_stat(ts->innerstream, ssb); ! 519: } ! 520: /* }}} */ ! 521: ! 522: static int php_stream_temp_set_option(php_stream *stream, int option, int value, void *ptrparam TSRMLS_DC) /* {{{ */ ! 523: { ! 524: php_stream_temp_data *ts = (php_stream_temp_data*)stream->abstract; ! 525: ! 526: switch(option) { ! 527: case PHP_STREAM_OPTION_META_DATA_API: ! 528: if (ts->meta) { ! 529: zend_hash_copy(Z_ARRVAL_P((zval*)ptrparam), Z_ARRVAL_P(ts->meta), (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval*)); ! 530: } ! 531: return PHP_STREAM_OPTION_RETURN_OK; ! 532: default: ! 533: if (ts->innerstream) { ! 534: return php_stream_set_option(ts->innerstream, option, value, ptrparam); ! 535: } ! 536: return PHP_STREAM_OPTION_RETURN_NOTIMPL; ! 537: } ! 538: } ! 539: /* }}} */ ! 540: ! 541: PHPAPI php_stream_ops php_stream_temp_ops = { ! 542: php_stream_temp_write, php_stream_temp_read, ! 543: php_stream_temp_close, php_stream_temp_flush, ! 544: "TEMP", ! 545: php_stream_temp_seek, ! 546: php_stream_temp_cast, ! 547: php_stream_temp_stat, ! 548: php_stream_temp_set_option ! 549: }; ! 550: ! 551: /* }}} */ ! 552: ! 553: /* {{{ _php_stream_temp_create */ ! 554: PHPAPI php_stream *_php_stream_temp_create(int mode, size_t max_memory_usage STREAMS_DC TSRMLS_DC) ! 555: { ! 556: php_stream_temp_data *self; ! 557: php_stream *stream; ! 558: ! 559: self = ecalloc(1, sizeof(*self)); ! 560: self->smax = max_memory_usage; ! 561: self->mode = mode; ! 562: self->meta = NULL; ! 563: stream = php_stream_alloc_rel(&php_stream_temp_ops, self, 0, mode & TEMP_STREAM_READONLY ? "rb" : "w+b"); ! 564: stream->flags |= PHP_STREAM_FLAG_NO_BUFFER; ! 565: self->innerstream = php_stream_memory_create_rel(mode); ! 566: php_stream_auto_cleanup(self->innerstream); /* do not warn if innerstream is GC'ed before stream */ ! 567: ((php_stream_memory_data*)self->innerstream->abstract)->owner_ptr = &self->innerstream; ! 568: ! 569: return stream; ! 570: } ! 571: /* }}} */ ! 572: ! 573: ! 574: /* {{{ _php_stream_temp_open */ ! 575: PHPAPI php_stream *_php_stream_temp_open(int mode, size_t max_memory_usage, char *buf, size_t length STREAMS_DC TSRMLS_DC) ! 576: { ! 577: php_stream *stream; ! 578: php_stream_temp_data *ts; ! 579: off_t newoffs; ! 580: ! 581: if ((stream = php_stream_temp_create_rel(mode, max_memory_usage)) != NULL) { ! 582: if (length) { ! 583: assert(buf != NULL); ! 584: php_stream_temp_write(stream, buf, length TSRMLS_CC); ! 585: php_stream_temp_seek(stream, 0, SEEK_SET, &newoffs TSRMLS_CC); ! 586: } ! 587: ts = (php_stream_temp_data*)stream->abstract; ! 588: assert(ts != NULL); ! 589: ts->mode = mode; ! 590: } ! 591: return stream; ! 592: } ! 593: /* }}} */ ! 594: ! 595: PHPAPI php_stream_ops php_stream_rfc2397_ops = { ! 596: php_stream_temp_write, php_stream_temp_read, ! 597: php_stream_temp_close, php_stream_temp_flush, ! 598: "RFC2397", ! 599: php_stream_temp_seek, ! 600: php_stream_temp_cast, ! 601: php_stream_temp_stat, ! 602: php_stream_temp_set_option ! 603: }; ! 604: ! 605: static php_stream * php_stream_url_wrap_rfc2397(php_stream_wrapper *wrapper, char *path, char *mode, int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC) /* {{{ */ ! 606: { ! 607: php_stream *stream; ! 608: php_stream_temp_data *ts; ! 609: char *comma, *semi, *sep, *key; ! 610: size_t mlen, dlen, plen, vlen; ! 611: off_t newoffs; ! 612: zval *meta = NULL; ! 613: int base64 = 0, ilen; ! 614: ! 615: if (memcmp(path, "data:", 5)) { ! 616: return NULL; ! 617: } ! 618: ! 619: path += 5; ! 620: dlen = strlen(path); ! 621: ! 622: if (dlen >= 2 && path[0] == '/' && path[1] == '/') { ! 623: dlen -= 2; ! 624: path += 2; ! 625: } ! 626: ! 627: if ((comma = memchr(path, ',', dlen)) == NULL) { ! 628: php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "rfc2397: no comma in URL"); ! 629: return NULL; ! 630: } ! 631: ! 632: if (comma != path) { ! 633: /* meta info */ ! 634: mlen = comma - path; ! 635: dlen -= mlen; ! 636: semi = memchr(path, ';', mlen); ! 637: sep = memchr(path, '/', mlen); ! 638: ! 639: if (!semi && !sep) { ! 640: php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "rfc2397: illegal media type"); ! 641: return NULL; ! 642: } ! 643: ! 644: MAKE_STD_ZVAL(meta); ! 645: array_init(meta); ! 646: if (!semi) { /* there is only a mime type */ ! 647: add_assoc_stringl(meta, "mediatype", path, mlen, 1); ! 648: mlen = 0; ! 649: } else if (sep && sep < semi) { /* there is a mime type */ ! 650: plen = semi - path; ! 651: add_assoc_stringl(meta, "mediatype", path, plen, 1); ! 652: mlen -= plen; ! 653: path += plen; ! 654: } else if (semi != path || mlen != sizeof(";base64")-1 || memcmp(path, ";base64", sizeof(";base64")-1)) { /* must be error since parameters are only allowed after mediatype */ ! 655: zval_ptr_dtor(&meta); ! 656: php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "rfc2397: illegal media type"); ! 657: return NULL; ! 658: } ! 659: /* get parameters and potentially ';base64' */ ! 660: while(semi && (semi == path)) { ! 661: path++; ! 662: mlen--; ! 663: sep = memchr(path, '=', mlen); ! 664: semi = memchr(path, ';', mlen); ! 665: if (!sep || (semi && semi < sep)) { /* must be ';base64' or failure */ ! 666: if (mlen != sizeof("base64")-1 || memcmp(path, "base64", sizeof("base64")-1)) { ! 667: /* must be error since parameters are only allowed after mediatype and we have no '=' sign */ ! 668: zval_ptr_dtor(&meta); ! 669: php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "rfc2397: illegal parameter"); ! 670: return NULL; ! 671: } ! 672: base64 = 1; ! 673: mlen -= sizeof("base64") - 1; ! 674: path += sizeof("base64") - 1; ! 675: break; ! 676: } ! 677: /* found parameter ... the heart of cs ppl lies in +1/-1 or was it +2 this time? */ ! 678: plen = sep - path; ! 679: vlen = (semi ? semi - sep : mlen - plen) - 1 /* '=' */; ! 680: key = estrndup(path, plen); ! 681: add_assoc_stringl_ex(meta, key, plen + 1, sep + 1, vlen, 1); ! 682: efree(key); ! 683: plen += vlen + 1; ! 684: mlen -= plen; ! 685: path += plen; ! 686: } ! 687: if (mlen) { ! 688: zval_ptr_dtor(&meta); ! 689: php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "rfc2397: illegal URL"); ! 690: return NULL; ! 691: } ! 692: } else { ! 693: MAKE_STD_ZVAL(meta); ! 694: array_init(meta); ! 695: } ! 696: add_assoc_bool(meta, "base64", base64); ! 697: ! 698: /* skip ',' */ ! 699: comma++; ! 700: dlen--; ! 701: ! 702: if (base64) { ! 703: comma = (char*)php_base64_decode((const unsigned char *)comma, dlen, &ilen); ! 704: if (!comma) { ! 705: zval_ptr_dtor(&meta); ! 706: php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "rfc2397: unable to decode"); ! 707: return NULL; ! 708: } ! 709: } else { ! 710: comma = estrndup(comma, dlen); ! 711: ilen = dlen = php_url_decode(comma, dlen); ! 712: } ! 713: ! 714: if ((stream = php_stream_temp_create_rel(0, ~0u)) != NULL) { ! 715: /* store data */ ! 716: php_stream_temp_write(stream, comma, ilen TSRMLS_CC); ! 717: php_stream_temp_seek(stream, 0, SEEK_SET, &newoffs TSRMLS_CC); ! 718: /* set special stream stuff (enforce exact mode) */ ! 719: vlen = strlen(mode); ! 720: if (vlen >= sizeof(stream->mode)) { ! 721: vlen = sizeof(stream->mode) - 1; ! 722: } ! 723: memcpy(stream->mode, mode, vlen); ! 724: stream->mode[vlen] = '\0'; ! 725: stream->ops = &php_stream_rfc2397_ops; ! 726: ts = (php_stream_temp_data*)stream->abstract; ! 727: assert(ts != NULL); ! 728: ts->mode = mode && mode[0] == 'r' && mode[1] != '+' ? TEMP_STREAM_READONLY : 0; ! 729: ts->meta = meta; ! 730: } ! 731: efree(comma); ! 732: ! 733: return stream; ! 734: } ! 735: ! 736: PHPAPI php_stream_wrapper_ops php_stream_rfc2397_wops = { ! 737: php_stream_url_wrap_rfc2397, ! 738: NULL, /* close */ ! 739: NULL, /* fstat */ ! 740: NULL, /* stat */ ! 741: NULL, /* opendir */ ! 742: "RFC2397", ! 743: NULL, /* unlink */ ! 744: NULL, /* rename */ ! 745: NULL, /* mkdir */ ! 746: NULL /* rmdir */ ! 747: }; ! 748: ! 749: PHPAPI php_stream_wrapper php_stream_rfc2397_wrapper = { ! 750: &php_stream_rfc2397_wops, ! 751: NULL, ! 752: 1, /* is_url */ ! 753: }; ! 754: ! 755: /* ! 756: * Local variables: ! 757: * tab-width: 4 ! 758: * c-basic-offset: 4 ! 759: * End: ! 760: * vim600: noet sw=4 ts=4 fdm=marker ! 761: * vim<600: noet sw=4 ts=4 ! 762: */