diff options
| -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; |
