diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2014-11-05 16:50:29 -0200 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2014-11-05 16:50:29 -0200 |
commit | ad73e5156e488f48d291cb2ca0ea3dc0c8d3bdd8 (patch) | |
tree | 13665a116f59858cebf4defd606ccbb2e9c4f397 /lstrlib.c | |
parent | 720c68dabb6f3c960c68fdaa2caea8fe78d92524 (diff) | |
download | lua-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.c | 42 |
1 files changed, 29 insertions, 13 deletions
@@ -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 */ |
974 | static const union { | 971 | static const union { |
@@ -1049,7 +1046,8 @@ static int getnum (const char **fmt, int df) { | |||
1049 | static int getnumlimit (Header *h, const char **fmt, int df) { | 1046 | static 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 | */ | ||
1136 | static void packint (luaL_Buffer *b, lua_Unsigned n, | 1140 | static 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 | */ | ||
1252 | static lua_Integer unpackint (lua_State *L, const char *str, | 1267 | static 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; |