📄 pack.c
字号:
/* +----------------------------------------------------------------------+ | PHP Version 4 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2007 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: Chris Schneider <cschneid@relog.ch> | +----------------------------------------------------------------------+ *//* $Id: pack.c,v 1.40.2.7.2.6 2007/01/01 09:46:48 sebastian Exp $ */#include "php.h"#include <stdio.h>#include <stdlib.h>#include <errno.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#ifdef PHP_WIN32#include <windows.h>#include <winsock.h>#define O_RDONLY _O_RDONLY#include "win32/param.h"#elif defined(NETWARE)#ifdef USE_WINSOCK#include <novsock2.h>#else#include <sys/socket.h>#endif#include <sys/param.h>#else#include <sys/param.h>#endif#include "ext/standard/head.h"#include "safe_mode.h"#include "php_string.h"#include "pack.h"#if HAVE_PWD_H#ifdef PHP_WIN32#include "win32/pwd.h"#else#include <pwd.h>#endif#endif#include "fsock.h"#if HAVE_NETINET_IN_H#include <netinet/in.h>#endif#define INC_OUTPUTPOS(a,b) \ if ((a) < 0 || ((INT_MAX - outputpos)/(b)) < (a)) { \ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Type %c: integer overflow in format string", code); \ RETURN_FALSE; \ } \ outputpos += (a)*(b);/* Whether machine is little endian */char machine_little_endian;/* Mapping of byte from char (8bit) to long for machine endian */static int byte_map[1];/* Mappings of bytes from int (machine dependant) to int for machine endian */static int int_map[sizeof(int)];/* Mappings of bytes from shorts (16bit) for all endian environments */static int machine_endian_short_map[2];static int big_endian_short_map[2];static int little_endian_short_map[2];/* Mappings of bytes from longs (32bit) for all endian environments */static int machine_endian_long_map[4];static int big_endian_long_map[4];static int little_endian_long_map[4];/* {{{ php_pack */static void php_pack(zval **val, int size, int *map, char *output){ int i; char *v; convert_to_long_ex(val); v = (char *) &Z_LVAL_PP(val); for (i = 0; i < size; i++) { *output++ = v[map[i]]; }}/* }}} *//* pack() idea stolen from Perl (implemented formats behave the same as there) * Implemented formats are A, a, h, H, c, C, s, S, i, I, l, L, n, N, f, d, x, X, @. *//* {{{ proto string pack(string format, mixed arg1 [, mixed arg2 [, mixed ...]]) Takes one or more arguments and packs them into a binary string according to the format argument */PHP_FUNCTION(pack){ zval ***argv; int argc, i; int currentarg; char *format; int formatlen; char *formatcodes; int *formatargs; int formatcount = 0; int outputpos = 0, outputsize = 0; char *output; argc = ZEND_NUM_ARGS(); if (argc < 1) { WRONG_PARAM_COUNT; } argv = safe_emalloc(sizeof(zval **), argc, 0); if (zend_get_parameters_array_ex(argc, argv) == FAILURE) { efree(argv); WRONG_PARAM_COUNT; } convert_to_string_ex(argv[0]); format = Z_STRVAL_PP(argv[0]); formatlen = Z_STRLEN_PP(argv[0]); /* We have a maximum of <formatlen> format codes to deal with */ formatcodes = safe_emalloc(formatlen, sizeof(*formatcodes), 0); formatargs = safe_emalloc(formatlen, sizeof(*formatargs), 0); currentarg = 1; /* Preprocess format into formatcodes and formatargs */ for (i = 0; i < formatlen; formatcount++) { char code = format[i++]; int arg = 1; /* Handle format arguments if any */ if (i < formatlen) { char c = format[i]; if (c == '*') { arg = -1; i++; } else if (c >= '0' && c <= '9') { arg = atoi(&format[i]); while (format[i] >= '0' && format[i] <= '9' && i < formatlen) { i++; } } } /* Handle special arg '*' for all codes and check argv overflows */ switch ((int) code) { /* Never uses any args */ case 'x': case 'X': case '@': if (arg < 0) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Type %c: '*' ignored", code); arg = 1; } break; /* Always uses one arg */ case 'a': case 'A': case 'h': case 'H': if (currentarg >= argc) { efree(argv); efree(formatcodes); efree(formatargs); php_error_docref(NULL TSRMLS_CC, E_WARNING, "Type %c: not enough arguments", code); RETURN_FALSE; } if (arg < 0) { arg = Z_STRLEN_PP(argv[currentarg]); } currentarg++; break; /* Use as many args as specified */ case 'c': case 'C': case 's': case 'S': case 'i': case 'I': case 'l': case 'L': case 'n': case 'N': case 'v': case 'V': case 'f': case 'd': if (arg < 0) { arg = argc - currentarg; } currentarg += arg; if (currentarg > argc) { efree(argv); efree(formatcodes); efree(formatargs); php_error_docref(NULL TSRMLS_CC, E_WARNING, "Type %c: too few arguments", code); RETURN_FALSE; } break; default: efree(argv); efree(formatcodes); efree(formatargs); php_error_docref(NULL TSRMLS_CC, E_WARNING, "Type %c: unknown format code", code); RETURN_FALSE; } formatcodes[formatcount] = code; formatargs[formatcount] = arg; } if (currentarg < argc) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "%d arguments unused", (argc - currentarg)); } /* Calculate output length and upper bound while processing*/ for (i = 0; i < formatcount; i++) { int code = (int) formatcodes[i]; int arg = formatargs[i]; switch ((int) code) { case 'h': case 'H': INC_OUTPUTPOS((arg + (arg % 2)) / 2,1) /* 4 bit per arg */ break; case 'a': case 'A': case 'c': case 'C': case 'x': INC_OUTPUTPOS(arg,1) /* 8 bit per arg */ break; case 's': case 'S': case 'n': case 'v': INC_OUTPUTPOS(arg,2) /* 16 bit per arg */ break; case 'i': case 'I': INC_OUTPUTPOS(arg,sizeof(int)) break; case 'l': case 'L': case 'N': case 'V': INC_OUTPUTPOS(arg,4) /* 32 bit per arg */ break; case 'f': INC_OUTPUTPOS(arg,sizeof(float)) break; case 'd': INC_OUTPUTPOS(arg,sizeof(double)) break; case 'X': outputpos -= arg; if (outputpos < 0) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Type %c: outside of string", code); outputpos = 0; } break; case '@': outputpos = arg; break; } if (outputsize < outputpos) { outputsize = outputpos; } } output = emalloc(outputsize + 1); outputpos = 0; currentarg = 1; /* Do actual packing */ for (i = 0; i < formatcount; i++) { int code = (int) formatcodes[i]; int arg = formatargs[i]; zval **val; switch ((int) code) { case 'a': case 'A': memset(&output[outputpos], (code == 'a') ? '\0' : ' ', arg); val = argv[currentarg++]; convert_to_string_ex(val); memcpy(&output[outputpos], Z_STRVAL_PP(val), (Z_STRLEN_PP(val) < arg) ? Z_STRLEN_PP(val) : arg); outputpos += arg; break; case 'h': case 'H': { int nibbleshift = (code == 'h') ? 0 : 4; int first = 1; char *v; val = argv[currentarg++]; convert_to_string_ex(val); v = Z_STRVAL_PP(val); outputpos--; if(arg > Z_STRLEN_PP(val)) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Type %c: not enough characters in string", code); arg = Z_STRLEN_PP(val); } while (arg-- > 0) { char n = *v++; if (n >= '0' && n <= '9') { n -= '0'; } else if (n >= 'A' && n <= 'F') { n -= ('A' - 10); } else if (n >= 'a' && n <= 'f') { n -= ('a' - 10); } else { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Type %c: illegal hex digit %c", code, n); n = 0; } if (first--) { output[++outputpos] = 0; } else { first = 1; } output[outputpos] |= (n << nibbleshift); nibbleshift = (nibbleshift + 4) & 7; } outputpos++; break; } case 'c': case 'C': while (arg-- > 0) { php_pack(argv[currentarg++], 1, byte_map, &output[outputpos]); outputpos++; } break; case 's': case 'S': case 'n': case 'v': { int *map = machine_endian_short_map; if (code == 'n') { map = big_endian_short_map; } else if (code == 'v') { map = little_endian_short_map; } while (arg-- > 0) { php_pack(argv[currentarg++], 2, map, &output[outputpos]); outputpos += 2; } break; } case 'i': case 'I': while (arg-- > 0) { php_pack(argv[currentarg++], sizeof(int), int_map, &output[outputpos]); outputpos += sizeof(int); } break; case 'l': case 'L': case 'N': case 'V': { int *map = machine_endian_long_map; if (code == 'N') { map = big_endian_long_map; } else if (code == 'V') { map = little_endian_long_map; } while (arg-- > 0) { php_pack(argv[currentarg++], 4, map, &output[outputpos]); outputpos += 4; } break; } case 'f': { float v; while (arg-- > 0) { val = argv[currentarg++]; convert_to_double_ex(val); v = (float) Z_DVAL_PP(val); memcpy(&output[outputpos], &v, sizeof(v)); outputpos += sizeof(v); } break; } case 'd': { double v; while (arg-- > 0) { val = argv[currentarg++]; convert_to_double_ex(val); v = (double) Z_DVAL_PP(val); memcpy(&output[outputpos], &v, sizeof(v)); outputpos += sizeof(v); } break; } case 'x': memset(&output[outputpos], '\0', arg); outputpos += arg; break; case 'X': outputpos -= arg; if (outputpos < 0) { outputpos = 0; } break; case '@': if (arg > outputpos) { memset(&output[outputpos], '\0', arg - outputpos); } outputpos = arg; break; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -