diff --git a/ext/standard/string.c b/ext/standard/string.c index a39105e20bd4e..9c1031effb52b 100644 --- a/ext/standard/string.c +++ b/ext/standard/string.c @@ -117,8 +117,16 @@ void register_string_constants(INIT_FUNC_ARGS) int php_tag_find(char *tag, size_t len, const char *set); +#ifdef PHP_WIN32 +# define SET_ALIGNED(alignment, decl) __declspec(align(alignment)) decl +#elif HAVE_ATTRIBUTE_ALIGNED +# define SET_ALIGNED(alignment, decl) decl __attribute__ ((__aligned__ (alignment))) +#else +# define SET_ALIGNED(alignment, decl) decl +#endif + /* this is read-only, so it's ok */ -static char hexconvtab[] = "0123456789abcdef"; +SET_ALIGNED(16, static char hexconvtab[]) = "0123456789abcdef"; /* localeconv mutex */ #ifdef ZTS @@ -155,25 +163,22 @@ static zend_string *php_hex2bin(const unsigned char *old, const size_t oldlen) for (i = j = 0; i < target_length; i++) { unsigned char c = old[j++]; + unsigned char l = c & ~0x20; + int is_letter = ((unsigned int) ((l - 'A') ^ (l - 'F' - 1))) >> (8 * sizeof(unsigned int) - 1); unsigned char d; - if (c >= '0' && c <= '9') { - d = (c - '0') << 4; - } else if (c >= 'a' && c <= 'f') { - d = (c - 'a' + 10) << 4; - } else if (c >= 'A' && c <= 'F') { - d = (c - 'A' + 10) << 4; + /* basically (c >= '0' && c <= '9') || (l >= 'A' && l <= 'F') */ + if (EXPECTED((((c ^ '0') - 10) >> (8 * sizeof(unsigned int) - 1)) | is_letter)) { + d = (l - 0x10 - 0x27 * is_letter) << 4; } else { zend_string_free(str); return NULL; } c = old[j++]; - if (c >= '0' && c <= '9') { - d |= c - '0'; - } else if (c >= 'a' && c <= 'f') { - d |= c - 'a' + 10; - } else if (c >= 'A' && c <= 'F') { - d |= c - 'A' + 10; + l = c & ~0x20; + is_letter = ((unsigned int) ((l - 'A') ^ (l - 'F' - 1))) >> (8 * sizeof(unsigned int) - 1); + if (EXPECTED((((c ^ '0') - 10) >> (8 * sizeof(unsigned int) - 1)) | is_letter)) { + d |= l - 0x10 - 0x27 * is_letter; } else { zend_string_free(str); return NULL;