summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2014-01-05 12:05:58 -0200
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2014-01-05 12:05:58 -0200
commit29256e8960d7f4bae728bb07a86eb0d604f5d98d (patch)
treed41f0f0f136c25505ee93a90673730ade1c87127
parent438c534ff4c8ccad117354826d4ac133b84f2fdc (diff)
downloadlua-29256e8960d7f4bae728bb07a86eb0d604f5d98d.tar.gz
lua-29256e8960d7f4bae728bb07a86eb0d604f5d98d.tar.bz2
lua-29256e8960d7f4bae728bb07a86eb0d604f5d98d.zip
first implementation of string.packint/string.unpackint
-rw-r--r--lstrlib.c125
1 files changed, 124 insertions, 1 deletions
diff --git a/lstrlib.c b/lstrlib.c
index 8ca34691..8fd1a433 100644
--- a/lstrlib.c
+++ b/lstrlib.c
@@ -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
951static union {
952 int dummy;
953 char little; /* true iff machine is little endian */
954} const nativeendian = {1};
955
956
957static 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
966static 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
974static 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
996static 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
1015static 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
1043static 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
941static const luaL_Reg strlib[] = { 1062static 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