diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2014-01-05 12:05:58 -0200 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2014-01-05 12:05:58 -0200 |
commit | 29256e8960d7f4bae728bb07a86eb0d604f5d98d (patch) | |
tree | d41f0f0f136c25505ee93a90673730ade1c87127 | |
parent | 438c534ff4c8ccad117354826d4ac133b84f2fdc (diff) | |
download | lua-29256e8960d7f4bae728bb07a86eb0d604f5d98d.tar.gz lua-29256e8960d7f4bae728bb07a86eb0d604f5d98d.tar.bz2 lua-29256e8960d7f4bae728bb07a86eb0d604f5d98d.zip |
first implementation of string.packint/string.unpackint
-rw-r--r-- | lstrlib.c | 125 |
1 files changed, 124 insertions, 1 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lstrlib.c,v 1.181 2013/06/19 14:29:01 roberto Exp roberto $ | 2 | ** $Id: lstrlib.c,v 1.182 2013/06/20 15:06:51 roberto Exp roberto $ |
3 | ** Standard library for string operations and pattern-matching | 3 | ** Standard library for string operations and pattern-matching |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -938,6 +938,127 @@ static int str_format (lua_State *L) { | |||
938 | /* }====================================================== */ | 938 | /* }====================================================== */ |
939 | 939 | ||
940 | 940 | ||
941 | /* | ||
942 | ** {====================================================== | ||
943 | ** PACK/UNPACK | ||
944 | ** ======================================================= | ||
945 | */ | ||
946 | |||
947 | /* maximum size for the binary representation of an integer */ | ||
948 | #define MAXINTSIZE 8 | ||
949 | |||
950 | |||
951 | static union { | ||
952 | int dummy; | ||
953 | char little; /* true iff machine is little endian */ | ||
954 | } const nativeendian = {1}; | ||
955 | |||
956 | |||
957 | static int getendian (lua_State *L, int arg) { | ||
958 | const char *endian = luaL_optstring(L, arg, | ||
959 | (nativeendian.little ? "l" : "b")); | ||
960 | luaL_argcheck(L, *endian == 'l' || *endian == 'b', arg, | ||
961 | "endianess must be 'l' or 'b'"); | ||
962 | return (*endian == 'l'); | ||
963 | } | ||
964 | |||
965 | |||
966 | static int getintsize (lua_State *L, int arg) { | ||
967 | int size = luaL_optint(L, arg, sizeof(lua_Integer)); | ||
968 | luaL_argcheck(L, 1 <= size && size <= MAXINTSIZE, arg, | ||
969 | "integer size out of valid range"); | ||
970 | return size; | ||
971 | } | ||
972 | |||
973 | |||
974 | static int packint (char *buff, lua_Integer n, int littleendian, int size) { | ||
975 | int i; | ||
976 | if (littleendian) { | ||
977 | for (i = 0; i < size - 1; i++) { | ||
978 | buff[i] = (n & 0xff); | ||
979 | n >>= 8; | ||
980 | } | ||
981 | } | ||
982 | else { | ||
983 | for (i = size - 1; i > 0; i--) { | ||
984 | buff[i] = (n & 0xff); | ||
985 | n >>= 8; | ||
986 | } | ||
987 | } | ||
988 | buff[i] = (n & 0xff); /* last byte */ | ||
989 | /* test for overflow: OK if there are only zeros left in higher bytes, | ||
990 | or if there are only oneÅ› left and packed number is negative (signal | ||
991 | bit, the higher bit in last byte, is one) */ | ||
992 | return ((n & ~(lua_Integer)0xff) == 0 || (n | 0x7f) == ~(lua_Integer)0); | ||
993 | } | ||
994 | |||
995 | |||
996 | static int packint_l (lua_State *L) { | ||
997 | char buff[MAXINTSIZE]; | ||
998 | lua_Integer n = luaL_checkinteger(L, 1); | ||
999 | int size = getintsize(L, 2); | ||
1000 | int endian = getendian(L, 3); | ||
1001 | if (packint(buff, n, endian, size)) | ||
1002 | lua_pushlstring(L, buff, size); | ||
1003 | else | ||
1004 | luaL_error(L, "integer does not fit into given size (%d)", size); | ||
1005 | return 1; | ||
1006 | } | ||
1007 | |||
1008 | |||
1009 | /* mask to check higher-order byte in a Lua integer */ | ||
1010 | #define HIGHERBYTE (~((lua_Unsigned)~0 >> 8)) | ||
1011 | |||
1012 | /* mask to check higher-order byte + signal bit of next byte */ | ||
1013 | #define HIGHERBYTE1 (~((lua_Unsigned)~0 >> 9)) | ||
1014 | |||
1015 | static int unpackint (const char *buff, lua_Integer *res, | ||
1016 | int littleendian, int size) { | ||
1017 | lua_Integer n = 0; | ||
1018 | int i; | ||
1019 | for (i = 0; i < size; i++) { | ||
1020 | if (i >= (int)sizeof(lua_Integer)) { /* will throw away a byte? */ | ||
1021 | /* check for overflow: it is OK to throw away leading zeros for a | ||
1022 | positive number; leading ones for a negative number; and one | ||
1023 | last leading zero to allow unsigned integers with a 1 in | ||
1024 | its "signal bit" */ | ||
1025 | if (!((n & HIGHERBYTE1) == 0 || /* zeros for pos. number */ | ||
1026 | (n & HIGHERBYTE1) == HIGHERBYTE1 || /* ones for neg. number */ | ||
1027 | ((n & HIGHERBYTE) == 0 && i == size - 1))) /* last zero */ | ||
1028 | return 0; /* overflow */ | ||
1029 | } | ||
1030 | n <<= 8; | ||
1031 | n |= (lua_Integer)(unsigned char)buff[littleendian ? size - 1 - i : i]; | ||
1032 | } | ||
1033 | if (size < (int)sizeof(lua_Integer)) { /* need sign extension? */ | ||
1034 | lua_Integer mask = (~(lua_Integer)0) << (size*8 - 1); | ||
1035 | if (n & mask) /* negative value? */ | ||
1036 | n |= mask; /* signal extension */ | ||
1037 | } | ||
1038 | *res = n; | ||
1039 | return 1; | ||
1040 | } | ||
1041 | |||
1042 | |||
1043 | static int unpackint_l (lua_State *L) { | ||
1044 | lua_Integer res; | ||
1045 | size_t len; | ||
1046 | const char *s = luaL_checklstring(L, 1, &len); | ||
1047 | lua_Integer pos = posrelat(luaL_optinteger(L, 2, 1), len); | ||
1048 | int size = getintsize(L, 3); | ||
1049 | int endian = getendian(L, 4); | ||
1050 | luaL_argcheck(L, 1 <= pos && (size_t)pos + size - 1 <= len, 1, | ||
1051 | "string too short"); | ||
1052 | if(unpackint(s + pos - 1, &res, endian, size)) | ||
1053 | lua_pushinteger(L, res); | ||
1054 | else | ||
1055 | luaL_error(L, "result does not fit into a Lua integer"); | ||
1056 | return 1; | ||
1057 | } | ||
1058 | |||
1059 | /* }====================================================== */ | ||
1060 | |||
1061 | |||
941 | static const luaL_Reg strlib[] = { | 1062 | static const luaL_Reg strlib[] = { |
942 | {"byte", str_byte}, | 1063 | {"byte", str_byte}, |
943 | {"char", str_char}, | 1064 | {"char", str_char}, |
@@ -953,6 +1074,8 @@ static const luaL_Reg strlib[] = { | |||
953 | {"reverse", str_reverse}, | 1074 | {"reverse", str_reverse}, |
954 | {"sub", str_sub}, | 1075 | {"sub", str_sub}, |
955 | {"upper", str_upper}, | 1076 | {"upper", str_upper}, |
1077 | {"packint", packint_l}, | ||
1078 | {"unpackint", unpackint_l}, | ||
956 | {NULL, NULL} | 1079 | {NULL, NULL} |
957 | }; | 1080 | }; |
958 | 1081 | ||