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