/* OBJECTS_FIXME: This whole extension needs going through. The use of objects looks pretty broken here */
- static void browscap_entry_dtor_request(zval *zvalue) /* {{{ */
+ static void browscap_entry_dtor(zval *zvalue)
{
- if (Z_TYPE_P(zvalue) == IS_ARRAY) {
- zend_hash_destroy(Z_ARRVAL_P(zvalue));
- efree(Z_ARR_P(zvalue));
- } else if (Z_TYPE_P(zvalue) == IS_STRING) {
- zend_string_release(Z_STR_P(zvalue));
+ browscap_entry *entry = Z_PTR_P(zvalue);
+ zend_string_release(entry->pattern);
+ if (entry->parent) {
+ zend_string_release(entry->parent);
}
+ efree(entry);
}
- /* }}} */
- static void browscap_entry_dtor_persistent(zval *zvalue) /* {{{ */ {
- if (Z_TYPE_P(zvalue) == IS_ARRAY) {
- zend_hash_destroy(Z_ARRVAL_P(zvalue));
- free(Z_ARR_P(zvalue));
- } else if (Z_TYPE_P(zvalue) == IS_STRING) {
- zend_string_release(Z_STR_P(zvalue));
+ static void browscap_entry_dtor_persistent(zval *zvalue)
+ {
+ browscap_entry *entry = Z_PTR_P(zvalue);
+ zend_string_release(entry->pattern);
+ if (entry->parent) {
+ zend_string_release(entry->parent);
}
+ pefree(entry, 1);
+ }
+
+ static inline zend_bool is_placeholder(char c) {
+ return c == '?' || c == '*';
+ }
+
+ /* Length of prefix not containing any wildcards */
+ static uint8_t browscap_compute_prefix_len(zend_string *pattern) {
+ size_t i;
+ for (i = 0; i < ZSTR_LEN(pattern); i++) {
+ if (is_placeholder(ZSTR_VAL(pattern)[i])) {
+ break;
+ }
+ }
+ return MIN(i, UINT8_MAX);
+ }
+
+ static size_t browscap_compute_contains(
+ zend_string *pattern, size_t start_pos,
+ uint16_t *contains_start, uint8_t *contains_len) {
+ size_t i = start_pos;
+ /* Find first non-placeholder character after prefix */
+ for (; i < ZSTR_LEN(pattern); i++) {
+ if (!is_placeholder(ZSTR_VAL(pattern)[i])) {
+ /* Skip the case of a single non-placeholder character.
+ * Let's try to find something longer instead. */
+ if (i + 1 < ZSTR_LEN(pattern) &&
+ !is_placeholder(ZSTR_VAL(pattern)[i + 1])) {
+ break;
+ }
+ }
+ }
+ *contains_start = i;
+
+ /* Find first placeholder character after that */
+ for (; i < ZSTR_LEN(pattern); i++) {
+ if (is_placeholder(ZSTR_VAL(pattern)[i])) {
+ break;
+ }
+ }
+ *contains_len = MIN(i - *contains_start, UINT8_MAX);
+ return i;
+ }
+
+ /* Length of regex, including escapes, anchors, etc. */
+ static size_t browscap_compute_regex_len(zend_string *pattern) {
+ size_t i, len = ZSTR_LEN(pattern);
+ for (i = 0; i < ZSTR_LEN(pattern); i++) {
+ switch (ZSTR_VAL(pattern)[i]) {
+ case '*':
+ case '.':
+ case '\\':
+ case '(':
+ case ')':
+ case '~':
+ case '+':
+ len++;
+ break;
+ }
+ }
+
+ return len + sizeof("~^$~")-1;
}
- /* }}} */
- static void convert_browscap_pattern(zval *pattern, int persistent) /* {{{ */
+ static zend_string *browscap_convert_pattern(zend_string *pattern, int persistent) /* {{{ */
{
- int i, j=0;
+ size_t i, j=0;
char *t;
zend_string *res;
char *lc_pattern;
static int browscap_read_file(char *filename, browser_data *browdata, int persistent) /* {{{ */
{
- zend_file_handle fh = {{0}};
+ zend_file_handle fh;
+ browscap_parser_ctx ctx = {0};
if (filename == NULL || filename[0] == '\0') {
return FAILURE;