Annotation of embedaddon/php/main/streams/memory.c, revision 1.1.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>