From Masashi Honma:
[obnox/wireshark/wip.git] / epan / wslua / wslua_field.c
1 /*
2  *  wslua_field.c
3  *
4  * Wireshark's interface to the Lua Programming Language
5  *
6  * (c) 2006, Luis E. Garcia Ontanon <luis@ontanon.org>
7  *
8  * $Id$
9  *
10  * Wireshark - Network traffic analyzer
11  * By Gerald Combs <gerald@wireshark.org>
12  * Copyright 1998 Gerald Combs
13  *
14  * This program is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU General Public License
16  * as published by the Free Software Foundation; either version 2
17  * of the License, or (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, write to the Free Software
26  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
27  */
28
29 /* WSLUA_MODULE Field Obtaining dissection data */
30
31 #include "wslua.h"
32
33 WSLUA_CLASS_DEFINE(FieldInfo,NOP,NOP);
34 /*
35  An extracted Field
36  */
37
38 WSLUA_METAMETHOD FieldInfo__len(lua_State* L) {
39         /*
40          Obtain the Length of the field
41          */
42         FieldInfo fi = checkFieldInfo(L,1);
43         lua_pushnumber(L,fi->length);
44         return 1;
45 }
46
47 WSLUA_METAMETHOD FieldInfo__unm(lua_State* L) {
48         /*
49          Obtain the Offset of the field
50          */
51         FieldInfo fi = checkFieldInfo(L,1);
52         lua_pushnumber(L,fi->start);
53         return 1;
54 }
55
56 WSLUA_METAMETHOD FieldInfo__call(lua_State* L) {
57         /*
58          Obtain the Value of the field
59          */
60         FieldInfo fi = checkFieldInfo(L,1);
61
62         switch(fi->hfinfo->type) {
63                 case FT_NONE:
64                         lua_pushnil(L);
65                         return 1;
66                 case FT_BOOLEAN:
67                         lua_pushboolean(L,(int)fvalue_get_uinteger(&(fi->value)));
68                         return 1;
69                 case FT_UINT8:
70                 case FT_UINT16:
71                 case FT_UINT24:
72                 case FT_UINT32:
73                 case FT_FRAMENUM:
74                         lua_pushnumber(L,(lua_Number)fvalue_get_uinteger(&(fi->value)));
75                         return 1;
76                 case FT_INT8:
77                 case FT_INT16:
78                 case FT_INT24:
79                 case FT_INT32:
80                         lua_pushnumber(L,(lua_Number)fvalue_get_sinteger(&(fi->value)));
81                         return 1;
82                 case FT_FLOAT:
83                 case FT_DOUBLE:
84                         lua_pushnumber(L,(lua_Number)fvalue_get_floating(&(fi->value)));
85                         return 1;
86                 case FT_INT64: {
87                         Int64 num = g_malloc(sizeof(gint64));
88                         *num = fvalue_get_integer64(&(fi->value));
89                         pushInt64(L,num);
90                         return 1;
91                 }
92                 case FT_UINT64: {
93                         UInt64 num = g_malloc(sizeof(guint64));
94                         *num = fvalue_get_integer64(&(fi->value));
95                         pushUInt64(L,num);
96                         return 1;
97                 }
98                 case FT_ETHER: {
99                         Address eth = g_malloc(sizeof(address));
100                         eth->type = AT_ETHER;
101                         eth->len = fi->length;
102                         eth->data = tvb_memdup(fi->ds_tvb,fi->start,fi->length);
103                         pushAddress(L,eth);
104                         return 1;
105                 }
106                 case FT_IPv4:{
107                         Address ipv4 = g_malloc(sizeof(address));
108                         ipv4->type = AT_IPv4;
109                         ipv4->len = fi->length;
110                         ipv4->data = tvb_memdup(fi->ds_tvb,fi->start,fi->length);
111                         pushAddress(L,ipv4);
112                         return 1;
113                 }
114                 case FT_IPv6: {
115                         Address ipv6 = g_malloc(sizeof(address));
116                         ipv6->type = AT_IPv6;
117                         ipv6->len = fi->length;
118                         ipv6->data = tvb_memdup(fi->ds_tvb,fi->start,fi->length);
119                         pushAddress(L,ipv6);
120                         return 1;
121                 }
122                 case FT_IPXNET:{
123                         Address ipx = g_malloc(sizeof(address));
124                         ipx->type = AT_IPX;
125                         ipx->len = fi->length;
126                         ipx->data = tvb_memdup(fi->ds_tvb,fi->start,fi->length);
127                         pushAddress(L,ipx);
128                         return 1;
129                 }
130                 case FT_STRING:
131                 case FT_STRINGZ: {
132                         gchar* repr = fvalue_to_string_repr(&fi->value,FTREPR_DISPLAY,NULL);
133                         if (repr)
134                                 lua_pushstring(L,repr);
135                         else
136                                 luaL_error(L,"field cannot be represented as string because it may contain invalid characters");
137
138                         return 1;
139                 }
140                 case FT_BYTES:
141                 case FT_UINT_BYTES:
142                 case FT_GUID:
143                 case FT_PROTOCOL:
144                 case FT_OID: {
145                         ByteArray ba = g_byte_array_new();
146                         g_byte_array_append(ba, ep_tvb_memdup(fi->ds_tvb,fi->start,fi->length),fi->length);
147                         pushByteArray(L,ba);
148                         return 1;
149                 }
150                 default:
151                         luaL_error(L,"FT_ not yet supported");
152                         return 1;
153         }
154 }
155
156 WSLUA_METAMETHOD FieldInfo__tostring(lua_State* L) {
157         /* The string representation of the field */
158         FieldInfo fi = checkFieldInfo(L,1);
159         if (fi) {
160                 if (fi->value.ftype->val_to_string_repr) {
161                         gchar* repr = fvalue_to_string_repr(&fi->value,FTREPR_DISPLAY,NULL);
162                         if (repr)
163                                 lua_pushstring(L,repr);
164                         else
165                                 luaL_error(L,"field cannot be represented as string because it may contain invalid characters");
166                 } else
167                         luaL_error(L,"field has no string representation");
168         }
169         return 1;
170 }
171
172 static int FieldInfo_get_range(lua_State* L) {
173         /* The TvbRange covering this field */
174         FieldInfo fi = checkFieldInfo(L,1);
175         TvbRange r = ep_alloc(sizeof(struct _wslua_tvbrange));
176         r->tvb = ep_alloc(sizeof(struct _wslua_tvb));
177
178         r->tvb->ws_tvb = fi->ds_tvb;
179         r->offset = fi->start;
180         r->len = fi->length;
181
182         pushTvbRange(L,r);
183         return 1;
184 }
185
186 static int FieldInfo_get_generated(lua_State* L) {
187         /* Whether this field was marked as generated. */
188         FieldInfo fi = checkFieldInfo(L,1);
189         lua_pushboolean(L,FI_GET_FLAG(fi, FI_GENERATED));
190         return 1;
191 }
192
193 static int FieldInfo_get_name(lua_State* L) {
194         /* The filter name of this field. */
195         FieldInfo fi = checkFieldInfo(L,1);
196         lua_pushstring(L,fi->hfinfo->abbrev);
197         return 1;
198 }
199
200 static const luaL_reg FieldInfo_get[] = {
201 /*    {"data_source", FieldInfo_get_data_source }, */
202     {"range", FieldInfo_get_range},
203 /*    {"hidden", FieldInfo_get_hidden}, */
204     {"generated", FieldInfo_get_generated},
205
206         /* WSLUA_ATTRIBUTE FieldInfo_name RO The name of this field */
207     {"name", FieldInfo_get_name},
208         /* WSLUA_ATTRIBUTE FieldInfo_label RO The string representing this field */
209     {"label", FieldInfo__tostring},
210         /* WSLUA_ATTRIBUTE FieldInfo_value RO The value of this field */
211     {"value", FieldInfo__call},
212         /* WSLUA_ATTRIBUTE FieldInfo_len RO The length of this field */
213     {"len", FieldInfo__len},
214         /* WSLUA_ATTRIBUTE FieldInfo_offset RO The offset of this field */
215     {"offset", FieldInfo__unm},
216     { NULL, NULL }
217 };
218
219 static int FieldInfo__index(lua_State* L) {
220         /*
221          Other attributes:
222          */
223         const gchar* idx = luaL_checkstring(L,2);
224         const luaL_reg* r;
225
226         checkFieldInfo(L,1);
227
228         for (r = FieldInfo_get; r->name; r++) {
229                 if (g_str_equal(r->name, idx)) {
230                         return r->func(L);
231                 }
232         }
233
234         return 0;
235 }
236
237 WSLUA_METAMETHOD FieldInfo__eq(lua_State* L) {
238         /* Checks whether lhs is within rhs */
239         FieldInfo l = checkFieldInfo(L,1);
240         FieldInfo r = checkFieldInfo(L,2);
241
242         if (l->ds_tvb != r->ds_tvb)
243                 WSLUA_ERROR(FieldInfo__eq,"Data source must be the same for both fields");
244
245         if (l->start <= r->start && r->start + r->length <= l->start + r->length) {
246                 lua_pushboolean(L,1);
247                 return 1;
248         } else {
249                 return 0;
250         }
251 }
252
253 WSLUA_METAMETHOD FieldInfo__le(lua_State* L) {
254         /* Checks whether the end byte of lhs is before the end of rhs */
255         FieldInfo l = checkFieldInfo(L,1);
256         FieldInfo r = checkFieldInfo(L,2);
257
258         if (l->ds_tvb != r->ds_tvb)
259                 return 0;
260
261         if (r->start + r->length <= l->start + r->length) {
262                 lua_pushboolean(L,1);
263                 return 1;
264         } else {
265                 return 0;
266         }
267 }
268
269 WSLUA_METAMETHOD FieldInfo__lt(lua_State* L) {
270         /* Checks whether the end byte of rhs is before the beginning of rhs */
271         FieldInfo l = checkFieldInfo(L,1);
272         FieldInfo r = checkFieldInfo(L,2);
273
274         if (l->ds_tvb != r->ds_tvb)
275                 WSLUA_ERROR(FieldInfo__eq,"Data source must be the same for both fields");
276
277         if ( r->start + r->length < l->start ) {
278                 lua_pushboolean(L,1);
279                 return 1;
280         } else {
281                 return 0;
282         }
283 }
284
285
286 static const luaL_reg FieldInfo_meta[] = {
287     {"__tostring", FieldInfo__tostring},
288     {"__call", FieldInfo__call},
289     {"__index", FieldInfo__index},
290     {"__len", FieldInfo__len},
291     {"__unm", FieldInfo__unm},
292     {"__eq", FieldInfo__eq},
293     {"__le", FieldInfo__le},
294     {"__lt", FieldInfo__lt},
295     { NULL, NULL }
296 };
297
298 int FieldInfo_register(lua_State* L) {
299     WSLUA_REGISTER_META(FieldInfo);
300     return 1;
301 }
302
303
304 WSLUA_FUNCTION wslua_all_field_infos(lua_State* L) {
305         /* Obtain all fields from the current tree */
306         GPtrArray* found;
307         int items_found = 0;
308         guint i;
309
310         if (! lua_tree || ! lua_tree->tree ) {
311                 WSLUA_ERROR(wslua_all_field_infos,"Cannot be called outside a listener or dissector");
312         }
313
314         found = proto_all_finfos(lua_tree->tree);
315
316         if (found) {
317                 for (i=0; i<found->len; i++) {
318                         pushFieldInfo(L,g_ptr_array_index(found,i));
319                         items_found++;
320                 }
321
322                 g_ptr_array_free(found,TRUE);
323         }
324
325         return items_found;
326 }
327
328 WSLUA_CLASS_DEFINE(Field,NOP,NOP);
329 /*
330  A Field extractor to to obtain field values.
331  */
332
333 static GPtrArray* wanted_fields = NULL;
334
335 /*
336  * field extractor registartion is tricky, In order to allow
337  * the user to define them in the body of the script we will
338  * populate the Field value with a pointer of the abbrev of it
339  * to later replace it with the hfi.
340  *
341  * This will be added to the wanted_fields array that will
342  * exists only while they can be defined, and be cleared right
343  * after the fields are primed.
344  */
345
346 void lua_prime_all_fields(proto_tree* tree _U_) {
347     GString* fake_tap_filter = g_string_new("frame");
348     guint i;
349     static gboolean fake_tap = FALSE;
350
351     for(i=0; i < wanted_fields->len; i++) {
352         Field f = g_ptr_array_index(wanted_fields,i);
353         gchar* name = *((gchar**)f);
354
355         *f = proto_registrar_get_byname(name);
356
357         if (!*f) {
358             report_failure("Could not find field `%s'",name);
359             *f = NULL;
360             g_free(name);
361             continue;
362         }
363
364         g_free(name);
365
366         g_string_append_printf(fake_tap_filter," || %s",(*f)->abbrev);
367         fake_tap = TRUE;
368     }
369
370     g_ptr_array_free(wanted_fields,TRUE);
371     wanted_fields = NULL;
372
373     if (fake_tap) {
374         /* a boring tap :-) */
375         GString* error = register_tap_listener("frame",
376                                                &fake_tap,
377                                                fake_tap_filter->str,
378                                                0, /* XXX - do we need the protocol tree or columns? */
379                                                NULL, NULL, NULL);
380
381         if (error) {
382             report_failure("while registering lua_fake_tap:\n%s",error->str);
383             g_string_free(error,TRUE);
384         }
385     }
386
387 }
388
389 WSLUA_CONSTRUCTOR Field_new(lua_State *L) {
390         /*
391          Create a Field extractor
392          */
393 #define WSLUA_ARG_Field_new_FIELDNAME 1 /* The filter name of the field (e.g. ip.addr) */
394     const gchar* name = luaL_checkstring(L,WSLUA_ARG_Field_new_FIELDNAME);
395     Field f;
396
397     if (!name) return 0;
398
399         if (!proto_registrar_get_byname(name))
400                 WSLUA_ARG_ERROR(Field_new,FIELDNAME,"a field with this name must exist");
401
402     if (!wanted_fields)
403                 WSLUA_ERROR(Field_get,"A Field extractor must be defined before Taps or Dissectors get called");
404
405     f = g_malloc(sizeof(void*));
406     *f = (header_field_info*)g_strdup(name); /* cheating */
407
408     g_ptr_array_add(wanted_fields,f);
409
410     pushField(L,f);
411     WSLUA_RETURN(1); /* The field extractor */
412 }
413
414 WSLUA_METAMETHOD Field__call (lua_State* L) {
415         /* Obtain all values (see FieldInfo) for this field. */
416     Field f = checkField(L,1);
417     header_field_info* in = *f;
418         int items_found = 0;
419
420     if (! in) {
421         luaL_error(L,"invalid field");
422         return 0;
423     }
424
425     if (! lua_pinfo ) {
426         WSLUA_ERROR(Field__call,"Fields cannot be used outside dissectors or taps");
427         return 0;
428     }
429
430     for (;in;in = in->same_name_next) {
431         GPtrArray* found = proto_get_finfo_ptr_array(lua_tree->tree, in->id);
432         guint i;
433         if (found) {
434             for (i=0; i<found->len; i++) {
435                                 pushFieldInfo(L,g_ptr_array_index(found,i));
436                                 items_found++;
437                         }
438         }
439     }
440
441     WSLUA_RETURN(items_found); /* All the values of this field */
442 }
443
444 WSLUA_METAMETHOD Field_tostring(lua_State* L) {
445         /* Obtain a srting with the field name */
446     Field f = checkField(L,1);
447
448     if ( !(f && *f) ) {
449         luaL_error(L,"invalid Field");
450         return 0;
451     }
452
453     if (wanted_fields) {
454         lua_pushstring(L,*((gchar**)f));
455     } else {
456         lua_pushstring(L,(*f)->abbrev);
457     }
458
459     return 1;
460 }
461
462 static const luaL_reg Field_methods[] = {
463     {"new", Field_new},
464     { NULL, NULL }
465 };
466
467 static const luaL_reg Field_meta[] = {
468     {"__tostring", Field_tostring},
469     {"__call", Field__call},
470     { NULL, NULL }
471 };
472
473 int Field_register(lua_State* L) {
474
475     wanted_fields = g_ptr_array_new();
476
477     WSLUA_REGISTER_CLASS(Field);
478
479     return 1;
480 }
481
482