aboutsummaryrefslogtreecommitdiff
path: root/lstrlib.c
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2014-11-05 16:50:29 -0200
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2014-11-05 16:50:29 -0200
commitad73e5156e488f48d291cb2ca0ea3dc0c8d3bdd8 (patch)
tree13665a116f59858cebf4defd606ccbb2e9c4f397 /lstrlib.c
parent720c68dabb6f3c960c68fdaa2caea8fe78d92524 (diff)
downloadlua-ad73e5156e488f48d291cb2ca0ea3dc0c8d3bdd8.tar.gz
lua-ad73e5156e488f48d291cb2ca0ea3dc0c8d3bdd8.tar.bz2
lua-ad73e5156e488f48d291cb2ca0ea3dc0c8d3bdd8.zip
more direct way to fill sign-extension extra bytes when packing
integers with sizes larger than lua_Integer + added comments
Diffstat (limited to 'lstrlib.c')
-rw-r--r--lstrlib.c42
1 files changed, 29 insertions, 13 deletions
diff --git a/lstrlib.c b/lstrlib.c
index f67ae592..a5b0b15f 100644
--- a/lstrlib.c
+++ b/lstrlib.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lstrlib.c,v 1.212 2014/11/02 19:19:04 roberto Exp roberto $ 2** $Id: lstrlib.c,v 1.213 2014/11/04 14:34:43 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*/
@@ -966,9 +966,6 @@ static int str_format (lua_State *L) {
966/* size of a lua_Integer */ 966/* size of a lua_Integer */
967#define SZINT ((int)sizeof(lua_Integer)) 967#define SZINT ((int)sizeof(lua_Integer))
968 968
969/* mask for all ones in last byte in a lua Integer */
970#define HIGHERBYTE ((lua_Unsigned)MC << (NB * (SZINT - 1)))
971
972 969
973/* dummy union to get native endianness */ 970/* dummy union to get native endianness */
974static const union { 971static const union {
@@ -1049,7 +1046,8 @@ static int getnum (const char **fmt, int df) {
1049static int getnumlimit (Header *h, const char **fmt, int df) { 1046static int getnumlimit (Header *h, const char **fmt, int df) {
1050 int sz = getnum(fmt, df); 1047 int sz = getnum(fmt, df);
1051 if (sz > MAXINTSIZE || sz <= 0) 1048 if (sz > MAXINTSIZE || sz <= 0)
1052 luaL_error(h->L, "integral size (%d) out of limits [1,%d]", sz, MAXINTSIZE); 1049 luaL_error(h->L, "integral size (%d) out of limits [1,%d]",
1050 sz, MAXINTSIZE);
1053 return sz; 1051 return sz;
1054} 1052}
1055 1053
@@ -1133,15 +1131,25 @@ static KOption getdetails (Header *h, size_t totalsize,
1133} 1131}
1134 1132
1135 1133
1134/*
1135** Pack integer 'n' with 'size' bytes and 'islittle' endianness.
1136** The final 'if' handles the case when 'size' is larger than
1137** the size of a Lua integer, correcting the extra sign-extension
1138** bytes if necessary (by default they would be zeros).
1139*/
1136static void packint (luaL_Buffer *b, lua_Unsigned n, 1140static void packint (luaL_Buffer *b, lua_Unsigned n,
1137 int islittle, int size, lua_Unsigned mask) { 1141 int islittle, int size, int neg) {
1138 char *buff = luaL_prepbuffsize(b, size); 1142 char *buff = luaL_prepbuffsize(b, size);
1139 int i; 1143 int i;
1140 for (i = 0; i < size - 1; i++) { 1144 buff[islittle ? 0 : size - 1] = (char)(n & MC); /* first byte */
1145 for (i = 1; i < size; i++) {
1146 n >>= NB;
1141 buff[islittle ? i : size - 1 - i] = (char)(n & MC); 1147 buff[islittle ? i : size - 1 - i] = (char)(n & MC);
1142 n = (n >> NB) | mask;
1143 } 1148 }
1144 buff[islittle ? i : size - 1 - i] = (char)(n & MC); 1149 if (neg) { /* need sign extension (negative number)? */
1150 for (i = SZINT; i < size; i++) /* correct extra bytes */
1151 buff[islittle ? i : size - 1 - i] = (char)MC;
1152 }
1145 luaL_addsize(b, size); /* add result to buffer */ 1153 luaL_addsize(b, size); /* add result to buffer */
1146} 1154}
1147 1155
@@ -1183,12 +1191,11 @@ static int str_pack (lua_State *L) {
1183 switch (opt) { 1191 switch (opt) {
1184 case Kint: { /* signed integers */ 1192 case Kint: { /* signed integers */
1185 lua_Integer n = luaL_checkinteger(L, arg); 1193 lua_Integer n = luaL_checkinteger(L, arg);
1186 lua_Unsigned mask = (n < 0) ? HIGHERBYTE : 0; /* sign extension */
1187 if (size < SZINT) { /* need overflow check? */ 1194 if (size < SZINT) { /* need overflow check? */
1188 lua_Integer lim = (lua_Integer)1 << ((size * NB) - 1); 1195 lua_Integer lim = (lua_Integer)1 << ((size * NB) - 1);
1189 luaL_argcheck(L, -lim <= n && n < lim, arg, "integer overflow"); 1196 luaL_argcheck(L, -lim <= n && n < lim, arg, "integer overflow");
1190 } 1197 }
1191 packint(&b, (lua_Unsigned)n, h.islittle, size, mask); 1198 packint(&b, (lua_Unsigned)n, h.islittle, size, (n < 0));
1192 break; 1199 break;
1193 } 1200 }
1194 case Kuint: { /* unsigned integers */ 1201 case Kuint: { /* unsigned integers */
@@ -1249,6 +1256,14 @@ static int str_pack (lua_State *L) {
1249} 1256}
1250 1257
1251 1258
1259/*
1260** Unpack an integer with 'size' bytes and 'islittle' endianness.
1261** If size is smaller than the size of a Lua integer and integer
1262** is signed, must do sign extension (propagating the sign to the
1263** higher bits); if size is larger than the size of a Lua integer,
1264** it must check the unread bytes to see whether they do not cause an
1265** overflow.
1266*/
1252static lua_Integer unpackint (lua_State *L, const char *str, 1267static lua_Integer unpackint (lua_State *L, const char *str,
1253 int islittle, int size, int issigned) { 1268 int islittle, int size, int issigned) {
1254 lua_Unsigned res = 0; 1269 lua_Unsigned res = 0;
@@ -1264,11 +1279,12 @@ static lua_Integer unpackint (lua_State *L, const char *str,
1264 res = ((res ^ mask) - mask); /* do sign extension */ 1279 res = ((res ^ mask) - mask); /* do sign extension */
1265 } 1280 }
1266 } 1281 }
1267 else { /* must check unread bytes */ 1282 else if (size > SZINT) { /* must check unread bytes */
1268 int mask = (!issigned || (lua_Integer)res >= 0) ? 0 : MC; 1283 int mask = (!issigned || (lua_Integer)res >= 0) ? 0 : MC;
1269 for (i = limit; i < size; i++) { 1284 for (i = limit; i < size; i++) {
1270 if ((unsigned char)str[islittle ? i : size - 1 - i] != mask) 1285 if ((unsigned char)str[islittle ? i : size - 1 - i] != mask)
1271 luaL_error(L, "%d-bit integer does not fit into Lua Integer", size); 1286 luaL_error(L, "%d-bit integer does not fit into Lua Integer",
1287 size * NB);
1272 } 1288 }
1273 } 1289 }
1274 return (lua_Integer)res; 1290 return (lua_Integer)res;