From 9b6bb2d451cd43918214ab7d6d9dd7ec8ae0ee3c Mon Sep 17 00:00:00 2001 From: Bob Weinand Date: Thu, 21 May 2015 04:17:17 +0200 Subject: [PATCH] Add support for string dictionaries, fix array dictionaries ({de,in}flate) --- ext/zlib/tests/dictionary_usage.phpt | 5 ++ ext/zlib/zlib.c | 123 ++++++++++++++++----------- 2 files changed, 80 insertions(+), 48 deletions(-) diff --git a/ext/zlib/tests/dictionary_usage.phpt b/ext/zlib/tests/dictionary_usage.phpt index 8ffa9e8bcd..f7ef3b3a9c 100644 --- a/ext/zlib/tests/dictionary_usage.phpt +++ b/ext/zlib/tests/dictionary_usage.phpt @@ -9,6 +9,10 @@ $r = deflate_init(ZLIB_ENCODING_DEFLATE, ["dictionary" => $dict]); $a = deflate_add($r, "abdcde", ZLIB_FINISH); var_dump($a); +$r = deflate_init(ZLIB_ENCODING_DEFLATE, ["dictionary" => implode("\0", $dict)."\0"]); +$dictStr_a = deflate_add($r, "abdcde", ZLIB_FINISH); +var_dump($dictStr_a === $a); + $r = inflate_init(ZLIB_ENCODING_DEFLATE, ["dictionary" => $dict]); var_dump(inflate_add($r, $a, ZLIB_FINISH)); @@ -19,6 +23,7 @@ var_dump(inflate_add($r, $a, ZLIB_FINISH)); ?> --EXPECTF-- string(%d) "%s" +bool(true) string(6) "abdcde" Warning: inflate_add(): dictionary does not match expected dictionary (incorrect adler32 hash) in %s on line %d diff --git a/ext/zlib/zlib.c b/ext/zlib/zlib.c index 8169424362..b4b95e85a5 100644 --- a/ext/zlib/zlib.c +++ b/ext/zlib/zlib.c @@ -759,60 +759,87 @@ static zend_bool zlib_create_dictionary_string(HashTable *options, char **dict, zval *option_buffer; if (options && (option_buffer = zend_hash_str_find(options, ZEND_STRL("dictionary"))) != NULL) { - HashTable *dictionary; - ZVAL_DEREF(option_buffer); - if (Z_TYPE_P(option_buffer) != IS_ARRAY) { - php_error_docref(NULL, E_WARNING, "dictionary must be of type array, got %s", zend_get_type_by_const(Z_TYPE_P(option_buffer))); - return 0; - } - dictionary = Z_ARR_P(option_buffer); - - if (zend_hash_num_elements(dictionary) > 0) { - char *dictptr; - zval *cur; - zend_string **strings = emalloc(sizeof(zend_string *) * zend_hash_num_elements(dictionary)); - zend_string **end, **ptr = strings - 1; - - ZEND_HASH_FOREACH_VAL(dictionary, cur) { + switch (Z_TYPE_P(option_buffer)) { + case IS_STRING: { + zend_string *str = Z_STR_P(option_buffer); int i; - - *++ptr = zval_get_string(cur); - if (!*ptr || (*ptr)->len == 0) { - if (*ptr) { - efree(*ptr); - } - while (--ptr >= strings) { - efree(ptr); + zend_bool last_null = 1; + + for (i = 0; i < str->len; i++) { + if (str->val[i]) { + last_null = 0; + } else { + if (last_null) { + php_error_docref(NULL, E_WARNING, "dictionary string must not contain empty entries (two consecutive NULL-bytes or one at the very beginning)"); + return 0; + } + last_null = 1; } - efree(strings); - php_error_docref(NULL, E_WARNING, "dictionary entries must be non-empty strings"); - return 0; } - for (i = 0; i < (*ptr)->len; i++) { - if ((*ptr)->val[i] == 0) { - do { - efree(ptr); - } while (--ptr >= strings); - efree(strings); - php_error_docref(NULL, E_WARNING, "dictionary entries must not contain a NULL-byte"); - return 0; - } + if (!last_null) { + php_error_docref(NULL, E_WARNING, "dictionary string must be NULL-byte terminated (each dictionary entry has to be NULL-terminated)"); + } + + *dict = emalloc(str->len); + memcpy(*dict, str->val, str->len); + *dictlen = str->len; + } break; + + case IS_ARRAY: { + HashTable *dictionary = Z_ARR_P(option_buffer); + + if (zend_hash_num_elements(dictionary) > 0) { + char *dictptr; + zval *cur; + zend_string **strings = emalloc(sizeof(zend_string *) * zend_hash_num_elements(dictionary)); + zend_string **end, **ptr = strings - 1; + + ZEND_HASH_FOREACH_VAL(dictionary, cur) { + int i; + + *++ptr = zval_get_string(cur); + if (!*ptr || (*ptr)->len == 0) { + if (*ptr) { + efree(*ptr); + } + while (--ptr >= strings) { + efree(ptr); + } + efree(strings); + php_error_docref(NULL, E_WARNING, "dictionary entries must be non-empty strings"); + return 0; + } + for (i = 0; i < (*ptr)->len; i++) { + if ((*ptr)->val[i] == 0) { + do { + efree(ptr); + } while (--ptr >= strings); + efree(strings); + php_error_docref(NULL, E_WARNING, "dictionary entries must not contain a NULL-byte"); + return 0; + } + } + + *dictlen += (*ptr)->len + 1; + } ZEND_HASH_FOREACH_END(); + + dictptr = *dict = emalloc(*dictlen); + ptr = strings; + end = strings + zend_hash_num_elements(dictionary); + do { + memcpy(dictptr, (*ptr)->val, (*ptr)->len); + dictptr += (*ptr)->len; + *dictptr++ = 0; + zend_string_release(*ptr); + } while (++ptr != end); + efree(strings); } + } break; - *dictlen += (*ptr)->len + 1; - } ZEND_HASH_FOREACH_END(); - - dictptr = *dict = emalloc(*dictlen); - ptr = strings; - end = strings + zend_hash_num_elements(dictionary); - do { - memcpy(dictptr, *ptr, (*ptr)->len); - dictptr += (*ptr)->len; - *dictptr++ = 0; - zend_string_release(*ptr); - } while (++ptr != end); - efree(strings); + default: + php_error_docref(NULL, E_WARNING, "dictionary must be of type zero-terminated string or array, got %s", zend_get_type_by_const(Z_TYPE_P(option_buffer))); + return 0; } } -- 2.40.0