diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2014-10-17 07:55:28 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2014-10-17 07:55:28 -0300 |
commit | c172a4f7c2d452035f9cbb4285f2e6761ab7a68b (patch) | |
tree | b89c21784842759f91664787258576bcf3e32a31 /lstrlib.c | |
parent | f8e0d33b25bcff35a40b1f7493fc660b435119d9 (diff) | |
download | lua-c172a4f7c2d452035f9cbb4285f2e6761ab7a68b.tar.gz lua-c172a4f7c2d452035f9cbb4285f2e6761ab7a68b.tar.bz2 lua-c172a4f7c2d452035f9cbb4285f2e6761ab7a68b.zip |
'dumpint' and related functions replaced by 'string.pack'/'string.unpack'
Diffstat (limited to 'lstrlib.c')
-rw-r--r-- | lstrlib.c | 497 |
1 files changed, 340 insertions, 157 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lstrlib.c,v 1.201 2014/08/20 22:06:41 roberto Exp roberto $ | 2 | ** $Id: lstrlib.c,v 1.202 2014/10/01 11:54:56 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 | */ |
@@ -950,214 +950,399 @@ static int str_format (lua_State *L) { | |||
950 | */ | 950 | */ |
951 | 951 | ||
952 | 952 | ||
953 | /* maximum size for the binary representation of an integer */ | ||
954 | #define MAXINTSIZE 16 | ||
955 | |||
953 | /* number of bits in a character */ | 956 | /* number of bits in a character */ |
954 | #define NB CHAR_BIT | 957 | #define NB CHAR_BIT |
955 | 958 | ||
956 | /* mask for one character (NB 1's) */ | 959 | /* mask for one character (NB 1's) */ |
957 | #define MC ((1 << NB) - 1) | 960 | #define MC ((1 << NB) - 1) |
958 | 961 | ||
959 | /* mask for one character without sign bit ((NB - 1) 1's) */ | ||
960 | #define SM (MC >> 1) | ||
961 | |||
962 | /* size of a lua_Integer */ | 962 | /* size of a lua_Integer */ |
963 | #define SZINT ((int)sizeof(lua_Integer)) | 963 | #define SZINT ((int)sizeof(lua_Integer)) |
964 | 964 | ||
965 | /* maximum size for the binary representation of an integer */ | 965 | /* mask for all ones in last byte in a lua Integer */ |
966 | #define MAXINTSIZE 12 | 966 | #define HIGHERBYTE ((lua_Unsigned)MC << (NB * (SZINT - 1))) |
967 | 967 | ||
968 | 968 | ||
969 | static union { | 969 | /* dummy union to get native endianness */ |
970 | static const union { | ||
970 | int dummy; | 971 | int dummy; |
971 | char little; /* true iff machine is little endian */ | 972 | char little; /* true iff machine is little endian */ |
972 | } const nativeendian = {1}; | 973 | } nativeendian = {1}; |
973 | 974 | ||
974 | 975 | ||
975 | static int getendian (lua_State *L, int arg) { | 976 | /* dummy structure to get native alignment requirements */ |
976 | const char *endian = luaL_optstring(L, arg, | 977 | struct cD { |
977 | (nativeendian.little ? "l" : "b")); | 978 | char c; |
978 | if (*endian == 'n') /* native? */ | 979 | union { double d; void *p; lua_Integer i; lua_Number n; } u; |
979 | return nativeendian.little; | 980 | }; |
980 | luaL_argcheck(L, *endian == 'l' || *endian == 'b', arg, | ||
981 | "endianness must be 'l'/'b'/'n'"); | ||
982 | return (*endian == 'l'); | ||
983 | } | ||
984 | 981 | ||
982 | #define MAXALIGN (offsetof(struct cD, u)) | ||
985 | 983 | ||
986 | static int getintsize (lua_State *L, int arg) { | ||
987 | lua_Integer size = luaL_optinteger(L, arg, 0); | ||
988 | if (size == 0) size = SZINT; | ||
989 | luaL_argcheck(L, 1 <= size && size <= MAXINTSIZE, arg, | ||
990 | "integer size out of valid range"); | ||
991 | return (int)size; | ||
992 | } | ||
993 | 984 | ||
985 | /* | ||
986 | ** Union for serializing floats | ||
987 | */ | ||
988 | typedef union Ftypes { | ||
989 | float f; | ||
990 | double d; | ||
991 | lua_Number n; | ||
992 | char buff[5 * sizeof(lua_Number)]; /* enough for any float type */ | ||
993 | } Ftypes; | ||
994 | 994 | ||
995 | /* mask for all ones in last byte in a lua Integer */ | ||
996 | #define HIGHERBYTE ((lua_Unsigned)MC << (NB * (SZINT - 1))) | ||
997 | 995 | ||
996 | /* | ||
997 | ** information to pack/unpack stuff | ||
998 | */ | ||
999 | typedef struct Header { | ||
1000 | lua_State *L; | ||
1001 | int islittle; | ||
1002 | int maxalign; | ||
1003 | } Header; | ||
998 | 1004 | ||
999 | static int dumpint (char *buff, lua_Integer m, int littleendian, int size) { | 1005 | |
1000 | int i; | 1006 | typedef enum KOption {Kint, Kuint, Kfloat, Kchar, Kstring, Kstring0, |
1001 | lua_Unsigned n = (lua_Unsigned)m; | 1007 | Kspace, Kpadding, Kpaddalig} KOption; |
1002 | lua_Unsigned mask = (m >= 0) ? 0 : HIGHERBYTE; /* sign extension */ | 1008 | |
1003 | if (littleendian) { | 1009 | |
1004 | for (i = 0; i < size - 1; i++) { | 1010 | /* |
1005 | buff[i] = (n & MC); | 1011 | ** Read an integer numeral from string 'fmt' or return 'df' if |
1006 | n = (n >> NB) | mask; | 1012 | ** there is no numeral |
1007 | } | 1013 | */ |
1008 | } | 1014 | static int digit (int c) { return '0' <= c && c <= '9'; } |
1015 | |||
1016 | static int getnum (const char **fmt, int df) { | ||
1017 | if (!digit(**fmt)) /* no number? */ | ||
1018 | return df; /* return default value */ | ||
1009 | else { | 1019 | else { |
1010 | for (i = size - 1; i > 0; i--) { | 1020 | int a = 0; |
1011 | buff[i] = (n & MC); | 1021 | do { |
1012 | n = (n >> NB) | mask; | 1022 | a = a*10 + *((*fmt)++) - '0'; |
1013 | } | 1023 | } while (digit(**fmt) && a < (INT_MAX/10 - 10)); |
1014 | } | 1024 | return a; |
1015 | buff[i] = (n & MC); /* last byte */ | ||
1016 | if (size < SZINT) { /* need test for overflow? */ | ||
1017 | /* OK if there are only zeros left in higher bytes, | ||
1018 | or only ones left (excluding non-signal bits in last byte) */ | ||
1019 | return ((n & ~(lua_Unsigned)MC) == 0 || | ||
1020 | (n | SM) == ~(lua_Unsigned)0); | ||
1021 | } | 1025 | } |
1022 | else return 1; /* no overflow can occur with full size */ | ||
1023 | } | 1026 | } |
1024 | 1027 | ||
1025 | 1028 | ||
1026 | static int dumpint_l (lua_State *L) { | 1029 | /* |
1027 | char buff[MAXINTSIZE]; | 1030 | ** Read an integer numeral and raises an error if it is larger |
1028 | lua_Integer n = luaL_checkinteger(L, 1); | 1031 | ** than the maximum size for integers. |
1029 | int size = getintsize(L, 2); | 1032 | */ |
1030 | int endian = getendian(L, 3); | 1033 | static int getnumlimit (Header *h, const char **fmt, int df) { |
1031 | if (dumpint(buff, n, endian, size)) | 1034 | int sz = getnum(fmt, df); |
1032 | lua_pushlstring(L, buff, size); | 1035 | if (sz > MAXINTSIZE || sz <= 0) |
1033 | else | 1036 | luaL_error(h->L, "integral size (%d) out of limits [1,%d]", sz, MAXINTSIZE); |
1034 | luaL_error(L, "integer does not fit into given size (%d)", size); | 1037 | return sz; |
1035 | return 1; | ||
1036 | } | 1038 | } |
1037 | 1039 | ||
1038 | 1040 | ||
1039 | /* mask to check higher-order byte + signal bit of next (lower) byte */ | 1041 | /* |
1040 | #define HIGHERBYTE1 (HIGHERBYTE | (HIGHERBYTE >> 1)) | 1042 | ** Reads an option endianness indication ('<'/'>') and |
1043 | ** returns true if operation should use little endian. | ||
1044 | */ | ||
1045 | static int getendian (const char **fmt) { | ||
1046 | if (**fmt == '<' || **fmt == '>') /* explicit endianness? */ | ||
1047 | return (*((*fmt)++) == '<'); /* true iff little endian */ | ||
1048 | else /* no endian indication */ | ||
1049 | return nativeendian.little; /* use native */ | ||
1050 | } | ||
1041 | 1051 | ||
1042 | 1052 | ||
1043 | static int undumpint (const char *buff, lua_Integer *res, | 1053 | /* |
1044 | int littleendian, int size) { | 1054 | ** Read and return maximum alignment to be used |
1045 | lua_Unsigned n = 0; | 1055 | */ |
1046 | int i; | 1056 | static int getalignment (Header *h, const char **fmt) { |
1047 | for (i = 0; i < size; i++) { | 1057 | if (**fmt == '!') { /* explicit alignment? */ |
1048 | if (i >= SZINT) { /* will throw away a byte? */ | 1058 | (*fmt)++; /* skip '!' */ |
1049 | /* check for overflow: it is OK to throw away leading zeros for a | 1059 | return getnumlimit(h, fmt, MAXALIGN); |
1050 | positive number, leading ones for a negative number, and a | ||
1051 | leading zero byte to allow unsigned integers with a 1 in | ||
1052 | its "signal bit" */ | ||
1053 | if (!((n & HIGHERBYTE1) == 0 || /* zeros for positive number */ | ||
1054 | (n & HIGHERBYTE1) == HIGHERBYTE1 || /* ones for negative number */ | ||
1055 | (i == size - 1 && (n & HIGHERBYTE) == 0))) /* leading zero */ | ||
1056 | return 0; /* overflow */ | ||
1057 | } | ||
1058 | n <<= NB; | ||
1059 | n |= (lua_Unsigned)(unsigned char)buff[littleendian ? size - 1 - i : i]; | ||
1060 | } | ||
1061 | if (size < SZINT) { /* need sign extension? */ | ||
1062 | lua_Unsigned mask = (lua_Unsigned)1 << (size*NB - 1); | ||
1063 | *res = (lua_Integer)((n ^ mask) - mask); /* do sign extension */ | ||
1064 | } | 1060 | } |
1065 | else | 1061 | else |
1066 | *res = (lua_Integer)n; | 1062 | return 1; /* default is no alignment */ |
1067 | return 1; | ||
1068 | } | 1063 | } |
1069 | 1064 | ||
1070 | 1065 | ||
1071 | static int undumpint_l (lua_State *L) { | 1066 | /* |
1072 | lua_Integer res; | 1067 | ** Read optional endianness and alignment indications |
1073 | size_t len; | 1068 | */ |
1074 | const char *s = luaL_checklstring(L, 1, &len); | 1069 | static void getheader (lua_State *L, Header *h, const char **fmt) { |
1075 | lua_Integer pos = posrelat(luaL_optinteger(L, 2, 1), len); | 1070 | h->L = L; |
1076 | int size = getintsize(L, 3); | 1071 | h->islittle = getendian(fmt); |
1077 | int endian = getendian(L, 4); | 1072 | h->maxalign = getalignment(h, fmt); |
1078 | luaL_argcheck(L, 1 <= pos && (size_t)pos + size - 1 <= len, 1, | ||
1079 | "string too short"); | ||
1080 | if(undumpint(s + pos - 1, &res, endian, size)) | ||
1081 | lua_pushinteger(L, res); | ||
1082 | else | ||
1083 | luaL_error(L, "result does not fit into a Lua integer"); | ||
1084 | return 1; | ||
1085 | } | 1073 | } |
1086 | 1074 | ||
1087 | 1075 | ||
1088 | static void correctendianness (lua_State *L, char *b, int size, int endianarg) { | 1076 | /* |
1089 | int endian = getendian(L, endianarg); | 1077 | ** Read and classify next option. 'size' is filled with option's size. |
1090 | if (endian != nativeendian.little) { /* not native endianness? */ | 1078 | */ |
1091 | int i = 0; | 1079 | static KOption getoption (Header *h, const char **fmt, int *size) { |
1092 | while (i < --size) { | 1080 | int opt = *((*fmt)++); |
1093 | char temp = b[i]; | 1081 | switch (opt) { |
1094 | b[i++] = b[size]; | 1082 | case 'b': *size = sizeof(char); return Kint; |
1095 | b[size] = temp; | 1083 | case 'B': *size = sizeof(char); return Kuint; |
1084 | case 'h': *size = sizeof(short); return Kint; | ||
1085 | case 'H': *size = sizeof(short); return Kuint; | ||
1086 | case 'l': *size = sizeof(long); return Kint; | ||
1087 | case 'L': *size = sizeof(long); return Kuint; | ||
1088 | case 'j': *size = sizeof(lua_Integer); return Kint; | ||
1089 | case 'J': *size = sizeof(lua_Integer); return Kuint; | ||
1090 | case 'T': *size = sizeof(size_t); return Kuint; | ||
1091 | case 'f': *size = sizeof(float); return Kfloat; | ||
1092 | case 'd': *size = sizeof(double); return Kfloat; | ||
1093 | case 'n': *size = sizeof(lua_Number); return Kfloat; | ||
1094 | case 'i': *size = getnumlimit(h, fmt, sizeof(int)); return Kint; | ||
1095 | case 'I': *size = getnumlimit(h, fmt, sizeof(int)); return Kuint; | ||
1096 | case 's': *size = getnumlimit(h, fmt, sizeof(size_t)); return Kstring; | ||
1097 | case 'c': *size = getnum(fmt, 1); return Kchar; | ||
1098 | case 'z': *size = 0; return Kstring0; | ||
1099 | case 'x': *size = 1; return Kpadding; | ||
1100 | case 'X': *size = 0; return Kpaddalig; | ||
1101 | case ' ': *size = 0; return Kspace; | ||
1102 | default: { | ||
1103 | *size = 0; /* to avoid warnings */ | ||
1104 | luaL_error(h->L, "invalid format option '%c'", opt); | ||
1105 | return (KOption)0; | ||
1096 | } | 1106 | } |
1097 | } | 1107 | } |
1098 | } | 1108 | } |
1099 | 1109 | ||
1100 | 1110 | ||
1101 | static int getfloatsize (lua_State *L, int arg) { | 1111 | /* |
1102 | const char *size = luaL_optstring(L, arg, "n"); | 1112 | ** Read, classify, and fill other details about the next option. |
1103 | if (*size == 'n') return sizeof(lua_Number); | 1113 | ** 'psize' is filled with option's size, 'notoalign' with its |
1104 | luaL_argcheck(L, *size == 'd' || *size == 'f', arg, | 1114 | ** alignment requirements. |
1105 | "size must be 'f'/'d'/'n'"); | 1115 | ** Local variable 'size' gets the size to be aligned. (Kpadal option |
1106 | return (*size == 'd' ? sizeof(double) : sizeof(float)); | 1116 | ** always gets its full alignment, other options are limited by |
1117 | ** the maximum alignment ('maxalign). Kchar option needs no aligment | ||
1118 | ** despite its size. | ||
1119 | */ | ||
1120 | static KOption getdetails (Header *h, size_t totalsize, | ||
1121 | const char **fmt, int *psize, int *ntoalign) { | ||
1122 | KOption opt = getoption(h, fmt, psize); | ||
1123 | int align = *psize; /* usually, alignment follows size */ | ||
1124 | if (opt == Kpaddalig) { | ||
1125 | if (**fmt == '\0' || strchr("Xc ", **fmt) != NULL) | ||
1126 | luaL_argerror(h->L, 1, "invalid next option for option 'X'"); | ||
1127 | getoption(h, fmt, &align); /* get next element's size for alignment */ | ||
1128 | } | ||
1129 | if (align <= 1 || opt == Kchar) /* need no alignment? */ | ||
1130 | *ntoalign = 0; | ||
1131 | else { | ||
1132 | if (align > h->maxalign) | ||
1133 | align = h->maxalign; | ||
1134 | if ((align & (align - 1)) != 0) /* is 'align' not a power of 2? */ | ||
1135 | luaL_argerror(h->L, 1, "format asks for alignment not power of 2"); | ||
1136 | *ntoalign = (align - (int)(totalsize & (align - 1))) & (align - 1); | ||
1137 | } | ||
1138 | return opt; | ||
1107 | } | 1139 | } |
1108 | 1140 | ||
1109 | 1141 | ||
1110 | static int dumpfloat_l (lua_State *L) { | 1142 | static void packint (luaL_Buffer *b, lua_Unsigned n, |
1111 | float f; double d; | 1143 | int islittle, int size, lua_Unsigned mask) { |
1112 | char *pn; /* pointer to number */ | 1144 | char *buff = luaL_prepbuffsize(b, size); |
1113 | lua_Number n = luaL_checknumber(L, 1); | 1145 | int i; |
1114 | int size = getfloatsize(L, 2); | 1146 | for (i = 0; i < size - 1; i++) { |
1115 | if (size == sizeof(lua_Number)) | 1147 | buff[islittle ? i : size - 1 - i] = (n & MC); |
1116 | pn = (char*)&n; | 1148 | n = (n >> NB) | mask; |
1117 | else if (size == sizeof(float)) { | ||
1118 | f = (float)n; | ||
1119 | pn = (char*)&f; | ||
1120 | } | ||
1121 | else { /* native lua_Number may be neither float nor double */ | ||
1122 | lua_assert(size == sizeof(double)); | ||
1123 | d = (double)n; | ||
1124 | pn = (char*)&d; | ||
1125 | } | 1149 | } |
1126 | correctendianness(L, pn, size, 3); | 1150 | buff[islittle ? i : size - 1 - i] = (n & MC); |
1127 | lua_pushlstring(L, pn, size); | 1151 | luaL_addsize(b, size); /* add result to buffer */ |
1128 | return 1; | ||
1129 | } | 1152 | } |
1130 | 1153 | ||
1131 | 1154 | ||
1132 | static int undumpfloat_l (lua_State *L) { | 1155 | /* |
1133 | lua_Number res; | 1156 | ** Copy 'size' bytes from 'src' to 'dest', correcting endianness if |
1134 | size_t len; | 1157 | ** given 'islittle' is different from native endianness. |
1135 | const char *s = luaL_checklstring(L, 1, &len); | 1158 | */ |
1136 | lua_Integer pos = posrelat(luaL_optinteger(L, 2, 1), len); | 1159 | static void copywithendian (volatile char *dest, volatile const char *src, |
1137 | int size = getfloatsize(L, 3); | 1160 | int size, int islittle) { |
1138 | luaL_argcheck(L, 1 <= pos && (size_t)pos + size - 1 <= len, 1, | 1161 | if (islittle == nativeendian.little) { |
1139 | "string too short"); | 1162 | while (size-- != 0) |
1140 | if (size == sizeof(lua_Number)) { | 1163 | *(dest++) = *(src++); |
1141 | memcpy(&res, s + pos - 1, size); | ||
1142 | correctendianness(L, (char*)&res, size, 4); | ||
1143 | } | 1164 | } |
1144 | else if (size == sizeof(float)) { | 1165 | else { |
1145 | float f; | 1166 | dest += size - 1; |
1146 | memcpy(&f, s + pos - 1, size); | 1167 | while (size-- != 0) |
1147 | correctendianness(L, (char*)&f, size, 4); | 1168 | *(dest--) = *(src++); |
1148 | res = (lua_Number)f; | 1169 | } |
1149 | } | 1170 | } |
1150 | else { /* native lua_Number may be neither float nor double */ | 1171 | |
1151 | double d; | 1172 | |
1152 | lua_assert(size == sizeof(double)); | 1173 | static int str_pack (lua_State *L) { |
1153 | memcpy(&d, s + pos - 1, size); | 1174 | luaL_Buffer b; |
1154 | correctendianness(L, (char*)&d, size, 4); | 1175 | Header h; |
1155 | res = (lua_Number)d; | 1176 | const char *fmt = luaL_checkstring(L, 1); /* format string */ |
1177 | int arg = 1; /* current argument to pack */ | ||
1178 | size_t totalsize = 0; /* accumulate total size of result */ | ||
1179 | getheader(L, &h, &fmt); | ||
1180 | lua_pushnil(L); /* mark to separate arguments from string buffer */ | ||
1181 | luaL_buffinit(L, &b); | ||
1182 | while (*fmt != '\0') { | ||
1183 | int size, ntoalign; | ||
1184 | KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign); | ||
1185 | totalsize += ntoalign + size; | ||
1186 | while (ntoalign-- > 0) luaL_addchar(&b, '\0'); /* fill alignment */ | ||
1187 | arg++; | ||
1188 | switch (opt) { | ||
1189 | case Kint: { /* signed integers */ | ||
1190 | lua_Integer n = luaL_checkinteger(L, arg); | ||
1191 | lua_Unsigned mask = (n < 0) ? HIGHERBYTE : 0; /* sign extension */ | ||
1192 | if (size < SZINT) { /* need overflow check? */ | ||
1193 | lua_Integer lim = (lua_Integer)1 << ((size * NB) - 1); | ||
1194 | luaL_argcheck(L, -lim <= n && n < lim, arg, "integer overflow"); | ||
1195 | } | ||
1196 | packint(&b, (lua_Unsigned)n, h.islittle, size, mask); | ||
1197 | break; | ||
1198 | } | ||
1199 | case Kuint: { /* unsigned integers */ | ||
1200 | lua_Integer n = luaL_checkinteger(L, arg); | ||
1201 | if (size < SZINT) /* need overflow check? */ | ||
1202 | luaL_argcheck(L, (lua_Unsigned)n < ((lua_Unsigned)1 << (size * NB)), | ||
1203 | arg, "unsigned overflow"); | ||
1204 | packint(&b, (lua_Unsigned)n, h.islittle, size, 0); | ||
1205 | break; | ||
1206 | } | ||
1207 | case Kfloat: { /* floating-point options */ | ||
1208 | volatile Ftypes u; | ||
1209 | char *buff = luaL_prepbuffsize(&b, size); | ||
1210 | lua_Number n = luaL_checknumber(L, arg); /* get argument */ | ||
1211 | if (size == sizeof(u.f)) u.f = (float)n; /* copy it into 'u' */ | ||
1212 | else if (size == sizeof(u.d)) u.d = (double)n; | ||
1213 | else u.n = n; | ||
1214 | /* move 'u' to final result, correcting endianness if needed */ | ||
1215 | copywithendian(buff, u.buff, size, h.islittle); | ||
1216 | luaL_addsize(&b, size); | ||
1217 | break; | ||
1218 | } | ||
1219 | case Kchar: { /* fixed-size string */ | ||
1220 | size_t len; | ||
1221 | const char *s = luaL_checklstring(L, arg, &len); | ||
1222 | luaL_argcheck(L, len == (size_t)size, arg, "wrong length"); | ||
1223 | luaL_addlstring(&b, s, size); | ||
1224 | break; | ||
1225 | } | ||
1226 | case Kstring: { /* strings with length count */ | ||
1227 | size_t len; | ||
1228 | const char *s = luaL_checklstring(L, arg, &len); | ||
1229 | luaL_argcheck(L, size >= (int)sizeof(size_t) || | ||
1230 | len < ((size_t)1 << (size * NB)), | ||
1231 | arg, "string length does not fit in given size"); | ||
1232 | packint(&b, (lua_Unsigned)len, h.islittle, size, 0); /* pack length */ | ||
1233 | luaL_addlstring(&b, s, len); | ||
1234 | totalsize += len; | ||
1235 | break; | ||
1236 | } | ||
1237 | case Kstring0: { /* zero-terminated string */ | ||
1238 | size_t len; | ||
1239 | const char *s = luaL_checklstring(L, arg, &len); | ||
1240 | luaL_argcheck(L, strlen(s) == len, arg, "string contains zeros"); | ||
1241 | luaL_addlstring(&b, s, len); | ||
1242 | luaL_addchar(&b, '\0'); /* add zero at the end */ | ||
1243 | totalsize += len + 1; | ||
1244 | break; | ||
1245 | } | ||
1246 | case Kpadding: luaL_addchar(&b, '\0'); /* go through */ | ||
1247 | case Kpaddalig: case Kspace: | ||
1248 | arg--; /* undo increment */ | ||
1249 | break; | ||
1250 | } | ||
1156 | } | 1251 | } |
1157 | lua_pushnumber(L, res); | 1252 | luaL_pushresult(&b); |
1158 | return 1; | 1253 | return 1; |
1159 | } | 1254 | } |
1160 | 1255 | ||
1256 | |||
1257 | static lua_Integer unpackint (lua_State *L, const char *str, | ||
1258 | int islittle, int size, int issigned) { | ||
1259 | lua_Unsigned res = 0; | ||
1260 | int i; | ||
1261 | int limit = (size <= SZINT) ? size : SZINT; | ||
1262 | for (i = limit - 1; i >= 0; i--) { | ||
1263 | res <<= NB; | ||
1264 | res |= (lua_Unsigned)(unsigned char)str[islittle ? i : size - 1 - i]; | ||
1265 | } | ||
1266 | if (size < SZINT) { /* real size smaller than lua_Integer? */ | ||
1267 | if (issigned) { /* needs sign extension? */ | ||
1268 | lua_Unsigned mask = (lua_Unsigned)1 << (size*NB - 1); | ||
1269 | res = ((res ^ mask) - mask); /* do sign extension */ | ||
1270 | } | ||
1271 | } | ||
1272 | else { /* must check unread bytes */ | ||
1273 | int mask = (!issigned || (lua_Integer)res >= 0) ? 0 : MC; | ||
1274 | for (i = limit; i < size; i++) { | ||
1275 | if ((unsigned char)str[islittle ? i : size - 1 - i] != mask) | ||
1276 | luaL_error(L, "%d-bit integer does not fit into Lua Integer", size); | ||
1277 | } | ||
1278 | } | ||
1279 | return (lua_Integer)res; | ||
1280 | } | ||
1281 | |||
1282 | |||
1283 | static int str_unpack (lua_State *L) { | ||
1284 | Header h; | ||
1285 | const char *fmt = luaL_checkstring(L, 1); | ||
1286 | size_t ld; | ||
1287 | const char *data = luaL_checklstring(L, 2, &ld); | ||
1288 | size_t pos = (size_t)posrelat(luaL_optinteger(L, 3, 1), ld) - 1; | ||
1289 | int n = 0; /* number of results */ | ||
1290 | luaL_argcheck(L, pos <= ld, 3, "initial position out of string"); | ||
1291 | getheader(L, &h, &fmt); | ||
1292 | while (*fmt) { | ||
1293 | int size, ntoalign; | ||
1294 | KOption opt = getdetails(&h, pos, &fmt, &size, &ntoalign); | ||
1295 | if ((size_t)ntoalign + size > ~pos || pos + ntoalign + size > ld) | ||
1296 | luaL_argerror(L, 2, "data string too short"); | ||
1297 | pos += ntoalign; | ||
1298 | /* stack space for item + next position */ | ||
1299 | luaL_checkstack(L, 2, "too many results"); | ||
1300 | n++; | ||
1301 | switch (opt) { | ||
1302 | case Kint: | ||
1303 | case Kuint: { | ||
1304 | lua_Integer res = unpackint(L, data + pos, h.islittle, size, | ||
1305 | (opt == Kint)); | ||
1306 | lua_pushinteger(L, res); | ||
1307 | break; | ||
1308 | } | ||
1309 | case Kfloat: { | ||
1310 | volatile Ftypes u; | ||
1311 | lua_Number num; | ||
1312 | copywithendian(u.buff, data + pos, size, h.islittle); | ||
1313 | if (size == sizeof(u.f)) num = (lua_Number)u.f; | ||
1314 | else if (size == sizeof(u.d)) num = (lua_Number)u.d; | ||
1315 | else num = u.n; | ||
1316 | lua_pushnumber(L, num); | ||
1317 | break; | ||
1318 | } | ||
1319 | case Kchar: { | ||
1320 | lua_pushlstring(L, data + pos, size); | ||
1321 | break; | ||
1322 | } | ||
1323 | case Kstring: { | ||
1324 | size_t len = (size_t)unpackint(L, data + pos, h.islittle, size, 0); | ||
1325 | luaL_argcheck(L, pos + len + size <= ld, 2, "data string too short"); | ||
1326 | lua_pushlstring(L, data + pos + size, len); | ||
1327 | pos += len; | ||
1328 | break; | ||
1329 | } | ||
1330 | case Kstring0: { | ||
1331 | size_t len = (int)strlen(data + pos); | ||
1332 | lua_pushlstring(L, data + pos, len); | ||
1333 | pos += len + 1; /* skip final '\0' */ | ||
1334 | break; | ||
1335 | } | ||
1336 | case Kpaddalig: case Kpadding: case Kspace: | ||
1337 | n--; /* undo increment */ | ||
1338 | break; | ||
1339 | } | ||
1340 | pos += size; | ||
1341 | } | ||
1342 | lua_pushinteger(L, pos + 1); /* next position */ | ||
1343 | return n + 1; | ||
1344 | } | ||
1345 | |||
1161 | /* }====================================================== */ | 1346 | /* }====================================================== */ |
1162 | 1347 | ||
1163 | 1348 | ||
@@ -1176,10 +1361,8 @@ static const luaL_Reg strlib[] = { | |||
1176 | {"reverse", str_reverse}, | 1361 | {"reverse", str_reverse}, |
1177 | {"sub", str_sub}, | 1362 | {"sub", str_sub}, |
1178 | {"upper", str_upper}, | 1363 | {"upper", str_upper}, |
1179 | {"dumpfloat", dumpfloat_l}, | 1364 | {"pack", str_pack}, |
1180 | {"dumpinteger", dumpint_l}, | 1365 | {"unpack", str_unpack}, |
1181 | {"undumpfloat", undumpfloat_l}, | ||
1182 | {"undumpinteger", undumpint_l}, | ||
1183 | {NULL, NULL} | 1366 | {NULL, NULL} |
1184 | }; | 1367 | }; |
1185 | 1368 | ||