Skip to content

Commit aa898d9

Browse files
committed
stream: implement initial changes to control filter seeking
1 parent ca7f556 commit aa898d9

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
@@ -260,6 +260,23 @@ PHPAPI php_stream_filter *php_stream_filter_create(const char *filtername, zval
260260
return filter;
261261
}
262262

263+
PHPAPI php_stream_filter *_php_stream_filter_alloc_ex(const php_stream_filter_ops *fops,
264+
const php_stream_filter_extra_ops *feops, void *abstract, uint8_t persistent, uint16_t flags STREAMS_DC)
265+
{
266+
php_stream_filter *filter;
267+
268+
filter = (php_stream_filter*) pemalloc_rel_orig(sizeof(php_stream_filter), persistent);
269+
memset(filter, 0, sizeof(php_stream_filter));
270+
271+
filter->fops = fops;
272+
filter->feops = feops;
273+
filter->seekable = flags & PHP_STREAM_FILTER_SEEKABLE_MASK;
274+
Z_PTR(filter->abstract) = abstract;
275+
filter->is_persistent = persistent;
276+
277+
return filter;
278+
}
279+
263280
PHPAPI php_stream_filter *_php_stream_filter_alloc(const php_stream_filter_ops *fops, void *abstract, uint8_t persistent STREAMS_DC)
264281
{
265282
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
@@ -1361,6 +1361,40 @@ PHPAPI zend_off_t _php_stream_tell(const php_stream *stream)
13611361
return stream->position;
13621362
}
13631363

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

1410+
bool is_start_seeking = whence == SEEK_SET && offset == 0;
1411+
1412+
if (stream->writefilters.head) {
1413+
_php_stream_flush(stream, 0);
1414+
if (!php_stream_are_filters_seekable(stream->writefilters.head, is_start_seeking)) {
1415+
return -1;
1416+
}
1417+
}
1418+
if (stream->readfilters.head && !php_stream_are_filters_seekable(stream->readfilters.head, is_start_seeking)) {
1419+
return -1;
1420+
}
1421+
13761422
/* handle the case where we are in the buffer */
13771423
if ((stream->flags & PHP_STREAM_FLAG_NO_BUFFER) == 0) {
13781424
switch(whence) {
@@ -1382,6 +1428,7 @@ PHPAPI int _php_stream_seek(php_stream *stream, zend_off_t offset, int whence)
13821428
stream->position += offset;
13831429
stream->eof = 0;
13841430
stream->fatal_error = 0;
1431+
php_stream_filters_seek_all(stream, is_start_seeking);
13851432
return 0;
13861433
}
13871434
break;
@@ -1392,6 +1439,7 @@ PHPAPI int _php_stream_seek(php_stream *stream, zend_off_t offset, int whence)
13921439
stream->position = offset;
13931440
stream->eof = 0;
13941441
stream->fatal_error = 0;
1442+
php_stream_filters_seek_all(stream, is_start_seeking);
13951443
return 0;
13961444
}
13971445
break;
@@ -1401,11 +1449,6 @@ PHPAPI int _php_stream_seek(php_stream *stream, zend_off_t offset, int whence)
14011449

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

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

0 commit comments

Comments
 (0)