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-
121/*
132** {======================================================
143** Library for packing/unpacking structures.
15- ** $Id: struct.c,v 1.2 2008/04/18 20:06:01 roberto Exp $
4+ ** $Id: struct.c,v 1.4 2012/07/04 18:54:29 roberto Exp $
165** See Copyright Notice at the end of this file
176** =======================================================
187*/
2514** b/B - signed/unsigned byte
2615** h/H - signed/unsigned short
2716** l/L - signed/unsigned long
17+ ** T - size_t
2818** i/In - signed/unsigned integer with size `n' (default is size of int)
2919** cn - sequence of `n' chars (from/to a string); when packing, n==0 means
3020 the whole string; when unpacking, n==0 means use the previous
3626*/
3727
3828
29+ #include <assert.h>
30+ #include <ctype.h>
31+ #include <limits.h>
32+ #include <stddef.h>
33+ #include <string.h>
34+
35+
36+ #include "lua.h"
37+ #include "lauxlib.h"
38+
39+
40+ #if (LUA_VERSION_NUM >= 502 )
41+
42+ #define luaL_register (L ,n ,f ) luaL_newlib(L,f)
43+
44+ #endif
45+
46+
47+ /* basic integer type */
48+ #if !defined(STRUCT_INT )
49+ #define STRUCT_INT long
50+ #endif
51+
52+ typedef STRUCT_INT Inttype ;
53+
54+ /* corresponding unsigned version */
55+ typedef unsigned STRUCT_INT Uinttype ;
56+
57+
58+ /* maximum size (in bytes) for integral types */
59+ #define MAXINTSIZE 32
60+
3961/* is 'x' a power of 2? */
4062#define isp2 (x ) ((x) > 0 && ((x) & ((x) - 1)) == 0)
4163
@@ -67,11 +89,11 @@ typedef struct Header {
6789} Header ;
6890
6991
70- static size_t getnum (const char * * fmt , size_t df ) {
92+ static int getnum (const char * * fmt , int df ) {
7193 if (!isdigit (* * fmt )) /* no number? */
7294 return df ; /* return default value */
7395 else {
74- size_t a = 0 ;
96+ int a = 0 ;
7597 do {
7698 a = a * 10 + * ((* fmt )++ ) - '0' ;
7799 } while (isdigit (* * fmt ));
@@ -89,33 +111,40 @@ static size_t optsize (lua_State *L, char opt, const char **fmt) {
89111 case 'B' : case 'b' : return sizeof (char );
90112 case 'H' : case 'h' : return sizeof (short );
91113 case 'L' : case 'l' : return sizeof (long );
114+ case 'T' : return sizeof (size_t );
92115 case 'f' : return sizeof (float );
93116 case 'd' : return sizeof (double );
94117 case 'x' : return 1 ;
95118 case 'c' : return getnum (fmt , 1 );
96- case 's' : case ' ' : case '<' : case '>' : case '!' : return 0 ;
97119 case 'i' : case 'I' : {
98120 int sz = getnum (fmt , sizeof (int ));
99- if (!isp2 (sz ))
100- luaL_error (L , "integral size %d is not a power of 2" , sz );
121+ if (sz > MAXINTSIZE )
122+ luaL_error (L , "integral size %d is larger than limit of %d" ,
123+ sz , MAXINTSIZE );
101124 return sz ;
102125 }
103- default : {
104- const char * msg = lua_pushfstring (L , "invalid format option [%c]" , opt );
105- return luaL_argerror (L , 1 , msg );
106- }
126+ default : return 0 ; /* other cases do not need alignment */
107127 }
108128}
109129
110130
131+ /*
132+ ** return number of bytes needed to align an element of size 'size'
133+ ** at current position 'len'
134+ */
111135static int gettoalign (size_t len , Header * h , int opt , size_t size ) {
112136 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 );
137+ if (size > (size_t )h -> align )
138+ size = h -> align ; /* respect max. alignment */
139+ return (size - (len & (size - 1 ))) & (size - 1 );
115140}
116141
117142
118- static void commoncases (lua_State * L , int opt , const char * * fmt , Header * h ) {
143+ /*
144+ ** options to control endianess and alignment
145+ */
146+ static void controloptions (lua_State * L , int opt , const char * * fmt ,
147+ Header * h ) {
119148 switch (opt ) {
120149 case ' ' : return ; /* ignore white spaces */
121150 case '>' : h -> endian = BIG ; return ;
@@ -127,29 +156,38 @@ static void commoncases (lua_State *L, int opt, const char **fmt, Header *h) {
127156 h -> align = a ;
128157 return ;
129158 }
130- default : assert (0 );
159+ default : {
160+ const char * msg = lua_pushfstring (L , "invalid format option '%c'" , opt );
161+ luaL_argerror (L , 1 , msg );
162+ }
131163 }
132164}
133165
134166
135167static void putinteger (lua_State * L , luaL_Buffer * b , int arg , int endian ,
136168 int size ) {
137169 lua_Number n = luaL_checknumber (L , arg );
138- unsigned long value ;
139- if (n < (lua_Number )LONG_MAX )
140- value = (long )n ;
170+ Uinttype value ;
171+ char buff [MAXINTSIZE ];
172+ if (n < 0 )
173+ value = (Uinttype )(Inttype )n ;
141174 else
142- value = (unsigned long )n ;
175+ value = (Uinttype )n ;
143176 if (endian == LITTLE ) {
144177 int i ;
145- for (i = 0 ; i < size ; i ++ )
146- luaL_addchar (b , (value >> 8 * i ) & 0xff );
178+ for (i = 0 ; i < size ; i ++ ) {
179+ buff [i ] = (value & 0xff );
180+ value >>= 8 ;
181+ }
147182 }
148183 else {
149184 int i ;
150- for (i = size - 1 ; i >= 0 ; i -- )
151- luaL_addchar (b , (value >> 8 * i ) & 0xff );
185+ for (i = size - 1 ; i >= 0 ; i -- ) {
186+ buff [i ] = (value & 0xff );
187+ value >>= 8 ;
188+ }
152189 }
190+ luaL_addlstring (b , buff , size );
153191}
154192
155193
@@ -179,15 +217,15 @@ static int b_pack (lua_State *L) {
179217 size_t size = optsize (L , opt , & fmt );
180218 int toalign = gettoalign (totalsize , & h , opt , size );
181219 totalsize += toalign ;
182- while (toalign -- > 0 ) luaL_putchar (& b , '\0' );
220+ while (toalign -- > 0 ) luaL_addchar (& b , '\0' );
183221 switch (opt ) {
184222 case 'b' : case 'B' : case 'h' : case 'H' :
185- case 'l' : case 'L' : case 'i' : case 'I' : { /* integer types */
223+ case 'l' : case 'L' : case 'T' : case ' i' : case 'I' : { /* integer types */
186224 putinteger (L , & b , arg ++ , h .endian , size );
187225 break ;
188226 }
189227 case 'x' : {
190- luaL_putchar (& b , '\0' );
228+ luaL_addchar (& b , '\0' );
191229 break ;
192230 }
193231 case 'f' : {
@@ -209,12 +247,12 @@ static int b_pack (lua_State *L) {
209247 luaL_argcheck (L , l >= (size_t )size , arg , "string too short" );
210248 luaL_addlstring (& b , s , size );
211249 if (opt == 's' ) {
212- luaL_putchar (& b , '\0' ); /* add zero at the end */
250+ luaL_addchar (& b , '\0' ); /* add zero at the end */
213251 size ++ ;
214252 }
215253 break ;
216254 }
217- default : commoncases (L , opt , & fmt , & h );
255+ default : controloptions (L , opt , & fmt , & h );
218256 }
219257 totalsize += size ;
220258 }
@@ -225,24 +263,27 @@ static int b_pack (lua_State *L) {
225263
226264static lua_Number getinteger (const char * buff , int endian ,
227265 int issigned , int size ) {
228- unsigned long l = 0 ;
266+ Uinttype l = 0 ;
267+ int i ;
229268 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 );
269+ for (i = 0 ; i < size ; i ++ ) {
270+ l <<= 8 ;
271+ l |= (Uinttype )(unsigned char )buff [i ];
272+ }
233273 }
234274 else {
235- int i ;
236- for (i = 0 ; i < size ; i ++ )
237- l |= (unsigned long )(unsigned char )buff [i ] << (i * 8 );
275+ for (i = size - 1 ; i >= 0 ; i -- ) {
276+ l <<= 8 ;
277+ l |= (Uinttype )(unsigned char )buff [i ];
278+ }
238279 }
239280 if (!issigned )
240281 return (lua_Number )l ;
241282 else { /* signed format */
242- unsigned long mask = ~( 0UL ) << (size * 8 - 1 );
283+ Uinttype mask = ( Uinttype )(~(( Uinttype ) 0 ) ) << (size * 8 - 1 );
243284 if (l & mask ) /* negative value? */
244285 l |= mask ; /* signal extension */
245- return (lua_Number )(long )l ;
286+ return (lua_Number )(Inttype )l ;
246287 }
247288}
248289
@@ -260,9 +301,10 @@ static int b_unpack (lua_State *L) {
260301 size_t size = optsize (L , opt , & fmt );
261302 pos += gettoalign (pos , & h , opt , size );
262303 luaL_argcheck (L , pos + size <= ld , 2 , "data string too short" );
304+ luaL_checkstack (L , 1 , "too many results" );
263305 switch (opt ) {
264306 case 'b' : case 'B' : case 'h' : case 'H' :
265- case 'l' : case 'L' : case 'i' : case 'I' : { /* integer types */
307+ case 'l' : case 'L' : case 'T' : case ' i' : case 'I' : { /* integer types */
266308 int issigned = islower (opt );
267309 lua_Number res = getinteger (data + pos , h .endian , issigned , size );
268310 lua_pushnumber (L , res );
@@ -304,34 +346,58 @@ static int b_unpack (lua_State *L) {
304346 lua_pushlstring (L , data + pos , size - 1 );
305347 break ;
306348 }
307- default : commoncases (L , opt , & fmt , & h );
349+ default : controloptions (L , opt , & fmt , & h );
308350 }
309351 pos += size ;
310352 }
311353 lua_pushinteger (L , pos + 1 );
312354 return lua_gettop (L ) - 2 ;
313355}
314356
357+
358+ static int b_size (lua_State * L ) {
359+ Header h ;
360+ const char * fmt = luaL_checkstring (L , 1 );
361+ size_t pos = 0 ;
362+ defaultoptions (& h );
363+ while (* fmt ) {
364+ int opt = * fmt ++ ;
365+ size_t size = optsize (L , opt , & fmt );
366+ pos += gettoalign (pos , & h , opt , size );
367+ if (opt == 's' )
368+ luaL_argerror (L , 1 , "option 's' has no fixed size" );
369+ else if (opt == 'c' && size == 0 )
370+ luaL_argerror (L , 1 , "option 'c0' has no fixed size" );
371+ if (!isalnum (opt ))
372+ controloptions (L , opt , & fmt , & h );
373+ pos += size ;
374+ }
375+ lua_pushinteger (L , pos );
376+ return 1 ;
377+ }
378+
315379/* }====================================================== */
316380
317381
318382
319- static const struct luaL_reg thislib [] = {
383+ static const struct luaL_Reg thislib [] = {
320384 {"pack" , b_pack },
321385 {"unpack" , b_unpack },
386+ {"size" , b_size },
322387 {NULL , NULL }
323388};
324389
325390
391+ LUALIB_API int luaopen_struct (lua_State * L );
392+
326393LUALIB_API int luaopen_struct (lua_State * L ) {
327394 luaL_register (L , "struct" , thislib );
328395 return 1 ;
329396}
330397
331398
332-
333399/******************************************************************************
334- * Copyright (C) 2010 Lua.org, PUC-Rio. All rights reserved.
400+ * Copyright (C) 2010-2012 Lua.org, PUC-Rio. All rights reserved.
335401*
336402* Permission is hereby granted, free of charge, to any person obtaining
337403* a copy of this software and associated documentation files (the
@@ -352,3 +418,4 @@ LUALIB_API int luaopen_struct (lua_State *L) {
352418* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
353419* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
354420******************************************************************************/
421+
0 commit comments