Annotation of embedaddon/php/main/streams/memory.c, revision 1.1
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: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>