[PATCH] New hexdump manipulation functions for PHP5
| From: | Alexander Demin | Date: | Thu, 14 Dec 2006 12:16:30 +0000 |
| Subject: | [PATCH] New hexdump manipulation functions for PHP5 | ||
| Groups: | php.internals | ||
| Request: | Send a blank email to internals+get-26952@lists.php.net to get a copy of this message | ||
Dear sirs,
this patch for PHP5 adds four new string functions into the extension
'standard':
- hexdump()
- packhex()
- smart_hexdump()
- smart_packhex()
The description of these functions and smart hexdump format in general is
attached in the file 'hexdump_descr.txt'.
I've tested this on PHP 5.2.0 and on the last CVS tree of PHP 5.2.0
Attachments:
1. hexdump_functions.patch - patch for the last CVS tree of the PHP 5.2.0.
It patches files 'ext/standard/basic_functions.c', 'ext/standard/config.m4',
'ext/standard/config.w32', 'win32/php5dllts.dsp'
2. hexdump.c and php_hexdump.h - files, that should be placed into
'ext/standard/', which implements the hexdump functions.
3. hexdump.phpt - test file for hexdump function, that should be placed into
'ext/standard/tests/strings/'
4. hexdump_descr.txt - detailed description of the hexdump functions
interface and smart hexdump format
If it needs to create any documentation stuff for help file (and translate
it, for example to russian), I will do it.
Thanks.
--
Regards,
Alexander Demin
demin@ots.ru
/* +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2006 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | | http://www.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Author: Alexander Demin <demin@ots.ru> | +----------------------------------------------------------------------+ */ #ifndef PHP_HEXDUMP_H #define PHP_HEXDUMP_H PHP_FUNCTION(hexdump); PHP_FUNCTION(packhex); PHP_FUNCTION(smart_hexdump); PHP_FUNCTION(smart_packhex); PHPAPI int php_hexdump(char *src, int src_len, char* delim, int delim_len, char **dest); PHPAPI int php_packhex(char *src, int src_len, zend_bool strict, char **dest); PHPAPI int php_smart_hexdump(char *src, int src_len, char **dest); PHPAPI int php_smart_packhex(char *src, int src_len, char **dest); #endif /* PHP_HEXDUMP_H */ /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: */ /* +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2006 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | | http://www.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Author: Alexander Demin <demin@ots.ru> | +----------------------------------------------------------------------+ */ #include "php.h" #include "php_hexdump.h" static const char php_hexdump_digits[] = "0123456789ABCDEF"; static const unsigned char php_hex_index[ 256 ] = { /* 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F */ /*00*/ 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, /*10*/ 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, /*20*/ 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, /*30*/ 0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,255,255,255,255,255,255, /* ASCII */ /*40*/ 255,0xa,0xb,0xc,0xd,0xe,0xf,255,255,255,255,255,255,255,255,255, /* ASCII */ /*50*/ 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, /*60*/ 255,0xa,0xb,0xc,0xd,0xe,0xf,255,255,255,255,255,255,255,255,255, /* ASCII */ /*70*/ 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, /*80*/ 255,0xa,0xb,0xc,0xd,0xe,0xf,255,255,255,255,255,255,255,255,255, /* EBCDIC */ /*90*/ 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, /*A0*/ 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, /*B0*/ 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, /*C0*/ 255,0xa,0xb,0xc,0xd,0xe,0xf,255,255,255,255,255,255,255,255,255, /* EBCDIC */ /*D0*/ 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, /*E0*/ 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, /*F0*/ 0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,255,255,255,255,255,255 /* EBCDIC */ }; static const char php_packhex_default_map[ 256 ] = { /* 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F */ /*00*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*10*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*20*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*30*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*40*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*50*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*60*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*70*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*80*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*90*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*A0*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*B0*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*C0*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*D0*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*E0*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*F0*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; PHPAPI int php_hexdump(char *src, int src_len, char *delim, int delim_len, char **dest) { char *p; int out_sz = src_len * 2; if (delim_len) out_sz += delim_len * src_len - 1; p = *dest = emalloc(out_sz + 1); while (src_len--) { *p++ = php_hexdump_digits[ (unsigned char)*src >> 4 ]; *p++ = php_hexdump_digits[ (unsigned char)*src++ & 0x0F ]; if (delim_len && src_len) { memcpy( p, delim, delim_len ); p += delim_len; } } *p = 0; return out_sz; } PHPAPI int php_packhex(char *src, int src_len, zend_bool strict, char **dest) { int dest_len = 0; int hex_count = 0; int first_nibble; unsigned char *p; int i; i = src_len; p = (unsigned char *)src; while (i--) { if (php_hex_index[ *p++ ] != 255) ++hex_count; else { if (strict) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Non-hexadecimal character at the position %d", i+1); return -1; } } } if (hex_count & 1) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Non-paired nibble at the end of the string"); --hex_count; } if (!hex_count) { *dest = NULL; return 0; } dest_len = hex_count / 2; p = *dest = emalloc(dest_len); first_nibble = 1; while (src_len--) { unsigned char ch = php_hex_index[ (unsigned char)*src++ ]; if (ch == 255) continue; if (first_nibble) *p = ch << 4; else *p++ |= ch & 0xf; first_nibble = !first_nibble; } return dest_len; } PHPAPI int php_smart_hexdump(char *src, int src_len, char **dest) { char *p; int out_sz = src_len * 4; char* map = (char *)php_packhex_default_map; int i; p = *dest = emalloc(out_sz + 1); *p = 0; for(i = 0; i < src_len; i++) { if (map[ (unsigned char)src[i] ] && src[i] != '<' && src[i] != '>') *p++ = src[i]; else { unsigned char ch; *p++ = '<'; for(; i < src_len && !map[ (unsigned char)src[i] ]; i++) { *p++ = php_hexdump_digits[ (unsigned char)src[i] >> 4 ]; *p++ = php_hexdump_digits[ (unsigned char)src[i] & 0x0F ]; } *p++ = '>'; if (i < src_len) *p++ = (unsigned char)src[i]; } } *p = 0; return p - *dest; } PHPAPI int php_smart_packhex(char *src, int src_len, char **dest) { int dest_len = src_len; int first_nibble; unsigned char *p; int i; p = *dest = emalloc(dest_len); for (i = 0; i < src_len; ) { char *o_pos = (char *)memchr( src + i, '<', src_len - i ); char *c_pos = (char *)memchr( src + i, '>', src_len - i ); char *v; if (!o_pos || !c_pos || o_pos > c_pos) { memcpy(p, src + i, src_len - i); p += src_len - i; break; } memcpy( p, src + i, o_pos - src - i ); p += o_pos - src - i; first_nibble = 1; for (o_pos++; o_pos < c_pos; o_pos++ ) { unsigned char ch = php_hex_index[ (unsigned char)*o_pos ]; if (ch == 255) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Non-hexadecimal character at the position %d", o_pos - src); return -1; } if (first_nibble) *p = ch << 4; else *p++ |= ch & 0xf; first_nibble = !first_nibble; } if (!first_nibble) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Non-paired nibble at the position %d", o_pos - src - 1); return -1; } i = c_pos - src + 1; } *p = 0; dest_len = (char *)p - *dest; return dest_len; } /* {{{ proto string hexdump(string data[, string delimiter]) Produce hexadecimal dump of the string */ PHP_FUNCTION(hexdump) { char *src, *dst, *delim; int src_len, dst_len, delim_len = 0; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &src, &src_len, &delim, &delim_len) == FAILURE || src_len < 1) { RETURN_FALSE; } dst_len = php_hexdump(src, src_len, delim, delim_len, &dst); RETURN_STRINGL(dst, dst_len, 0); } /* }}} */ /* {{{ proto string packhex(string data[, bool strict]) Pack hexadecimal dump into the string */ PHP_FUNCTION(packhex) { char *src, *dst; int src_len, dst_len; zend_bool strict = 1; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &src, &src_len, &strict) == FAILURE || src_len < 1) { RETURN_FALSE; } dst_len = php_packhex(src, src_len, strict, &dst); if (dst_len == -1) RETURN_FALSE; RETURN_STRINGL(dst, dst_len, 0); } /* }}} */ /* {{{ proto string smart_hexdump(string data) Produce hexadecimal smart dump of the string */ PHP_FUNCTION(smart_hexdump) { char *src, *dst; int src_len, dst_len; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &src, &src_len) == FAILURE || src_len < 1) { RETURN_FALSE; } dst_len = php_smart_hexdump(src, src_len, &dst); RETURN_STRINGL(dst, dst_len, 0); } /* }}} */ /* {{{ proto string smart_packhex(string data) Pack smart hexadecimal smart dump into the string */ PHP_FUNCTION(smart_packhex) { char *src, *dst; int src_len, dst_len; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &src, &src_len) == FAILURE || src_len < 1) { RETURN_FALSE; } dst_len = php_smart_packhex(src, src_len, &dst); if (dst_len == -1) RETURN_FALSE; RETURN_STRINGL(dst, dst_len, 0); } /* }}} */ Index: ext/standard/basic_functions.c =================================================================== RCS file: /repository/php-src/ext/standard/basic_functions.c,v retrieving revision 1.832 diff -u -r1.832 basic_functions.c --- ext/standard/basic_functions.c 12 Dec 2006 18:24:16 -0000 1.832 +++ ext/standard/basic_functions.c 14 Dec 2006 10:22:16 -0000 @@ -33,6 +33,7 @@ #include "zend_operators.h" #include "ext/standard/dns.h" #include "ext/standard/php_uuencode.h" +#include "ext/standard/php_hexdump.h" #ifdef PHP_WIN32 #include "win32/php_win32_globals.h" @@ -3066,6 +3067,29 @@ ZEND_ARG_INFO(0, data) ZEND_END_ARG_INFO() /* }}} */ +/* {{{ hexdump.c */ +static +ZEND_BEGIN_ARG_INFO_EX(arginfo_hexdump, 0, 0, 1) + ZEND_ARG_INFO(0, data) + ZEND_ARG_INFO(0, delimiter) +ZEND_END_ARG_INFO() + +static +ZEND_BEGIN_ARG_INFO_EX(arginfo_packhex, 0, 0, 1) + ZEND_ARG_INFO(0, data) + ZEND_ARG_INFO(0, strict) +ZEND_END_ARG_INFO() + +static +ZEND_BEGIN_ARG_INFO(arginfo_smart_hexdump, 0) + ZEND_ARG_INFO(0, data) +ZEND_END_ARG_INFO() + +static +ZEND_BEGIN_ARG_INFO(arginfo_smart_packhex, 0) + ZEND_ARG_INFO(0, data) +ZEND_END_ARG_INFO() +/* }}} */ /* {{{ var.c */ static ZEND_BEGIN_ARG_INFO_EX(arginfo_var_dump, 0, 0, 1) @@ -3317,6 +3341,11 @@ PHP_FE(convert_uuencode, arginfo_convert_uuencode) PHP_FE(convert_uudecode, arginfo_convert_uudecode) + PHP_FE(hexdump, arginfo_hexdump) + PHP_FE(packhex, arginfo_packhex) + PHP_FE(smart_hexdump, arginfo_hexdump) + PHP_FE(smart_packhex, arginfo_packhex) + PHP_FE(abs, arginfo_abs) PHP_FE(ceil, arginfo_ceil) PHP_FE(floor, arginfo_floor) Index: ext/standard/config.m4 =================================================================== RCS file: /repository/php-src/ext/standard/config.m4,v retrieving revision 1.84 diff -u -r1.84 config.m4 --- ext/standard/config.m4 24 Aug 2006 11:05:38 -0000 1.84 +++ ext/standard/config.m4 14 Dec 2006 10:22:17 -0000 @@ -508,7 +508,7 @@ url_scanner.c var.c versioning.c assert.c strnatcmp.c levenshtein.c \ incomplete_class.c url_scanner_ex.c ftp_fopen_wrapper.c \ http_fopen_wrapper.c php_fopen_wrapper.c credits.c css.c \ - var_unserializer.c ftok.c sha1.c user_filters.c uuencode.c \ + var_unserializer.c ftok.c sha1.c user_filters.c uuencode.c hexdump.c \ filters.c proc_open.c streamsfuncs.c http.c) PHP_ADD_MAKEFILE_FRAGMENT Index: ext/standard/config.w32 =================================================================== RCS file: /repository/php-src/ext/standard/config.w32,v retrieving revision 1.6 diff -u -r1.6 config.w32 --- ext/standard/config.w32 4 Jan 2006 12:57:04 -0000 1.6 +++ ext/standard/config.w32 14 Dec 2006 10:22:17 -0000 @@ -15,6 +15,6 @@ versioning.c assert.c strnatcmp.c levenshtein.c incomplete_class.c \ url_scanner_ex.c ftp_fopen_wrapper.c http_fopen_wrapper.c \ php_fopen_wrapper.c credits.c css.c var_unserializer.c ftok.c sha1.c \ - user_filters.c uuencode.c filters.c proc_open.c \ + user_filters.c uuencode.c hexdump.c filters.c proc_open.c \ streamsfuncs.c http.c", false /* never shared */); Index: win32/php5dllts.dsp =================================================================== RCS file: /repository/php-src/win32/php5dllts.dsp,v retrieving revision 1.9 diff -u -r1.9 php5dllts.dsp --- win32/php5dllts.dsp 10 Nov 2006 09:56:37 -0000 1.9 +++ win32/php5dllts.dsp 14 Dec 2006 10:22:20 -0000 @@ -1774,6 +1774,10 @@ # End Source File # Begin Source File +SOURCE=..\ext\standard\hexdump.c +# End Source File +# Begin Source File + SOURCE=..\ext\standard\var.c # End Source File # Begin Source File Preface ======= Hexadecimal manipulation functions. Prototype ========= string hexdump( string data[, string delimiter ] ) Description ----------- Produce the hexadecimal dump of the given string. The dump will be in upper case. If delimiter is given it will be inserted into the result string between each dumped byte. Examples -------- echo hexdump( "\x01\x02\x03\x04\x05" ) output: 0102030405 echo hexdump( "\x01\x02\x03\x04\x05", ", " ) output: 01, 02, 03, 04, 05 Prototype ========= string packhex( string data[, bool strict ] ) Default 'strict' value is 'true'. Description ----------- Pack the source string from hexadecimal dump. If 'strict' is true, only 0-9, a-f, A-F characters are allowed in the source string, otherwise the function will return 'false'. When 'strict' is 'false' any non-hexadecimal characters will be skipped. If the number of the hexadecimal digits is odd (unpaired nibble is present) regardless of 'strict' value, the function will return 'false' as well. The source string can be in ASCII or EBCDIC. Examples -------- $s = packhex( "0102030405" ) results: $s = "\x01\x02\x03\x04\x05" $s = packhex( "01, 02, 03, 04 and 05" ) results: $s = "\x01\x02\x03\x04\xAD\x05"; Smart hexadecimal dump format (smart hexdump) ============================================= Only non-printable characters are dumped in this format. Default non-printable character set is from '\x00' to '\x1F'. When the characters are dumped it is quoted into '<' and '>'. Other printable characters are represented as they are. Characters '<' ('\x3C') and '>' ('\x3E) are always dumped. Consecutive dumped characters can be grouped when they are quoted in the '<' and '>'. The function 'smart_hexdump' always produces the most grouped dump. In general, smart hexdump is very useful when you have to watch a lot of data, which can contain printable and non-printable characters. Of course, you can use simple hexdump, but in smart hexdump you are able to see, for example, text messages, and on the other hand you control any non-printable data of the stream. Examples ======== original : "\x01\x02\x03\x04TEST\x00\xFF\x00" smart hexdump: "<01020304>TEST<00FF00>" for example, this smart hexdump can be like "<01><02><03><04>TEST<00><FF><00>" original : "TEST STRING\x00" smart hexdump: "TEST STRING<00>" original : "TEST <STRING>\x00" smart hexdump: "TEST <3C>STRING<3E><00>" Prototype ========= string smart_hexdump( string data ) Description ----------- Produce the smart hexadecimal dump of the given string. The dump will be in upper case. Examples -------- echo smart_hexdump( "\x01\x02\x03\x04\x05" ) output: <0102030405> echo smart_hexdump( "\x01<\x02>TEST\x03\x04\x05" ) output: <013C023E>TEST<030405> Prototype ========= string smart_packhex( string data ) Description ----------- Pack the source string from the smart hexadecimal dump. Only 0-9, a-f, A-F, '<' and '>' characters are allowed in the source string, otherwise the function will return 'false'. If the number of the hexadecimal digits is odd (unpaired nibble is present), the function will return 'false' as well. The source string can be in ASCII or EBCDIC. Examples -------- $s = smart_packhex( "<0102030405>" ) results: $s = "\x01\x02\x03\x04\x05" $s = packhex( "<013C023E>TEST<030405>" ) results: $s = "\x01<\x02>TEST\x03\x04\x05";
/* +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2006 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | | http://www.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Author: Alexander Demin <demin@ots.ru> | +----------------------------------------------------------------------+ */ #ifndef PHP_HEXDUMP_H #define PHP_HEXDUMP_H PHP_FUNCTION(hexdump); PHP_FUNCTION(packhex); PHP_FUNCTION(smart_hexdump); PHP_FUNCTION(smart_packhex); PHPAPI int php_hexdump(char *src, int src_len, char* delim, int delim_len, char **dest); PHPAPI int php_packhex(char *src, int src_len, zend_bool strict, char **dest); PHPAPI int php_smart_hexdump(char *src, int src_len, char **dest); PHPAPI int php_smart_packhex(char *src, int src_len, char **dest); #endif /* PHP_HEXDUMP_H */ /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: */ /* +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2006 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | | http://www.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Author: Alexander Demin <demin@ots.ru> | +----------------------------------------------------------------------+ */ #include "php.h" #include "php_hexdump.h" static const char php_hexdump_digits[] = "0123456789ABCDEF"; static const unsigned char php_hex_index[ 256 ] = { /* 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F */ /*00*/ 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, /*10*/ 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, /*20*/ 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, /*30*/ 0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,255,255,255,255,255,255, /* ASCII */ /*40*/ 255,0xa,0xb,0xc,0xd,0xe,0xf,255,255,255,255,255,255,255,255,255, /* ASCII */ /*50*/ 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, /*60*/ 255,0xa,0xb,0xc,0xd,0xe,0xf,255,255,255,255,255,255,255,255,255, /* ASCII */ /*70*/ 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, /*80*/ 255,0xa,0xb,0xc,0xd,0xe,0xf,255,255,255,255,255,255,255,255,255, /* EBCDIC */ /*90*/ 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, /*A0*/ 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, /*B0*/ 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, /*C0*/ 255,0xa,0xb,0xc,0xd,0xe,0xf,255,255,255,255,255,255,255,255,255, /* EBCDIC */ /*D0*/ 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, /*E0*/ 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, /*F0*/ 0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,255,255,255,255,255,255 /* EBCDIC */ }; static const char php_packhex_default_map[ 256 ] = { /* 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F */ /*00*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*10*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*20*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*30*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*40*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*50*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*60*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*70*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*80*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*90*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*A0*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*B0*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*C0*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*D0*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*E0*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*F0*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; PHPAPI int php_hexdump(char *src, int src_len, char *delim, int delim_len, char **dest) { char *p; int out_sz = src_len * 2; if (delim_len) out_sz += delim_len * src_len - 1; p = *dest = emalloc(out_sz + 1); while (src_len--) { *p++ = php_hexdump_digits[ (unsigned char)*src >> 4 ]; *p++ = php_hexdump_digits[ (unsigned char)*src++ & 0x0F ]; if (delim_len && src_len) { memcpy( p, delim, delim_len ); p += delim_len; } } *p = 0; return out_sz; } PHPAPI int php_packhex(char *src, int src_len, zend_bool strict, char **dest) { int dest_len = 0; int hex_count = 0; int first_nibble; unsigned char *p; int i; i = src_len; p = (unsigned char *)src; while (i--) { if (php_hex_index[ *p++ ] != 255) ++hex_count; else { if (strict) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Non-hexadecimal character at the position %d", i+1); return -1; } } } if (hex_count & 1) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Non-paired nibble at the end of the string"); --hex_count; } if (!hex_count) { *dest = NULL; return 0; } dest_len = hex_count / 2; p = *dest = emalloc(dest_len); first_nibble = 1; while (src_len--) { unsigned char ch = php_hex_index[ (unsigned char)*src++ ]; if (ch == 255) continue; if (first_nibble) *p = ch << 4; else *p++ |= ch & 0xf; first_nibble = !first_nibble; } return dest_len; } PHPAPI int php_smart_hexdump(char *src, int src_len, char **dest) { char *p; int out_sz = src_len * 4; char* map = (char *)php_packhex_default_map; int i; p = *dest = emalloc(out_sz + 1); *p = 0; for(i = 0; i < src_len; i++) { if (map[ (unsigned char)src[i] ] && src[i] != '<' && src[i] != '>') *p++ = src[i]; else { unsigned char ch; *p++ = '<'; for(; i < src_len && !map[ (unsigned char)src[i] ]; i++) { *p++ = php_hexdump_digits[ (unsigned char)src[i] >> 4 ]; *p++ = php_hexdump_digits[ (unsigned char)src[i] & 0x0F ]; } *p++ = '>'; if (i < src_len) *p++ = (unsigned char)src[i]; } } *p = 0; return p - *dest; } PHPAPI int php_smart_packhex(char *src, int src_len, char **dest) { int dest_len = src_len; int first_nibble; unsigned char *p; int i; p = *dest = emalloc(dest_len); for (i = 0; i < src_len; ) { char *o_pos = (char *)memchr( src + i, '<', src_len - i ); char *c_pos = (char *)memchr( src + i, '>', src_len - i ); char *v; if (!o_pos || !c_pos || o_pos > c_pos) { memcpy(p, src + i, src_len - i); p += src_len - i; break; } memcpy( p, src + i, o_pos - src - i ); p += o_pos - src - i; first_nibble = 1; for (o_pos++; o_pos < c_pos; o_pos++ ) { unsigned char ch = php_hex_index[ (unsigned char)*o_pos ]; if (ch == 255) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Non-hexadecimal character at the position %d", o_pos - src); return -1; } if (first_nibble) *p = ch << 4; else *p++ |= ch & 0xf; first_nibble = !first_nibble; } if (!first_nibble) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Non-paired nibble at the position %d", o_pos - src - 1); return -1; } i = c_pos - src + 1; } *p = 0; dest_len = (char *)p - *dest; return dest_len; } /* {{{ proto string hexdump(string data[, string delimiter]) Produce hexadecimal dump of the string */ PHP_FUNCTION(hexdump) { char *src, *dst, *delim; int src_len, dst_len, delim_len = 0; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &src, &src_len, &delim, &delim_len) == FAILURE || src_len < 1) { RETURN_FALSE; } dst_len = php_hexdump(src, src_len, delim, delim_len, &dst); RETURN_STRINGL(dst, dst_len, 0); } /* }}} */ /* {{{ proto string packhex(string data[, bool strict]) Pack hexadecimal dump into the string */ PHP_FUNCTION(packhex) { char *src, *dst; int src_len, dst_len; zend_bool strict = 1; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &src, &src_len, &strict) == FAILURE || src_len < 1) { RETURN_FALSE; } dst_len = php_packhex(src, src_len, strict, &dst); if (dst_len == -1) RETURN_FALSE; RETURN_STRINGL(dst, dst_len, 0); } /* }}} */ /* {{{ proto string smart_hexdump(string data) Produce hexadecimal smart dump of the string */ PHP_FUNCTION(smart_hexdump) { char *src, *dst; int src_len, dst_len; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &src, &src_len) == FAILURE || src_len < 1) { RETURN_FALSE; } dst_len = php_smart_hexdump(src, src_len, &dst); RETURN_STRINGL(dst, dst_len, 0); } /* }}} */ /* {{{ proto string smart_packhex(string data) Pack smart hexadecimal smart dump into the string */ PHP_FUNCTION(smart_packhex) { char *src, *dst; int src_len, dst_len; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &src, &src_len) == FAILURE || src_len < 1) { RETURN_FALSE; } dst_len = php_smart_packhex(src, src_len, &dst); if (dst_len == -1) RETURN_FALSE; RETURN_STRINGL(dst, dst_len, 0); } /* }}} */ Index: ext/standard/basic_functions.c =================================================================== RCS file: /repository/php-src/ext/standard/basic_functions.c,v retrieving revision 1.832 diff -u -r1.832 basic_functions.c --- ext/standard/basic_functions.c 12 Dec 2006 18:24:16 -0000 1.832 +++ ext/standard/basic_functions.c 14 Dec 2006 10:22:16 -0000 @@ -33,6 +33,7 @@ #include "zend_operators.h" #include "ext/standard/dns.h" #include "ext/standard/php_uuencode.h" +#include "ext/standard/php_hexdump.h" #ifdef PHP_WIN32 #include "win32/php_win32_globals.h" @@ -3066,6 +3067,29 @@ ZEND_ARG_INFO(0, data) ZEND_END_ARG_INFO() /* }}} */ +/* {{{ hexdump.c */ +static +ZEND_BEGIN_ARG_INFO_EX(arginfo_hexdump, 0, 0, 1) + ZEND_ARG_INFO(0, data) + ZEND_ARG_INFO(0, delimiter) +ZEND_END_ARG_INFO() + +static +ZEND_BEGIN_ARG_INFO_EX(arginfo_packhex, 0, 0, 1) + ZEND_ARG_INFO(0, data) + ZEND_ARG_INFO(0, strict) +ZEND_END_ARG_INFO() + +static +ZEND_BEGIN_ARG_INFO(arginfo_smart_hexdump, 0) + ZEND_ARG_INFO(0, data) +ZEND_END_ARG_INFO() + +static +ZEND_BEGIN_ARG_INFO(arginfo_smart_packhex, 0) + ZEND_ARG_INFO(0, data) +ZEND_END_ARG_INFO() +/* }}} */ /* {{{ var.c */ static ZEND_BEGIN_ARG_INFO_EX(arginfo_var_dump, 0, 0, 1) @@ -3317,6 +3341,11 @@ PHP_FE(convert_uuencode, arginfo_convert_uuencode) PHP_FE(convert_uudecode, arginfo_convert_uudecode) + PHP_FE(hexdump, arginfo_hexdump) + PHP_FE(packhex, arginfo_packhex) + PHP_FE(smart_hexdump, arginfo_hexdump) + PHP_FE(smart_packhex, arginfo_packhex) + PHP_FE(abs, arginfo_abs) PHP_FE(ceil, arginfo_ceil) PHP_FE(floor, arginfo_floor) Index: ext/standard/config.m4 =================================================================== RCS file: /repository/php-src/ext/standard/config.m4,v retrieving revision 1.84 diff -u -r1.84 config.m4 --- ext/standard/config.m4 24 Aug 2006 11:05:38 -0000 1.84 +++ ext/standard/config.m4 14 Dec 2006 10:22:17 -0000 @@ -508,7 +508,7 @@ url_scanner.c var.c versioning.c assert.c strnatcmp.c levenshtein.c \ incomplete_class.c url_scanner_ex.c ftp_fopen_wrapper.c \ http_fopen_wrapper.c php_fopen_wrapper.c credits.c css.c \ - var_unserializer.c ftok.c sha1.c user_filters.c uuencode.c \ + var_unserializer.c ftok.c sha1.c user_filters.c uuencode.c hexdump.c \ filters.c proc_open.c streamsfuncs.c http.c) PHP_ADD_MAKEFILE_FRAGMENT Index: ext/standard/config.w32 =================================================================== RCS file: /repository/php-src/ext/standard/config.w32,v retrieving revision 1.6 diff -u -r1.6 config.w32 --- ext/standard/config.w32 4 Jan 2006 12:57:04 -0000 1.6 +++ ext/standard/config.w32 14 Dec 2006 10:22:17 -0000 @@ -15,6 +15,6 @@ versioning.c assert.c strnatcmp.c levenshtein.c incomplete_class.c \ url_scanner_ex.c ftp_fopen_wrapper.c http_fopen_wrapper.c \ php_fopen_wrapper.c credits.c css.c var_unserializer.c ftok.c sha1.c \ - user_filters.c uuencode.c filters.c proc_open.c \ + user_filters.c uuencode.c hexdump.c filters.c proc_open.c \ streamsfuncs.c http.c", false /* never shared */); Index: win32/php5dllts.dsp =================================================================== RCS file: /repository/php-src/win32/php5dllts.dsp,v retrieving revision 1.9 diff -u -r1.9 php5dllts.dsp --- win32/php5dllts.dsp 10 Nov 2006 09:56:37 -0000 1.9 +++ win32/php5dllts.dsp 14 Dec 2006 10:22:20 -0000 @@ -1774,6 +1774,10 @@ # End Source File # Begin Source File +SOURCE=..\ext\standard\hexdump.c +# End Source File +# Begin Source File + SOURCE=..\ext\standard\var.c # End Source File # Begin Source File Preface ======= Hexadecimal manipulation functions. Prototype ========= string hexdump( string data[, string delimiter ] ) Description ----------- Produce the hexadecimal dump of the given string. The dump will be in upper case. If delimiter is given it will be inserted into the result string between each dumped byte. Examples -------- echo hexdump( "\x01\x02\x03\x04\x05" ) output: 0102030405 echo hexdump( "\x01\x02\x03\x04\x05", ", " ) output: 01, 02, 03, 04, 05 Prototype ========= string packhex( string data[, bool strict ] ) Default 'strict' value is 'true'. Description ----------- Pack the source string from hexadecimal dump. If 'strict' is true, only 0-9, a-f, A-F characters are allowed in the source string, otherwise the function will return 'false'. When 'strict' is 'false' any non-hexadecimal characters will be skipped. If the number of the hexadecimal digits is odd (unpaired nibble is present) regardless of 'strict' value, the function will return 'false' as well. The source string can be in ASCII or EBCDIC. Examples -------- $s = packhex( "0102030405" ) results: $s = "\x01\x02\x03\x04\x05" $s = packhex( "01, 02, 03, 04 and 05" ) results: $s = "\x01\x02\x03\x04\xAD\x05"; Smart hexadecimal dump format (smart hexdump) ============================================= Only non-printable characters are dumped in this format. Default non-printable character set is from '\x00' to '\x1F'. When the characters are dumped it is quoted into '<' and '>'. Other printable characters are represented as they are. Characters '<' ('\x3C') and '>' ('\x3E) are always dumped. Consecutive dumped characters can be grouped when they are quoted in the '<' and '>'. The function 'smart_hexdump' always produces the most grouped dump. In general, smart hexdump is very useful when you have to watch a lot of data, which can contain printable and non-printable characters. Of course, you can use simple hexdump, but in smart hexdump you are able to see, for example, text messages, and on the other hand you control any non-printable data of the stream. Examples ======== original : "\x01\x02\x03\x04TEST\x00\xFF\x00" smart hexdump: "<01020304>TEST<00FF00>" for example, this smart hexdump can be like "<01><02><03><04>TEST<00><FF><00>" original : "TEST STRING\x00" smart hexdump: "TEST STRING<00>" original : "TEST <STRING>\x00" smart hexdump: "TEST <3C>STRING<3E><00>" Prototype ========= string smart_hexdump( string data ) Description ----------- Produce the smart hexadecimal dump of the given string. The dump will be in upper case. Examples -------- echo smart_hexdump( "\x01\x02\x03\x04\x05" ) output: <0102030405> echo smart_hexdump( "\x01<\x02>TEST\x03\x04\x05" ) output: <013C023E>TEST<030405> Prototype ========= string smart_packhex( string data ) Description ----------- Pack the source string from the smart hexadecimal dump. Only 0-9, a-f, A-F, '<' and '>' characters are allowed in the source string, otherwise the function will return 'false'. If the number of the hexadecimal digits is odd (unpaired nibble is present), the function will return 'false' as well. The source string can be in ASCII or EBCDIC. Examples -------- $s = smart_packhex( "<0102030405>" ) results: $s = "\x01\x02\x03\x04\x05" $s = packhex( "<013C023E>TEST<030405>" ) results: $s = "\x01<\x02>TEST\x03\x04\x05";