1 2 #include <assert.h> 3 #include <ctype.h> 4 #include <limits.h> 5 #include <string.h> 6 7 8 #include "lua.h" 9 #include "lauxlib.h" 10 11 12 /* 13 ** {====================================================== 14 ** Library for packing/unpacking structures. 15 ** $Id: struct.c,v 1.2 2008/04/18 20:06:01 roberto Exp $ 16 ** See Copyright Notice at the end of this file 17 ** ======================================================= 18 */ 19 /* 20 ** Valid formats: 21 ** > - big endian 22 ** < - little endian 23 ** ![num] - alignment 24 ** x - pading 25 ** b/B - signed/unsigned byte 26 ** h/H - signed/unsigned short 27 ** l/L - signed/unsigned long 28 ** i/In - signed/unsigned integer with size `n' (default is size of int) 29 ** cn - sequence of `n' chars (from/to a string); when packing, n==0 means 30 the whole string; when unpacking, n==0 means use the previous 31 read number as the string length 32 ** s - zero-terminated string 33 ** f - float 34 ** d - double 35 ** ' ' - ignored 36 */ 37 38 39 /* is 'x' a power of 2? */ 40 #define isp2(x) ((x) > 0 && ((x) & ((x) - 1)) == 0) 41 42 /* dummy structure to get alignment requirements */ 43 struct cD { 44 char c; 45 double d; 46 }; 47 48 49 #define PADDING (sizeof(struct cD) - sizeof(double)) 50 #define MAXALIGN (PADDING > sizeof(int) ? PADDING : sizeof(int)) 51 52 53 /* endian options */ 54 #define BIG 0 55 #define LITTLE 1 56 57 58 static union { 59 int dummy; 60 char endian; 61 } const native = {1}; 62 63 64 typedef struct Header { 65 int endian; 66 int align; 67 } Header; 68 69 70 static size_t getnum (const char **fmt, size_t df) { 71 if (!isdigit(**fmt)) /* no number? */ 72 return df; /* return default value */ 73 else { 74 size_t a = 0; 75 do { 76 a = a*10 + *((*fmt)++) - '0'; 77 } while (isdigit(**fmt)); 78 return a; 79 } 80 } 81 82 83 #define defaultoptions(h) ((h)->endian = native.endian, (h)->align = 1) 84 85 86 87 static size_t optsize (lua_State *L, char opt, const char **fmt) { 88 switch (opt) { 89 case 'B': case 'b': return sizeof(char); 90 case 'H': case 'h': return sizeof(short); 91 case 'L': case 'l': return sizeof(long); 92 case 'f': return sizeof(float); 93 case 'd': return sizeof(double); 94 case 'x': return 1; 95 case 'c': return getnum(fmt, 1); 96 case 's': case ' ': case '<': case '>': case '!': return 0; 97 case 'i': case 'I': { 98 int sz = getnum(fmt, sizeof(int)); 99 if (!isp2(sz)) 100 luaL_error(L, "integral size %d is not a power of 2", sz); 101 return sz; 102 } 103 default: { 104 const char *msg = lua_pushfstring(L, "invalid format option [%c]", opt); 105 return luaL_argerror(L, 1, msg); 106 } 107 } 108 } 109 110 111 static int gettoalign (size_t len, Header *h, int opt, size_t size) { 112 if (size == 0 || opt == 'c') return 0; 113 if (size > (size_t)h->align) size = h->align; /* respect max. alignment */ 114 return (size - (len & (size - 1))) & (size - 1); 115 } 116 117 118 static void commoncases (lua_State *L, int opt, const char **fmt, Header *h) { 119 switch (opt) { 120 case ' ': return; /* ignore white spaces */ 121 case '>': h->endian = BIG; return; 122 case '<': h->endian = LITTLE; return; 123 case '!': { 124 int a = getnum(fmt, MAXALIGN); 125 if (!isp2(a)) 126 luaL_error(L, "alignment %d is not a power of 2", a); 127 h->align = a; 128 return; 129 } 130 default: assert(0); 131 } 132 } 133 134 135 static void putinteger (lua_State *L, luaL_Buffer *b, int arg, int endian, 136 int size) { 137 lua_Number n = luaL_checknumber(L, arg); 138 unsigned long value; 139 if (n < (lua_Number)LONG_MAX) 140 value = (long)n; 141 else 142 value = (unsigned long)n; 143 if (endian == LITTLE) { 144 int i; 145 for (i = 0; i < size; i++) 146 luaL_addchar(b, (value >> 8*i) & 0xff); 147 } 148 else { 149 int i; 150 for (i = size - 1; i >= 0; i--) 151 luaL_addchar(b, (value >> 8*i) & 0xff); 152 } 153 } 154 155 156 static void correctbytes (char *b, int size, int endian) { 157 if (endian != native.endian) { 158 int i = 0; 159 while (i < --size) { 160 char temp = b[i]; 161 b[i++] = b[size]; 162 b[size] = temp; 163 } 164 } 165 } 166 167 168 static int b_pack (lua_State *L) { 169 luaL_Buffer b; 170 const char *fmt = luaL_checkstring(L, 1); 171 Header h; 172 int arg = 2; 173 size_t totalsize = 0; 174 defaultoptions(&h); 175 lua_pushnil(L); /* mark to separate arguments from string buffer */ 176 luaL_buffinit(L, &b); 177 while (*fmt != '\0') { 178 int opt = *fmt++; 179 size_t size = optsize(L, opt, &fmt); 180 int toalign = gettoalign(totalsize, &h, opt, size); 181 totalsize += toalign; 182 while (toalign-- > 0) luaL_putchar(&b, '\0'); 183 switch (opt) { 184 case 'b': case 'B': case 'h': case 'H': 185 case 'l': case 'L': case 'i': case 'I': { /* integer types */ 186 putinteger(L, &b, arg++, h.endian, size); 187 break; 188 } 189 case 'x': { 190 luaL_putchar(&b, '\0'); 191 break; 192 } 193 case 'f': { 194 float f = (float)luaL_checknumber(L, arg++); 195 correctbytes((char *)&f, size, h.endian); 196 luaL_addlstring(&b, (char *)&f, size); 197 break; 198 } 199 case 'd': { 200 double d = luaL_checknumber(L, arg++); 201 correctbytes((char *)&d, size, h.endian); 202 luaL_addlstring(&b, (char *)&d, size); 203 break; 204 } 205 case 'c': case 's': { 206 size_t l; 207 const char *s = luaL_checklstring(L, arg++, &l); 208 if (size == 0) size = l; 209 luaL_argcheck(L, l >= (size_t)size, arg, "string too short"); 210 luaL_addlstring(&b, s, size); 211 if (opt == 's') { 212 luaL_putchar(&b, '\0'); /* add zero at the end */ 213 size++; 214 } 215 break; 216 } 217 default: commoncases(L, opt, &fmt, &h); 218 } 219 totalsize += size; 220 } 221 luaL_pushresult(&b); 222 return 1; 223 } 224 225 226 static lua_Number getinteger (const char *buff, int endian, 227 int issigned, int size) { 228 unsigned long l = 0; 229 if (endian == BIG) { 230 int i; 231 for (i = 0; i < size; i++) 232 l |= (unsigned long)(unsigned char)buff[size - i - 1] << (i*8); 233 } 234 else { 235 int i; 236 for (i = 0; i < size; i++) 237 l |= (unsigned long)(unsigned char)buff[i] << (i*8); 238 } 239 if (!issigned) 240 return (lua_Number)l; 241 else { /* signed format */ 242 unsigned long mask = ~(0UL) << (size*8 - 1); 243 if (l & mask) /* negative value? */ 244 l |= mask; /* signal extension */ 245 return (lua_Number)(long)l; 246 } 247 } 248 249 250 static int b_unpack (lua_State *L) { 251 Header h; 252 const char *fmt = luaL_checkstring(L, 1); 253 size_t ld; 254 const char *data = luaL_checklstring(L, 2, &ld); 255 size_t pos = luaL_optinteger(L, 3, 1) - 1; 256 defaultoptions(&h); 257 lua_settop(L, 2); 258 while (*fmt) { 259 int opt = *fmt++; 260 size_t size = optsize(L, opt, &fmt); 261 pos += gettoalign(pos, &h, opt, size); 262 luaL_argcheck(L, pos+size <= ld, 2, "data string too short"); 263 switch (opt) { 264 case 'b': case 'B': case 'h': case 'H': 265 case 'l': case 'L': case 'i': case 'I': { /* integer types */ 266 int issigned = islower(opt); 267 lua_Number res = getinteger(data+pos, h.endian, issigned, size); 268 lua_pushnumber(L, res); 269 break; 270 } 271 case 'x': { 272 break; 273 } 274 case 'f': { 275 float f; 276 memcpy(&f, data+pos, size); 277 correctbytes((char *)&f, sizeof(f), h.endian); 278 lua_pushnumber(L, f); 279 break; 280 } 281 case 'd': { 282 double d; 283 memcpy(&d, data+pos, size); 284 correctbytes((char *)&d, sizeof(d), h.endian); 285 lua_pushnumber(L, d); 286 break; 287 } 288 case 'c': { 289 if (size == 0) { 290 if (!lua_isnumber(L, -1)) 291 luaL_error(L, "format `c0' needs a previous size"); 292 size = lua_tonumber(L, -1); 293 lua_pop(L, 1); 294 luaL_argcheck(L, pos+size <= ld, 2, "data string too short"); 295 } 296 lua_pushlstring(L, data+pos, size); 297 break; 298 } 299 case 's': { 300 const char *e = (const char *)memchr(data+pos, '\0', ld - pos); 301 if (e == NULL) 302 luaL_error(L, "unfinished string in data"); 303 size = (e - (data+pos)) + 1; 304 lua_pushlstring(L, data+pos, size - 1); 305 break; 306 } 307 default: commoncases(L, opt, &fmt, &h); 308 } 309 pos += size; 310 } 311 lua_pushinteger(L, pos + 1); 312 return lua_gettop(L) - 2; 313 } 314 315 /* }====================================================== */ 316 317 318 319 static const struct luaL_reg thislib[] = { 320 {"pack", b_pack}, 321 {"unpack", b_unpack}, 322 {NULL, NULL} 323 }; 324 325 326 LUALIB_API int luaopen_struct (lua_State *L) { 327 luaL_register(L, "struct", thislib); 328 return 1; 329 } 330 331 332 333 /****************************************************************************** 334 * Copyright (C) 2010 Lua.org, PUC-Rio. All rights reserved. 335 * 336 * Permission is hereby granted, free of charge, to any person obtaining 337 * a copy of this software and associated documentation files (the 338 * "Software"), to deal in the Software without restriction, including 339 * without limitation the rights to use, copy, modify, merge, publish, 340 * distribute, sublicense, and/or sell copies of the Software, and to 341 * permit persons to whom the Software is furnished to do so, subject to 342 * the following conditions: 343 * 344 * The above copyright notice and this permission notice shall be 345 * included in all copies or substantial portions of the Software. 346 * 347 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 348 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 349 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 350 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 351 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 352 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 353 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 354 ******************************************************************************/ 355