Skip to content

Commit e78adee

Browse files
committed
stream: implement initial changes to control filter seeking
1 parent 65b9306 commit e78adee

File tree

3 files changed

+99
-6
lines changed

3 files changed

+99
-6
lines changed

main/streams/filter.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,23 @@ PHPAPI php_stream_filter *php_stream_filter_create(const char *filtername, zval
259259
return filter;
260260
}
261261

262+
PHPAPI php_stream_filter *_php_stream_filter_alloc_ex(const php_stream_filter_ops *fops,
263+
const php_stream_filter_extra_ops *feops, void *abstract, uint8_t persistent, uint16_t flags STREAMS_DC)
264+
{
265+
php_stream_filter *filter;
266+
267+
filter = (php_stream_filter*) pemalloc_rel_orig(sizeof(php_stream_filter), persistent);
268+
memset(filter, 0, sizeof(php_stream_filter));
269+
270+
filter->fops = fops;
271+
filter->feops = feops;
272+
filter->seekable = flags & PHP_STREAM_FILTER_SEEKABLE_MASK;
273+
Z_PTR(filter->abstract) = abstract;
274+
filter->is_persistent = persistent;
275+
276+
return filter;
277+
}
278+
262279
PHPAPI php_stream_filter *_php_stream_filter_alloc(const php_stream_filter_ops *fops, void *abstract, uint8_t persistent STREAMS_DC)
263280
{
264281
php_stream_filter *filter;

main/streams/php_stream_filter_api.h

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@
3434
#define PHP_STREAM_FILTER_WRITE 0x0002
3535
#define PHP_STREAM_FILTER_ALL (PHP_STREAM_FILTER_READ | PHP_STREAM_FILTER_WRITE)
3636

37+
#define PHP_STREAM_FILTER_SEEKABLE_NEVER 0
38+
#define PHP_STREAM_FILTER_SEEKABLE_START 1
39+
#define PHP_STREAM_FILTER_SEEKABLE_ALWAYS 2
40+
#define PHP_STREAM_FILTER_SEEKABLE_MASK 3
41+
3742
typedef struct _php_stream_bucket php_stream_bucket;
3843
typedef struct _php_stream_bucket_brigade php_stream_bucket_brigade;
3944

@@ -94,6 +99,26 @@ typedef struct _php_stream_filter_ops {
9499

95100
} php_stream_filter_ops;
96101

102+
typedef struct _php_stream_filter_extra_ops {
103+
/* it should indicate whether seeking is supported and possibly modify internal state */
104+
zend_result (*seek)(
105+
php_stream *stream,
106+
php_stream_filter *thisfilter,
107+
zend_off_t offset,
108+
int whence
109+
);
110+
111+
/* this is a generic interface for possible further extensions */
112+
zend_result (*set_option)(
113+
php_stream *stream,
114+
php_stream_filter *thisfilter,
115+
int option,
116+
void *value,
117+
size_t size
118+
);
119+
120+
} php_stream_filter_extra_ops;
121+
97122
typedef struct _php_stream_filter_chain {
98123
php_stream_filter *head, *tail;
99124

@@ -103,10 +128,12 @@ typedef struct _php_stream_filter_chain {
103128

104129
struct _php_stream_filter {
105130
const php_stream_filter_ops *fops;
131+
const php_stream_filter_extra_ops *feops;
106132
zval abstract; /* for use by filter implementation */
107133
php_stream_filter *next;
108134
php_stream_filter *prev;
109-
int is_persistent;
135+
bool is_persistent;
136+
uint8_t seekable;
110137

111138
/* link into stream and chain */
112139
php_stream_filter_chain *chain;
@@ -128,8 +155,12 @@ PHPAPI zend_result _php_stream_filter_flush(php_stream_filter *filter, bool fini
128155
PHPAPI php_stream_filter *php_stream_filter_remove(php_stream_filter *filter, bool call_dtor);
129156
PHPAPI void php_stream_filter_free(php_stream_filter *filter);
130157
PHPAPI php_stream_filter *_php_stream_filter_alloc(const php_stream_filter_ops *fops, void *abstract, uint8_t persistent STREAMS_DC);
158+
PHPAPI php_stream_filter *_php_stream_filter_alloc_ex(const php_stream_filter_ops *fops,
159+
const php_stream_filter_extra_ops *feops, void *abstract, uint8_t persistent, uint16_t flags STREAMS_DC);
131160
END_EXTERN_C()
132161
#define php_stream_filter_alloc(fops, thisptr, persistent) _php_stream_filter_alloc((fops), (thisptr), (persistent) STREAMS_CC)
162+
#define php_stream_filter_alloc_ex(fops, feops, thisptr, persistent) \
163+
_php_stream_filter_alloc_ex((fops), (feops), (thisptr), (persistent) STREAMS_CC)
133164
#define php_stream_filter_alloc_rel(fops, thisptr, persistent) _php_stream_filter_alloc((fops), (thisptr), (persistent) STREAMS_REL_CC)
134165
#define php_stream_filter_prepend(chain, filter) _php_stream_filter_prepend((chain), (filter))
135166
#define php_stream_filter_append(chain, filter) _php_stream_filter_append((chain), (filter))

main/streams/streams.c

Lines changed: 50 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1360,6 +1360,40 @@ PHPAPI zend_off_t _php_stream_tell(const php_stream *stream)
13601360
return stream->position;
13611361
}
13621362

1363+
static bool php_stream_are_filters_seekable(php_stream_filter *filter, bool is_start_seeking)
1364+
{
1365+
while (filter) {
1366+
if (filter->seekable == PHP_STREAM_FILTER_SEEKABLE_NEVER ||
1367+
(!is_start_seeking && filter->seekable == PHP_STREAM_FILTER_SEEKABLE_START)) {
1368+
php_error_docref(NULL, E_WARNING, "Stream filter %s is not seekable", filter->fops->label);
1369+
return false;
1370+
}
1371+
filter = filter->next;
1372+
}
1373+
return true;
1374+
}
1375+
1376+
static zend_result php_stream_filters_seek(php_stream *stream, php_stream_filter *filter, bool is_start_seeking)
1377+
{
1378+
while (filter) {
1379+
if ((filter->seekable == PHP_STREAM_FILTER_SEEKABLE_START && is_start_seeking &&
1380+
filter->feops->seek(stream, filter, 0, SEEK_SET))) {
1381+
php_error_docref(NULL, E_WARNING, "Stream filter seeking for %s failed", filter->fops->label);
1382+
return FAILURE;
1383+
}
1384+
filter = filter->next;
1385+
}
1386+
return SUCCESS;
1387+
}
1388+
1389+
static zend_result php_stream_filters_seek_all(php_stream *stream, bool is_start_seeking)
1390+
{
1391+
return php_stream_filters_seek(stream, stream->writefilters.head, is_start_seeking) == SUCCESS &&
1392+
php_stream_filters_seek(stream, stream->readfilters.head, is_start_seeking) == SUCCESS;
1393+
}
1394+
1395+
1396+
13631397
PHPAPI int _php_stream_seek(php_stream *stream, zend_off_t offset, int whence)
13641398
{
13651399
if (stream->fclose_stdiocast == PHP_STREAM_FCLOSE_FOPENCOOKIE) {
@@ -1372,6 +1406,18 @@ PHPAPI int _php_stream_seek(php_stream *stream, zend_off_t offset, int whence)
13721406
}
13731407
}
13741408

1409+
bool is_start_seeking = whence == SEEK_SET && offset == 0;
1410+
1411+
if (stream->writefilters.head) {
1412+
_php_stream_flush(stream, 0);
1413+
if (!php_stream_are_filters_seekable(stream->writefilters.head, is_start_seeking)) {
1414+
return -1;
1415+
}
1416+
}
1417+
if (stream->readfilters.head && !php_stream_are_filters_seekable(stream->readfilters.head, is_start_seeking)) {
1418+
return -1;
1419+
}
1420+
13751421
/* handle the case where we are in the buffer */
13761422
if ((stream->flags & PHP_STREAM_FLAG_NO_BUFFER) == 0) {
13771423
switch(whence) {
@@ -1381,6 +1427,7 @@ PHPAPI int _php_stream_seek(php_stream *stream, zend_off_t offset, int whence)
13811427
stream->position += offset;
13821428
stream->eof = 0;
13831429
stream->fatal_error = 0;
1430+
php_stream_filters_seek_all(stream, is_start_seeking);
13841431
return 0;
13851432
}
13861433
break;
@@ -1391,6 +1438,7 @@ PHPAPI int _php_stream_seek(php_stream *stream, zend_off_t offset, int whence)
13911438
stream->position = offset;
13921439
stream->eof = 0;
13931440
stream->fatal_error = 0;
1441+
php_stream_filters_seek_all(stream, is_start_seeking);
13941442
return 0;
13951443
}
13961444
break;
@@ -1400,11 +1448,6 @@ PHPAPI int _php_stream_seek(php_stream *stream, zend_off_t offset, int whence)
14001448

14011449
if (stream->ops->seek && (stream->flags & PHP_STREAM_FLAG_NO_SEEK) == 0) {
14021450
int ret;
1403-
1404-
if (stream->writefilters.head) {
1405-
_php_stream_flush(stream, 0);
1406-
}
1407-
14081451
switch(whence) {
14091452
case SEEK_CUR:
14101453
ZEND_ASSERT(stream->position >= 0);
@@ -1431,6 +1474,8 @@ PHPAPI int _php_stream_seek(php_stream *stream, zend_off_t offset, int whence)
14311474
/* invalidate the buffer contents */
14321475
stream->readpos = stream->writepos = 0;
14331476

1477+
php_stream_filters_seek_all(stream, is_start_seeking);
1478+
14341479
return ret;
14351480
}
14361481
/* else the stream has decided that it can't support seeking after all;

0 commit comments

Comments
 (0)