diff options
author | Guy Harris <guy@alum.mit.edu> | 2000-06-12 02:30:35 +0000 |
---|---|---|
committer | Guy Harris <guy@alum.mit.edu> | 2000-06-12 02:30:35 +0000 |
commit | 515f6811c0cbb82b9d56b4d2d1a9d90e784d6f7b (patch) | |
tree | 299e715456b6caad88700a3a0195e4e3beaac78e /packet-x11.c | |
parent | 1d97f13307d4e026fa78e30d45cacb53194d1971 (diff) |
Christophe Tronche's X11 dissector.
svn path=/trunk/; revision=2057
Diffstat (limited to 'packet-x11.c')
-rw-r--r-- | packet-x11.c | 2951 |
1 files changed, 2951 insertions, 0 deletions
diff --git a/packet-x11.c b/packet-x11.c new file mode 100644 index 0000000000..c9e60a81df --- /dev/null +++ b/packet-x11.c @@ -0,0 +1,2951 @@ +/* packet-x11.c + * Routines for X11 dissection + * Copyright 2000, Christophe Tronche <ch.tronche@computer.org> + * + * $Id: packet-x11.c,v 1.1 2000/06/12 02:30:35 guy Exp $ + * + * Ethereal - Network traffic analyzer + * By Gerald Combs <gerald@unicom.net> + * Copyright 1998 Gerald Combs + * + * Copied from README.developer + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* TODO (in no particular order): + * + * - keep track of Atom creation by server to be able to display non predefined atoms + * - Idem for keysym <-> keycode ??? + * - Idem for fonts + * - Subtree the request ids (that is x11.create-window.window and x11.change-window.window should be + * distinct), and add hidden fields (so we still have x11.window). + * - add hidden fields so we can have x11.circulate-window in addition to x11.opcode == 13 + * - add hidden fields so we have x11.listOfStuff.length + * - use a faster scheme that linear list searching for the opcode. + * - correct display of unicode chars. + * - Not everything is homogeneous, in particular the handling of items in list is a total mess. + */ + +/* By the way, I wrote a program to generate every request and test + * that stuff. If you're interested, you can get it at + * http://tronche.com/gui/x/ + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <X11/Xlib.h> +#include <assert.h> +#include <ctype.h> +#include <gdk/gdk.h> +#include <gdk/gdkx.h> +#include <stdio.h> +#include <stdlib.h> + +#ifdef HAVE_SYS_TYPES_H +# include <sys/types.h> +#endif + +#ifdef HAVE_NETINET_IN_H +# include <netinet/in.h> +#endif + +#ifdef NEED_SNPRINTF_H +# ifdef HAVE_STDARG_H +# include <stdarg.h> +# else +# include <varargs.h> +# endif +# include "snprintf.h" +#endif + +#include <string.h> +#include <glib.h> +#include "packet.h" + +#define cVALS(x) (const value_string*)(x) + +/* Initialize the protocol and registered fields */ +static int proto_x11 = -1; + +#include "packet-x11-declarations.h" + +/* Initialize the subtree pointers */ +static gint ett_x11 = -1; +static gint ett_x11_request = -1; + +#define TCP_PORT_X11 6000 +#define TCP_PORT_X11_2 6001 +#define TCP_PORT_X11_3 6002 + +/************************************************************************ + *** *** + *** E N U M T A B L E S D E F I N I T I O N S *** + *** *** + ************************************************************************/ + +static const value_string access_mode_vals[] = { + { 0, "Disable" }, + { 1, "Enable" }, + { 0, NULL } +}; + +static const value_string all_temporary_vals[] = { + { 0, "AllTemporary" }, + { 0, NULL } +}; + +static const value_string alloc_vals[] = { + { 0, "None" }, + { 1, "All" }, + { 0, NULL } +}; + +static const value_string allow_events_mode_vals[] = { + { 0, "AsyncPointer" }, + { 1, "SyncPointer" }, + { 2, "ReplayPointer" }, + { 3, "AsyncKeyboard" }, + { 4, "SyncKeyboard" }, + { 5, "ReplayKeyboard" }, + { 6, "AsyncBoth" }, + { 7, "SyncBoth" }, + { 0, NULL } +}; + +static const value_string arc_mode_vals[] = { + { 0, "Chord" }, + { 1, "PieSlice" }, + { 0, NULL } +}; + +static const char *atom_predefined_interpretation[] = { + "<error>", + "PRIMARY", + "SECONDARY", + "ARC", + "ATOM", + "BITMAP", + "CARDINAL", + "COLORMAP", + "CURSOR", + "CUT_BUFFER0", + "CUT_BUFFER1", + "CUT_BUFFER2", + "CUT_BUFFER3", + "CUT_BUFFER4", + "CUT_BUFFER5", + "CUT_BUFFER6", + "CUT_BUFFER7", + "DRAWABLE", + "FONT", + "INTEGER", + "PIXMAP", + "POINT", + "RECTANGLE", + "RESOURCE_MANAGER", + "RGB_COLOR_MAP", + "RGB_BEST_MAP", + "RGB_BLUE_MAP", + "RGB_DEFAULT_MAP", + "RGB_GRAY_MAP", + "RGB_GREEN_MAP", + "RGB_RED_MAP", + "STRING", + "VISUALID", + "WINDOW", + "WM_COMMAND", + "WM_HINTS", + "WM_CLIENT_MACHINE", + "WM_ICON_NAME", + "WM_ICON_SIZE", + "WM_NAME", + "WM_NORMAL_HINTS", + "WM_SIZE_HINTS", + "WM_ZOOM_HINTS", + "MIN_SPACE", + "NORM_SPACE", + "MAX_SPACE", + "END_SPACE", + "SUPERSCRIPT_X", + "SUPERSCRIPT_Y", + "SUBSCRIPT_X", + "SUBSCRIPT_Y", + "UNDERLINE_POSITION", + "UNDERLINE_THICKNESS", + "STRIKEOUT_ASCENT", + "STRIKEOUT_DESCENT", + "ITALIC_ANGLE", + "X_HEIGHT", + "QUAD_WIDTH", + "WEIGHT", + "POINT_SIZE", + "RESOLUTION", + "COPYRIGHT", + "NOTICE", + "FONT_NAME", + "FAMILY_NAME", + "FULL_NAME", + "CAP_HEIGHT", + "WM_CLASS", + "WM_TRANSIENT_FOR", +}; + +static const value_string auto_repeat_mode_vals[] = { + { 0, "Off" }, + { 1, "On" }, + { 2, "Default" }, + { 0, NULL } +}; + +static const value_string background_pixmap_vals[] = { + { 0, "None" }, + { 1, "ParentRelative" }, + { 0, NULL } +}; + +static const value_string backing_store_vals[] = { + { 0, "NotUseful" }, + { 1, "WhenMapped" }, + { 2, "Always" }, + { 0, NULL } +}; + +static const value_string border_pixmap_vals[] = { + { 0, "CopyFromParent" }, + { 0, NULL } +}; + +static const value_string button_vals[] = { + { 0x8000, "AnyButton" }, + { 0, NULL } +}; + +static const value_string cap_style_vals[] = { + { 0, "NotLast" }, + { 1, "Butt" }, + { 2, "Round" }, + { 3, "Projecting" }, + { 0, NULL } +}; + +static const value_string class_vals[] = { + { 0, "Cursor" }, + { 1, "Tile" }, + { 2, "Stipple" }, + { 0, NULL } +}; + +static const value_string close_down_mode_vals[] = { + { 0, "Destroy" }, + { 1, "RetainPermanent" }, + { 2, "RetainTemporary" }, + { 0, NULL } +}; + +static const value_string coordinate_mode_vals[] = { + { 0, "Origin" }, + { 1, "Previous" }, + { 0, NULL } +}; + +static const value_string direction_vals[] = { + { 0, "RaiseLowest" }, + { 1, "LowerHighest" }, + { 0, NULL } +}; + +static const value_string family_vals[] = { + { 0, "Internet" }, + { 1, "DECnet" }, + { 2, "Chaos" }, + { 0, NULL } +}; + +static const value_string fill_rule_vals[] = { + { 0, "EvenOdd" }, + { 1, "Winding" }, + { 0, NULL } +}; + +static const value_string fill_style_vals[] = { + { 0, "Solid" }, + { 1, "Tiled" }, + { 2, "Stippled" }, + { 3, "OpaqueStippled" }, + { 0, NULL } +}; + +static const value_string focus_vals[] = { + { 0, "None" }, + { 1, "PointerRoot" }, + { 0, NULL } +}; + +static const value_string function_vals[] = { + { 0, "Clear" }, + { 1, "And" }, + { 2, "AndReverse" }, + { 3, "Copy" }, + { 4, "AndInverted" }, + { 5, "NoOp" }, + { 6, "Xor" }, + { 7, "Or" }, + { 8, "Nor" }, + { 9, "Equiv" }, + { 10, "Invert" }, + { 11, "OrReverse" }, + { 12, "CopyInverted" }, + { 13, "OrInverted" }, + { 14, "Nand" }, + { 15, "Set" }, + { 0, NULL } +}; + +static const value_string gravity_vals[] = { + { 1, "NorthWest" }, + { 2, "North" }, + { 3, "NorthEast" }, + { 4, "West" }, + { 5, "Center" }, + { 6, "East" }, + { 7, "SouthWest" }, + { 8, "South" }, + { 9, "SouthEast" }, + { 10, "Static" }, + { 0, NULL } +}; + +static const value_string image_format_vals[] = { + { 0, "Bitmap" }, + { 1, "XYPixmap" }, + { 2, "ZPixmap" }, + { 0, NULL } +}; + +static const value_string image_pixmap_format_vals[] = { + { 1, "XYPixmap" }, + { 2, "ZPixmap" }, + { 0, NULL } +}; + +static const value_string join_style_vals[] = { + { 0, "Miter" }, + { 1, "Round" }, + { 2, "Bevel" }, + { 0, NULL } +}; + +static const value_string key_vals[] = { + { 0, "AnyKey" }, + { 0, NULL } +}; + +#include "packet-x11-keysym.h" + +static const value_string line_style_vals[] = { + { 0, "Solid" }, + { 1, "OnOffDash" }, + { 2, "DoubleDash" }, + { 0, NULL } +}; + +static const value_string mode_vals[] = { + { 0, "Replace" }, + { 1, "Prepend" }, + { 2, "Append" }, + { 0, NULL } +}; + +static const value_string on_off_vals[] = { + { 0, "Off" }, + { 1, "On" }, + { 0, NULL } +}; + +static const value_string opcode_vals[] = { + { 1, "CreateWindow" }, + { 2, "ChangeWindowAttributes" }, + { 3, "GetWindowAttributes" }, + { 4, "DestroyWindow" }, + { 5, "DestroySubwindows" }, + { 6, "ChangeSaveSet" }, + { 7, "ReparentWindow" }, + { 8, "MapWindow" }, + { 9, "MapSubwindows" }, + { 10, "UnmapWindow" }, + { 11, "UnmapSubwindows" }, + { 12, "ConfigureWindow" }, + { 13, "CirculateWindow" }, + { 14, "GetGeometry" }, + { 15, "QueryTree" }, + { 16, "InternAtom" }, + { 17, "GetAtomName" }, + { 18, "ChangeProperty" }, + { 19, "DeleteProperty" }, + { 20, "GetProperty" }, + { 21, "ListProperties" }, + { 22, "SetSelectionOwner" }, + { 23, "GetSelectionOwner" }, + { 24, "ConvertSelection" }, + + { 26, "GrabPointer" }, + { 27, "UngrabPointer" }, + { 28, "GrabButton" }, + { 29, "UngrabButton" }, + { 30, "ChangeActivePointerGrab" }, + { 31, "GrabKeyboard" }, + { 32, "UngrabKeyboard" }, + { 33, "GrabKey" }, + { 34, "UngrabKey" }, + { 35, "AllowEvents" }, + { 36, "GrabServer" }, + { 37, "UngrabServer" }, + { 38, "QueryPointer" }, + { 39, "GetMotionEvents" }, + { 40, "TranslateCoordinates" }, + { 41, "WarpPointer" }, + { 42, "SetInputFocus" }, + { 43, "GetInputFocus" }, + { 44, "QueryKeymap" }, + { 45, "OpenFont" }, + { 46, "CloseFont" }, + { 47, "QueryFont" }, + { 48, "QueryTextExtents" }, + { 49, "ListFonts" }, + { 50, "ListFontsWithInfo" }, + { 51, "SetFontPath" }, + { 52, "GetFontPath" }, + { 53, "CreatePixmap" }, + { 54, "FreePixmap" }, + { 55, "CreateGC" }, + { 56, "ChangeGC" }, + { 57, "CopyGC" }, + { 58, "SetDashes" }, + { 59, "SetClipRectangles" }, + { 60, "FreeGC" }, + { 61, "ClearArea" }, + { 62, "CopyArea" }, + { 63, "CopyPlane" }, + { 64, "PolyPoint" }, + { 65, "PolyLine" }, + { 66, "PolySegment" }, + { 67, "PolyRectangle" }, + { 68, "PolyArc" }, + { 69, "FillPoly" }, + { 70, "PolyFillRectangle" }, + { 71, "PolyFillArc" }, + { 72, "PutImage" }, + { 73, "GetImage" }, + { 74, "PolyText8" }, + { 75, "PolyText16" }, + { 76, "ImageText8" }, + { 77, "ImageText16" }, + { 78, "CreateColormap" }, + { 79, "FreeColormap" }, + { 80, "CopyColormapAndFree" }, + { 81, "InstallColormap" }, + { 82, "UninstallColormap" }, + { 83, "ListInstalledColormaps" }, + { 84, "AllocColor" }, + { 85, "AllocNamedColor" }, + { 86, "AllocColorCells" }, + { 87, "AllocColorPlanes" }, + { 88, "FreeColors" }, + { 89, "StoreColors" }, + { 90, "StoreNamedColor" }, + { 91, "QueryColors" }, + { 92, "LookupColor" }, + { 93, "CreateCursor" }, + { 94, "CreateGlyphCursor" }, + { 95, "FreeCursor" }, + { 96, "RecolorCursor" }, + { 97, "QueryBestSize" }, + { 98, "QueryExtension" }, + { 99, "ListExtensions" }, + { 100, "ChangeKeyboardMapping" }, + { 101, "GetKeyboardMapping" }, + { 102, "ChangeKeyboardControl" }, + { 103, "GetKeyboardControl" }, + { 104, "Bell" }, + { 105, "ChangePointerControl" }, + { 106, "GetPointerControl" }, + { 107, "SetScreenSaver" }, + { 108, "GetScreenSaver" }, + { 109, "ChangeHosts" }, + { 110, "ListHosts" }, + { 111, "SetAccessControl" }, + { 112, "SetCloseDownMode" }, + { 113, "KillClient" }, + { 114, "RotateProperties" }, + { 115, "ForceScreenSaver" }, + { 116, "SetPointerMapping" }, + { 117, "GetPointerMapping" }, + { 118, "SetModifierMapping" }, + { 119, "GetModifierMapping" }, + { 127, "NoOperation" }, + { 0, NULL } +}; + +static const value_string ordering_vals[] = { + { 0, "UnSorted" }, + { 1, "YSorted" }, + { 2, "YXSorted" }, + { 3, "YXBanded" }, + { 0, NULL } +}; + +static const value_string plane_mask_vals[] = { + { AllPlanes, "AllPlanes" }, + { 0, NULL } +}; + +static const value_string pointer_keyboard_mode_vals[] = { + { 0, "Synchronous" }, + { 1, "Asynchronous" }, + { 0, NULL } +}; + +static const value_string revert_to_vals[] = { + { 0, "None" }, + { 1, "PointerRoot" }, + { 2, "Parent" }, + { 0, NULL } +}; + +static const value_string insert_delete_vals[] = { + { 0, "Insert" }, + { 1, "Delete" }, + { 0, NULL } +}; + +static const value_string screen_saver_mode_vals[] = { + { 0, "Reset" }, + { 1, "Activate" }, + { 0, NULL } +}; + +static const value_string shape_vals[] = { + { 0, "Complex" }, + { 1, "Nonconvex" }, + { 2, "Convex" }, + { 0, NULL } +}; + +static const value_string stack_mode_vals[] = { + { 0, "Above" }, + { 1, "Below" }, + { 2, "TopIf" }, + { 3, "BottomIf" }, + { 4, "Opposite" }, + { 0, NULL } +}; + +static const value_string subwindow_mode_vals[] = { + { 0, "ClipByChildren" }, + { 1, "IncludeInferiors" }, + { 0, NULL } +}; + +static const value_string window_class_vals[] = { + { 0, "CopyFromParent" }, + { 1, "InputOutput" }, + { 2, "InputOnly" }, + { 0, NULL } +}; + +static const value_string yes_no_default_vals[] = { + { 0, "No" }, + { 1, "Yes" }, + { 2, "Default" }, + { 0, NULL } +}; + +static const value_string zero_is_any_property_type_vals[] = { + { 0, "AnyPropertyType" }, + { 0, NULL } +}; + +static const value_string zero_is_none_vals[] = { + { 0, "None" }, + { 0, NULL } +}; + +/************************************************************************ + *** *** + *** G L O B A L V A R I A B L E S ( A R G H H ! ) *** + *** *** + ************************************************************************/ + +static const u_char *pp = NULL; /* The pd exported so it's visible to every routines */ +static const u_char *p = NULL; /* The current data pointer in the pd buffer */ +static const u_char *nextp = NULL; /* Pointer to the next request in the pd buffer */ +static int left = 0; /* The number of bytes left in the pd buffer (may span several requests) */ +static tvbuff_t *tvb = NULL; +static gboolean little_endian = TRUE; +static proto_tree *t = NULL; + +static struct maskStruct { + guint32 _value; + int _offset; + int _zone; + proto_tree *_tree; +} lastMask = { 0, 0, 0, NULL }; + +/************************************************************************ + *** *** + *** F I E L D D E C O D I N G M A C R O S *** + *** *** + ************************************************************************/ + +#define VALUE16_LITTLE_ENDIAN(p) (((p)[0] | (p)[1] << 8)) +#define VALUE32_LITTLE_ENDIAN(p) (((p)[0] | (p)[1] << 8 | (p)[2] << 16 | (p)[3] << 24)) +#define VALUE16_BIG_ENDIAN(p) (((p)[1] | (p)[0] << 8)) +#define VALUE32_BIG_ENDIAN(p) (((p)[3] | (p)[2] << 8 | (p)[1] << 16 | (p)[0] << 24)) + +#define VALUE8(p) ((p)[0]) +#define VALUE16(p) (little_endian ? VALUE16_LITTLE_ENDIAN(p) : VALUE16_BIG_ENDIAN(p)) +#define VALUE32(p) (little_endian ? VALUE32_LITTLE_ENDIAN(p) : VALUE32_BIG_ENDIAN(p)) + +#define FIELD8(name) (field8(hf_x11_##name)) +#define FIELD16(name) (field16(hf_x11_##name)) +#define FIELD32(name) (field32(hf_x11_##name)) + +#define BITFIELD(TYPE, position, name) {\ + if (lastMask._value & proto_registrar_get_nth(hf_x11_##position##_##name) -> bitmask) {\ + int unused;\ + const u_char *save = p;\ + proto_tree_add_item(lastMask._tree, hf_x11_##position##_##name, tvb, lastMask._offset, \ + lastMask._zone, little_endian); \ + TYPE(name);\ + unused = save + 4 - p;\ + if (unused)\ + proto_tree_add_item(t, hf_x11_unused, tvb, p - pp, unused, little_endian);\ + p = save + 4;\ + }\ +} + +#define FLAG(position, name) {\ + if (lastMask._value & proto_registrar_get_nth(hf_x11_##position##_mask##_##name) -> bitmask)\ + proto_tree_add_boolean(lastMask._tree, hf_x11_##position##_mask##_##name, tvb, lastMask._offset, lastMask._zone, lastMask._value); } + +#define ATOM(name) { atom(t, hf_x11_##name); } +#define BITGRAVITY(name) { gravity(#name, hf_x11_##name, "Forget"); } +#define BITMASK8(name) { bitmask(hf_x11_##name##_mask, 1); } +#define BITMASK16(name) { bitmask(hf_x11_##name##_mask, 2); } +#define BITMASK32(name) { bitmask(hf_x11_##name##_mask, 4); } +#define BOOL(name) (boolean(#name, hf_x11_##name)) +#define BUTTON(name) { FIELD8(name); } +#define CARD8(name) { FIELD8(name); } +#define CARD16(name) (FIELD16(name)) +#define CARD32(name) (FIELD32(name)) +#define COLOR_FLAGS(name) { colorFlags(t); } +#define COLORMAP(name) { FIELD32(name); } +#define CURSOR(name) { FIELD32(name); } +#define DRAWABLE(name) { FIELD32(name); } +#define ENUM8(name) { FIELD8(name); } +#define ENUM16(name) { FIELD16(name); } +#define FONT(name) { FIELD32(name); } +#define FONTABLE(name) { FIELD32(name); } +#define GCONTEXT(name) { FIELD32(name); } +#define INT8(name) { FIELD8(name); } +#define INT16(name) { FIELD16(name); } +#define KEYCODE(name) { FIELD8(name); } +#define LISTofARC(name) { listOfArc(hf_x11_##name, (nextp - p) / 12); } +#define LISTofATOM(name, length) { listOfAtom(hf_x11_##name, (length) / 4); } +#define LISTofBYTE(name, length) { listOfByte(hf_x11_##name, (length)); } +#define LISTofCARD8(name, length) { listOfByte(hf_x11_##name, (length)); } +#define LISTofCARD32(name, length) { listOfCard32(hf_x11_##name, hf_x11_##name##_item, (length) / 4); } +#define LISTofCOLORITEM(name, length) { listOfColorItem(hf_x11_##name, (length) / 12); } +#define LISTofKEYCODE(name, length) { listOfKeycode(hf_x11_##name, (length)); } +#define LISTofKEYSYM(name, keycode_count, keysyms_per_keycode) { \ + listOfKeysyms(hf_x11_##name, hf_x11_##name##_item, (keycode_count), (keysyms_per_keycode)); } +#define LISTofPOINT(name, length) { listOfPoint(hf_x11_##name, (length) / 4); } +#define LISTofRECTANGLE(name) { listOfRectangle(hf_x11_##name, (nextp - p) / 8); } +#define LISTofSEGMENT(name) { listOfSegment(hf_x11_##name, (nextp - p) / 8); } +#define LISTofSTRING8(name, length) { listOfString8(hf_x11_##name, hf_x11_##name##_string, (length)); } +#define LISTofTEXTITEM8(name) { listOfTextItem(hf_x11_##name, FALSE); } +#define LISTofTEXTITEM16(name) { listOfTextItem(hf_x11_##name, TRUE); } +#define OPCODE() { FIELD8(opcode); } +#define PIXMAP(name) { FIELD32(name); } +#define REQUEST_LENGTH() (requestLength()) +#define SETofEVENT(name) { setOfEvent(); } +#define SETofDEVICEEVENT(name) { setOfDeviceEvent();} +#define SETofKEYMASK(name) { setOfKeyMask(); } +#define SETofPOINTEREVENT(name) { setOfPointerEvent(); } +#define STRING8(name, length) { string8(#name, hf_x11_##name, length); } +#define STRING16(name, length) { string16(hf_x11_##name, hf_x11_##name##_bytes, length); } +#define TIMESTAMP(name){ timestamp(#name, hf_x11_##name); } +#define UNDECODED(x) { proto_tree_add_item(t, hf_x11_undecoded, tvb, p - pp, x, little_endian); p += x; } +#define UNUSED(x) { proto_tree_add_item(t, hf_x11_unused, tvb, p - pp, x, little_endian); p += x; } +#define PAD() { if (nextp - p > 0) proto_tree_add_item(t, hf_x11_unused, tvb, p - pp, nextp - p, little_endian); p = nextp; } +#define WINDOW(name) { FIELD32(name); } +#define WINGRAVITY(name) { gravity(#name, hf_x11_##name, "Unmap"); } + +#define VISUALID(name) { gint32 v = VALUE32(p); \ + proto_tree_add_uint_format(t, hf_x11_##name, tvb, p - pp, 4, v, "Visualid: 0x%08x%s", v, \ + v ? "" : " (CopyFromParent)"); p += 4; } + +/************************************************************************ + *** *** + *** D E C O D I N G F I E L D S *** + *** *** + ************************************************************************/ + +static void atom(proto_tree *t, int hf) +{ + const char *interpretation = NULL; + + guint32 v = VALUE32(p); + if (v >= 1 && v < array_length(atom_predefined_interpretation)) + interpretation = atom_predefined_interpretation[v]; + else if (v) + interpretation = "Not a predefined atom"; + else { + struct header_field_info *hfi = proto_registrar_get_nth(hf); + if (hfi -> strings) + interpretation = match_strval(v, cVALS(hfi -> strings)); + } + if (!interpretation) interpretation = "error in Xlib client program ?"; + proto_tree_add_uint_format(t, hf, tvb, p - pp, 4, v, "%s: %d (%s)", + proto_registrar_get_nth(hf) -> name, v, interpretation); + p += 4; +} + +static void bitmask(int hf, int size) +{ + lastMask._value = size == 2 ? VALUE16(p) : VALUE32(p); + lastMask._offset = p - pp; + lastMask._zone = size; + lastMask._tree = proto_tree_add_uint(t, hf, tvb, p - pp, size, lastMask._value); + p += size; +} + +static guint32 boolean(const char *nameAsChar, int hf) +{ + guint32 v = VALUE8(p); + proto_tree_add_boolean(t, hf, tvb, p - pp, 1, v); + p += 1; + return v; +} + +static void colorFlags(proto_tree *t) +{ + unsigned do_red_green_blue = VALUE8(p); + proto_tree *tt; + + if (do_red_green_blue) { + int sep = FALSE; + char buffer[512]; + char *bp = buffer + sprintf(buffer, "flags: "); + + if (do_red_green_blue & 0x1) { + bp += sprintf(bp, "DoRed"); + sep = TRUE; + } + + if (do_red_green_blue & 0x2) { + if (sep) bp += sprintf(bp, " | "); + bp += sprintf(bp, "DoGreen"); + sep = TRUE; + } + + if (do_red_green_blue & 0x4) { + if (sep) bp += sprintf(bp, " | "); + bp += sprintf(bp, "DoBlue"); + sep = TRUE; + } + + if (do_red_green_blue & 0xf8) { + if (sep) bp += sprintf(bp, " + "); + sprintf(bp, "trash"); + } + + tt = proto_tree_add_uint_format(t, hf_x11_coloritem_flags, tvb, p - pp, 1, do_red_green_blue, + "%s", buffer); + if (do_red_green_blue & 0x1) + proto_tree_add_boolean(tt, hf_x11_coloritem_flags_do_red, tvb, p - pp, 1, + do_red_green_blue & 0x1); + if (do_red_green_blue & 0x2) + proto_tree_add_boolean(tt, hf_x11_coloritem_flags_do_green, tvb, p - pp, 1, + do_red_green_blue & 0x2); + if (do_red_green_blue & 0x4) + proto_tree_add_boolean(tt, hf_x11_coloritem_flags_do_blue, tvb, p - pp, 1, + do_red_green_blue & 0x4); + if (do_red_green_blue & 0xf8) + proto_tree_add_boolean(tt, hf_x11_coloritem_flags_unused, tvb, p - pp, 1, + do_red_green_blue & 0xf8); + } else + proto_tree_add_uint_format(t, hf_x11_coloritem_flags, tvb, p - pp, 1, do_red_green_blue, + "flags: none"); + p++; +} + +static void gravity(const char *nameAsChar, int hf, const char *nullInterpretation) +{ + guint8 v = VALUE8(p); + if (!v) + proto_tree_add_uint_format(t, hf, tvb, p - pp, 1, v, "%s: 0 (%s)", nameAsChar, + nullInterpretation); + else + proto_tree_add_uint(t, hf, tvb, p - pp, 1, v); + p += 1; +} + +static void listOfArc(int hf, int length) +{ + proto_tree *tt = proto_tree_add_item(t, hf, tvb, p - pp, length * 8, little_endian); + while(length--) { + gint16 x = VALUE16(p); + gint16 y = VALUE16(p + 2); + guint16 width = VALUE16(p + 4); + guint16 height = VALUE16(p + 6); + gint16 angle1 = VALUE16(p + 8); + gint16 angle2 = VALUE16(p + 10); + + proto_tree *ttt = proto_tree_add_protocol_format(tt, hf_x11_arc, tvb, p - pp, 12, + "arc: %dx%d%+d%+d, angle %d -> %d (%f° -> %f°)", + width, height, x, y, angle1, angle2, + angle1 / 64.0, angle2 / 64.0); + proto_tree_add_int(ttt, hf_x11_arc_x, tvb, p - pp, 2, x); p += 2; + proto_tree_add_int(ttt, hf_x11_arc_y, tvb, p - pp, 2, y); p += 2; + proto_tree_add_uint(ttt, hf_x11_arc_width, tvb, p - pp, 2, y); p += 2; + proto_tree_add_uint(ttt, hf_x11_arc_height, tvb, p - pp, 2, y); p += 2; + proto_tree_add_int(ttt, hf_x11_arc_angle1, tvb, p - pp, 2, y); p += 2; + proto_tree_add_int(ttt, hf_x11_arc_angle2, tvb, p - pp, 2, y); p += 2; + } +} + +static void listOfAtom(int hf, int length) +{ + proto_tree *tt = proto_tree_add_item(t, hf, tvb, p - pp, length * 4, little_endian); + while(length--) { + if (p + 4 > nextp) return; + atom(tt, hf_x11_properties_item); + } +} + +static void listOfByte(int hf, int length) +{ + if (p + length > nextp) length = nextp - p; + if (length <= 0) length = 1; + proto_tree_add_bytes(t, hf, tvb, p - pp, length, p); + p += length; +} + +static void listOfCard32(int hf, int hf_item, int length) +{ + proto_tree *tt = proto_tree_add_item(t, hf, tvb, p - pp, length * 4, little_endian); + while(length--) { + if (p + 4 > nextp) return; + proto_tree_add_uint(tt, hf_item, tvb, p - pp, 4, VALUE32(p)); + p += 4; + } +} + +static void listOfColorItem(int hf, int length) +{ + proto_tree *tt = proto_tree_add_item(t, hf, tvb, p - pp, length * 8, little_endian); + while(length--) { + proto_tree *ttt; + unsigned do_red_green_blue; + guint16 red, green, blue; + char buffer[1024]; + char *bp; + const char *sep; + + if (p + 12 > nextp) return; + red = VALUE16(p + 4); + green = VALUE16(p + 6); + blue = VALUE16(p + 8); + do_red_green_blue = VALUE8(p + 10); + + bp = buffer + sprintf(buffer, "colorItem: "); + sep = ""; + if (do_red_green_blue & 0x1) { bp += sprintf(bp, "red = %d", red); sep = ", "; } + if (do_red_green_blue & 0x2) { bp += sprintf(bp, "%sgreen = %d", sep, green); sep = ", "; } + if (do_red_green_blue & 0x4) bp += sprintf(bp, "%sblue = %d", sep, blue); + + ttt = proto_tree_add_protocol_format(tt, hf_x11_coloritem, tvb, p - pp, 12, "%s", buffer); + proto_tree_add_item(ttt, hf_x11_coloritem_pixel, tvb, p - pp, 4, little_endian); p += 4; + proto_tree_add_item(ttt, hf_x11_coloritem_red, tvb, p - pp, 2, little_endian); p += 2; + proto_tree_add_item(ttt, hf_x11_coloritem_green, tvb, p - pp, 2, little_endian); p += 2; + proto_tree_add_item(ttt, hf_x11_coloritem_blue, tvb, p - pp, 2, little_endian); p += 2; + colorFlags(ttt); + proto_tree_add_item(ttt, hf_x11_coloritem_unused, tvb, p - pp, 1, little_endian); p++; + } +} + +static GTree *keysymTable = NULL; + +static gint compareGuint32(gconstpointer a, gconstpointer b) +{ + return GPOINTER_TO_INT(b) - GPOINTER_TO_INT(a);; +} + +static const char *keysymString(guint32 v) +{ + gpointer res; + if (!keysymTable) { + + /* This table is so big that we built it only if necessary */ + + const value_string *p = keysym_vals_source; + keysymTable = g_tree_new(compareGuint32); + for(; p -> strptr; p++) + g_tree_insert(keysymTable, GINT_TO_POINTER(p -> value), p -> strptr); + } + res = g_tree_lookup(keysymTable, GINT_TO_POINTER(v)); + return res ? res : "Unknown"; +} + +static const char *modifiers[] = { "Shift", "Lock", "Control", "Mod1", "Mod2", "Mod3", "Mod4", "Mod5" }; + +static void listOfKeycode(int hf, int length) +{ + char buffer[1024]; + proto_tree *tt = proto_tree_add_item(t, hf, tvb, p - pp, length * 8, little_endian); + + while(length--) { + char *bp = buffer; + const char **m; + int i; + + if (p + 8 > nextp) return; + for(i = 8, m = modifiers; i; i--, m++) { + u_char c = *p++; + if (c) bp += sprintf(bp, " %s=%d", *m, c); + } + + proto_tree_add_bytes_format(tt, hf_x11_keycodes_item, tvb, p - 8 - pp, 8, p - 8, "item: %s", buffer); + } +} + +static void listOfKeysyms(int hf, int hf_item, int keycode_count, int keysyms_per_keycode) +{ + proto_tree *tt = proto_tree_add_item(t, hf, tvb, p - pp, keycode_count * keysyms_per_keycode * 4, little_endian); + proto_tree *ttt; + int i; + char buffer[128]; + char *bp; + + while(keycode_count--) { + if (p + keysyms_per_keycode * 4 > nextp) return; + bp = buffer + sprintf(buffer, "keysyms:"); + for(i = 0; i < keysyms_per_keycode; i++) { + bp += sprintf(bp, " %s", keysymString(VALUE32(p + i * 4))); + } + *bp = '\0'; + ttt = proto_tree_add_protocol_format(tt, hf_item, tvb, p - pp, keysyms_per_keycode * 4, + "%s", buffer); + for(i = keysyms_per_keycode; i; i--) { + guint32 v = VALUE32(p); + proto_tree_add_uint_format(ttt, hf_x11_keysyms_item_keysym, tvb, p - pp, 4, v, + "keysym: 0x%08x (%s)", v, keysymString(v)); + p += 4; + } + } +} + +static void listOfPoint(int hf, int length) +{ + proto_tree *tt = proto_tree_add_item(t, hf, tvb, p - pp, length * 4, little_endian); + while(length--) { + gint16 x, y; + proto_tree *ttt; + + if (p + 4 > nextp) return; + x = VALUE16(p); + y = VALUE16(p + 2); + + ttt = proto_tree_add_protocol_format(tt, hf_x11_point, tvb, p - pp, 4, "point: (%d,%d)", x, y); + proto_tree_add_int(ttt, hf_x11_point_x, tvb, p - pp, 2, x); p += 2; + proto_tree_add_int(ttt, hf_x11_point_y, tvb, p - pp, 2, y); p += 2; + } +} + +static void listOfRectangle(int hf, int length) +{ + proto_tree *tt = proto_tree_add_item(t, hf, tvb, p - pp, length * 8, little_endian); + while(length--) { + gint16 x, y; + unsigned width, height; + proto_tree *ttt; + + if (p + 8 > nextp) return; + x = VALUE16(p); + y = VALUE16(p + 2); + width = VALUE16(p + 4); + height = VALUE16(p + 6); + + ttt = proto_tree_add_protocol_format(tt, hf_x11_rectangle, tvb, p - pp, 8, + "rectangle: %dx%d%+d%+d", width, height, x, y); + proto_tree_add_int(ttt, hf_x11_rectangle_x, tvb, p - pp, 2, x); p += 2; + proto_tree_add_int(ttt, hf_x11_rectangle_y, tvb, p - pp, 2, y); p += 2; + proto_tree_add_uint(ttt, hf_x11_rectangle_width, tvb, p - pp, 2, width); p += 2; + proto_tree_add_uint(ttt, hf_x11_rectangle_height, tvb, p - pp, 2, height); p += 2; + } +} + +static void listOfSegment(int hf, int length) +{ + proto_tree *tt = proto_tree_add_item(t, hf, tvb, p - pp, length * 8, little_endian); + while(length--) { + gint16 x1, y1, x2, y2; + proto_tree *ttt; + if (p + 8 > nextp) return; + x1 = VALUE16(p); + y1 = VALUE16(p + 2); + x2 = VALUE16(p + 4); + y2 = VALUE16(p + 6); + + ttt = proto_tree_add_protocol_format(tt, hf_x11_segment, tvb, p - pp, 8, + "segment: (%d,%d)-(%d,%d)", x1, y1, x2, y2); + proto_tree_add_item(ttt, hf_x11_segment_x1, tvb, p - pp, 2, little_endian); p += 2; + proto_tree_add_item(ttt, hf_x11_segment_y1, tvb, p - pp, 2, little_endian); p += 2; + proto_tree_add_item(ttt, hf_x11_segment_x2, tvb, p - pp, 2, little_endian); p += 2; + proto_tree_add_item(ttt, hf_x11_segment_y2, tvb, p - pp, 2, little_endian); p += 2; + } +} + +static void stringCopy(char *dest, const char *source, int length) +{ + char c; + while(length--) { + c = *source++; + if (!isgraph(c) && c != ' ') c = '.'; + *dest++ = c; + } + *dest++ = '\0'; +} + +static void listOfString8(int hf, int hf_item, int length) +{ + char *s = NULL; + int allocated = 0; + proto_tree *tt; + int i; + + /* Compute total length */ + + const unsigned char *xp = p; + int l; + for(i = length; i; i--) { + l = *xp++; + xp += l; + } + + tt = proto_tree_add_item(t, hf, tvb, p - pp, xp - p, little_endian); + + while(length--) { + unsigned l = VALUE8(p); + if (allocated < l + 1) { + /* g_realloc doesn't work ??? */ + g_free(s); + s = g_malloc(l + 1); + allocated = l + 1; + } + stringCopy(s, p + 1, l); /* Nothing better for now. We need a better string handling API. */ + proto_tree_add_string_format(tt, hf_item, tvb, p - pp, l + 1, s, "\"%s\"", s); + p += l + 1; + } + g_free(s); +} + +#define STRING16_MAX_DISPLAYED_LENGTH 150 + +static int stringIsActuallyAn8BitString(const char *p, unsigned length) +{ + if (length > STRING16_MAX_DISPLAYED_LENGTH) length = STRING16_MAX_DISPLAYED_LENGTH; + for(; length > 0; p += 2, length--) if (*p) return FALSE; + return TRUE; +} + +/* length is the length of the _byte_zone_ (that is, twice the length of the string) */ + +static void string16_with_buffer_preallocated(proto_tree *t, int hf, int hf_bytes, + const unsigned char *p, unsigned length, + char **s, int *sLength) +{ + int truncated = FALSE; + unsigned l = length / 2; + + if (stringIsActuallyAn8BitString(p, l)) { + char *dp; + const char *sp = p; + + if (l > STRING16_MAX_DISPLAYED_LENGTH) { + truncated = TRUE; + l = STRING16_MAX_DISPLAYED_LENGTH; + } + if (*sLength < l + 3) { + g_free(*s); + *s = g_malloc(l + 3); + *sLength = l + 3; + } + dp = *s; + *dp++ = '"'; + if (truncated) l -= 3; + + while(l--) { + sp++; + *dp++ = *sp++; + } + *dp++ = '"'; + + /* If truncated, add an ellipsis */ + if (truncated) { *dp++ = '.'; *dp++ = '.'; *dp++ = '.'; } + + *dp++ = '\0'; + proto_tree_add_string_format(t, hf, tvb, p - pp, length, p, "%s: %s", + proto_registrar_get_nth(hf) -> name, *s); + } else + proto_tree_add_bytes(t, hf_bytes, tvb, p - pp, length, p); + +} + +static void listOfTextItem(int hf, int sizeIs16) +{ + int allocated = 0; + char *s = NULL; + proto_tree *tt; + guint32 fid; + + /* Compute total length */ + + const unsigned char *xp = p; /* Scanning pointer */ + int l; /* Length of an individual item */ + int n = 0; /* Number of items */ + while(xp < nextp) { + l = *xp++; + if (!l) break; + n++; + xp += l == 255 ? 4 : l + (sizeIs16 ? l : 0) + 1; + } + + tt = proto_tree_add_item(t, hf, tvb, p - pp, xp - p, little_endian); + + while(n--) { + unsigned l = VALUE8(p); + if (l == 255) { /* Item is a font */ + fid = VALUE32_BIG_ENDIAN(p + 1); + proto_tree_add_uint(tt, hf_x11_textitem_font, tvb, p - pp, 5, fid); + p += 5; + } else { /* Item is a string */ + proto_tree *ttt; + gint8 delta = VALUE8(p + 1); + if (sizeIs16) l += l; + if (allocated < l + 1) { + /* g_realloc doesn't work ??? */ + g_free(s); + s = g_malloc(l + 1); + allocated = l + 1; + } + stringCopy(s, p + 2, l); + ttt = proto_tree_add_protocol_format(tt, hf_x11_textitem_string, tvb, p - pp, l + 2, + "textitem (string): delta = %d, \"%s\"", + delta, s); + proto_tree_add_item(ttt, hf_x11_textitem_string_delta, tvb, p - pp + 1, 1, little_endian); + if (sizeIs16) + string16_with_buffer_preallocated(ttt, hf_x11_textitem_string_string16, + hf_x11_textitem_string_string16_bytes, + p + 2, l, + &s, &allocated); + else + proto_tree_add_string_format(ttt, hf_x11_textitem_string_string8, tvb, + p - pp + 2, l, s, "\"%s\"", s); + p += l + 2; + } + } + g_free(s); +} + +static guint32 field8(int hf) +{ + guint32 v = VALUE8(p); + struct header_field_info *hfi = proto_registrar_get_nth(hf); + gchar *enumValue = NULL; + gchar *nameAsChar = hfi -> name; + + if (hfi -> strings) + enumValue = match_strval(v, cVALS(hfi -> strings)); + if (enumValue) + proto_tree_add_uint_format(t, hf, tvb, p - pp, 1, v, "%s: %d (%s)", nameAsChar, v, enumValue); + else + proto_tree_add_item(t, hf, tvb, p - pp, 1, little_endian); + p += 1; + return v; +} + +static guint32 field16(int hf) +{ + guint32 v = VALUE16(p); + proto_tree_add_item(t, hf, tvb, p - pp, 2, v); + p += 2; + return v; +} + +static guint32 field32(int hf) +{ + guint32 v = VALUE32(p); + struct header_field_info *hfi = proto_registrar_get_nth(hf); + gchar *enumValue = NULL; + gchar *nameAsChar = hfi -> name; + + if (hfi -> strings) + enumValue = match_strval(v, cVALS(hfi -> strings)); + if (enumValue) + proto_tree_add_uint_format(t, hf, tvb, p - pp, 4, v, "%s: 0x%08x (%s)", nameAsChar, v, enumValue); + else + proto_tree_add_uint_format(t, hf, tvb, p - pp, 4, v, + hfi -> display == BASE_DEC ? "%s: %d" : "%s : 0x%08x", + nameAsChar, v); + p += 4; + return v; +} + +static void gcAttributes() +{ + BITMASK32(gc_value); + BITFIELD(ENUM8, gc_value_mask, function); + BITFIELD(CARD32, gc_value_mask, plane_mask); + BITFIELD(CARD32, gc_value_mask, foreground); + BITFIELD(CARD32, gc_value_mask, background); + BITFIELD(CARD16, gc_value_mask, line_width); + BITFIELD(ENUM8, gc_value_mask, line_style); + BITFIELD(ENUM8, gc_value_mask, cap_style); + BITFIELD(ENUM8, gc_value_mask, join_style); + BITFIELD(ENUM8, gc_value_mask, fill_style); + BITFIELD(ENUM8, gc_value_mask, fill_rule); + BITFIELD(PIXMAP, gc_value_mask, tile); + BITFIELD(PIXMAP, gc_value_mask, stipple); + BITFIELD(INT16, gc_value_mask, tile_stipple_x_origin); + BITFIELD(INT16, gc_value_mask, tile_stipple_y_origin); + BITFIELD(FONT, gc_value_mask, font); + BITFIELD(ENUM8, gc_value_mask, subwindow_mode); + BITFIELD(BOOL, gc_value_mask, graphics_exposures); + BITFIELD(INT16, gc_value_mask, clip_x_origin); + BITFIELD(INT16, gc_value_mask, clip_y_origin); + BITFIELD(PIXMAP, gc_value_mask, clip_mask); + BITFIELD(CARD16, gc_value_mask, dash_offset); + BITFIELD(CARD8, gc_value_mask, gc_dashes); + BITFIELD(ENUM8, gc_value_mask, arc_mode); +} + +static void gcMask() +{ + BITMASK32(gc_value); + FLAG(gc_value, function); + FLAG(gc_value, plane_mask); + FLAG(gc_value, foreground); + FLAG(gc_value, background); + FLAG(gc_value, line_width); + FLAG(gc_value, line_style); + FLAG(gc_value, cap_style); + FLAG(gc_value, join_style); + FLAG(gc_value, fill_style); + FLAG(gc_value, fill_rule); + FLAG(gc_value, tile); + FLAG(gc_value, stipple); + FLAG(gc_value, tile_stipple_x_origin); + FLAG(gc_value, tile_stipple_y_origin); + FLAG(gc_value, font); + FLAG(gc_value, subwindow_mode); + FLAG(gc_value, graphics_exposures); + FLAG(gc_value, clip_x_origin); + FLAG(gc_value, clip_y_origin); + FLAG(gc_value, clip_mask); + FLAG(gc_value, dash_offset); + FLAG(gc_value, gc_dashes); + FLAG(gc_value, arc_mode); +} + +static guint32 requestLength() +{ + guint32 res = VALUE16(p) * 4; + proto_tree_add_uint(t, hf_x11_request_length, tvb, p - pp, 2, res); + p += 2; + return res; +} + +static void setOfEvent() { + struct maskStruct save = lastMask; + BITMASK32(event); + FLAG(event, KeyPress); + FLAG(event, KeyRelease); + FLAG(event, ButtonPress); + FLAG(event, ButtonRelease); + FLAG(event, EnterWindow); + FLAG(event, LeaveWindow); + FLAG(event, PointerMotion); + FLAG(event, PointerMotionHint); + FLAG(event, Button1Motion); + FLAG(event, Button2Motion); + FLAG(event, Button3Motion); + FLAG(event, Button4Motion); + FLAG(event, Button5Motion); + FLAG(event, ButtonMotion); + FLAG(event, KeymapState); + FLAG(event, Exposure); + FLAG(event, VisibilityChange); + FLAG(event, StructureNotify); + FLAG(event, ResizeRedirect); + FLAG(event, SubstructureNotify); + FLAG(event, SubstructureRedirect); + FLAG(event, FocusChange); + FLAG(event, PropertyChange); + FLAG(event, ColormapChange); + FLAG(event, OwnerGrabButton); + FLAG(event, erroneous_bits); + lastMask = save; +} + +static void setOfDeviceEvent() { + struct maskStruct save = lastMask; + BITMASK32(do_not_propagate); + FLAG(do_not_propagate, KeyPress); + FLAG(do_not_propagate, KeyRelease); + FLAG(do_not_propagate, ButtonPress); + FLAG(do_not_propagate, ButtonRelease); + FLAG(do_not_propagate, PointerMotion); + FLAG(do_not_propagate, Button1Motion); + FLAG(do_not_propagate, Button2Motion); + FLAG(do_not_propagate, Button3Motion); + FLAG(do_not_propagate, Button4Motion); + FLAG(do_not_propagate, Button5Motion); + FLAG(do_not_propagate, ButtonMotion); + FLAG(do_not_propagate, erroneous_bits); + lastMask = save; +} + +static void setOfKeyMask() +{ + struct maskStruct save = lastMask; + lastMask._value = VALUE16(p); + lastMask._offset = p - pp; + lastMask._zone = 2; + if (lastMask._value == 0x8000) + proto_tree_add_uint_format(t, hf_x11_modifiers_mask_AnyModifier, tvb, p - pp, 2, 0x8000, + "modifiers-masks: 0x8000 (AnyModifier)"); + else { + lastMask._tree = proto_tree_add_uint(t, hf_x11_modifiers_mask, tvb, p - pp, 2, + lastMask._value); + FLAG(modifiers, Shift); + FLAG(modifiers, Lock); + FLAG(modifiers, Control); + FLAG(modifiers, Mod1); + FLAG(modifiers, Mod2); + FLAG(modifiers, Mod3); + FLAG(modifiers, Mod4); + FLAG(modifiers, Mod5); + FLAG(modifiers, erroneous_bits); + } + lastMask = save; + p += 2; +} + +static void setOfPointerEvent() { + struct maskStruct save = lastMask; + BITMASK16(pointer_event); + FLAG(pointer_event, ButtonPress); + FLAG(pointer_event, ButtonRelease); + FLAG(pointer_event, EnterWindow); + FLAG(pointer_event, LeaveWindow); + FLAG(pointer_event, PointerMotion); + FLAG(pointer_event, PointerMotionHint); + FLAG(pointer_event, Button1Motion); + FLAG(pointer_event, Button2Motion); + FLAG(pointer_event, Button3Motion); + FLAG(pointer_event, Button4Motion); + FLAG(pointer_event, Button5Motion); + FLAG(pointer_event, ButtonMotion); + FLAG(pointer_event, KeymapState); + FLAG(pointer_event, erroneous_bits); + lastMask = save; +} + +static void string8(const char *nameAsChar, int hf, unsigned length) +{ + char *s = g_malloc(length + 1); + stringCopy(s, p, length); + proto_tree_add_string_format(t, hf, tvb, p - pp, length, s, "%s: %s", nameAsChar, s); + g_free(s); + p += length; +} + +/* The length is the length of the _byte_zone_ (twice the length of the string) */ + +static void string16(int hf, int hf_bytes, unsigned length) +{ + char *s = NULL; + unsigned l = 0; + length += length; + string16_with_buffer_preallocated(t, hf, hf_bytes, p, length, &s, &l); + g_free(s); + p += length; +} + +static void timestamp(const char *nameAsChar, int hf) +{ + guint32 v = VALUE32(p); + if (!v) + proto_tree_add_uint_format(t, hf, tvb, p - pp, 4, 0, "%s: 0 (CurrentTime)", nameAsChar); + else + proto_tree_add_uint(t, hf, tvb, p - pp, 4, v); + p += 4; +} + +static void windowAttributes() +{ + BITMASK32(window_value); + BITFIELD(PIXMAP, window_value_mask, background_pixmap); + BITFIELD(CARD32, window_value_mask, background_pixel); + BITFIELD(PIXMAP, window_value_mask, border_pixmap); + BITFIELD(CARD32, window_value_mask, border_pixel); + BITFIELD(BITGRAVITY, window_value_mask, bit_gravity); + BITFIELD(WINGRAVITY, window_value_mask, win_gravity); + BITFIELD(ENUM8, window_value_mask, backing_store); + BITFIELD(CARD32, window_value_mask, backing_planes); + BITFIELD(CARD32, window_value_mask, backing_pixel); + BITFIELD(BOOL, window_value_mask, override_redirect); + BITFIELD(BOOL, window_value_mask, save_under); + BITFIELD(SETofEVENT, window_value_mask, event_mask); + BITFIELD(SETofDEVICEEVENT, window_value_mask, do_not_propagate_mask); + BITFIELD(COLORMAP, window_value_mask, colormap); + BITFIELD(CURSOR, window_value_mask, cursor); +} + +/************************************************************************ + *** *** + *** D E C O D I N G O N E P A C K E T *** + *** *** + ************************************************************************/ + +static void dissect_x11_request_loop(proto_tree *root) +{ + int nextLeft; + proto_item *ti; + guint8 v8, v8_2; + guint16 v16; + guint32 v32; + + for(;;) { + int length, opcode; + + /* fprintf(stderr, "Starting loop, left = %d, offset = %d\n", left, p - pp); */ + if (left < 4) return; + length = VALUE16(p + 2) * 4; + /* fprintf(stderr, "length = %d\n", length);*/ + if (left < length || length < 4) return; + + ti = proto_tree_add_uint(root, hf_x11_request, tvb, p - pp, length, *p); + t = proto_item_add_subtree(ti, ett_x11_request); + + nextp = p + length; + nextLeft = left - length; + opcode = *p; + + OPCODE(); + switch(opcode) { + case 1: /* CreateWindow */ + CARD8(depth); + REQUEST_LENGTH(); + WINDOW(wid); + WINDOW(parent); + INT16(x); + INT16(y); + CARD16(width); + CARD16(height); + CARD16(border_width); + ENUM16(window_class); + VISUALID(visual); + windowAttributes(); + break; + + case 2: /* ChangeWindowAttributes */ + UNUSED(1); + REQUEST_LENGTH(); + WINDOW(window); + windowAttributes(); + break; + + case 3: /* GetWindowAttributes */ + case 4: /* DestroyWindow */ + case 5: /* DestroySubwindows */ + UNUSED(1); + REQUEST_LENGTH(); + WINDOW(window); + break; + + case 6: /* ChangeSaveSet */ + ENUM8(save_set_mode); + REQUEST_LENGTH(); + WINDOW(window); + break; + + case 7: /* ReparentWindow */ + UNUSED(1); + REQUEST_LENGTH(); + WINDOW(window); + WINDOW(parent); + INT16(x); + INT16(y); + break; + + case 8: /* MapWindow */ + case 9: /* MapSubWindow */ + case 10: /* UnmapWindow */ + case 11: /* UnmapSubwindows */ + UNUSED(1); + REQUEST_LENGTH(); + WINDOW(window); + break; + + case 12: /* ConfigureWindow */ + UNUSED(1); + REQUEST_LENGTH(); + WINDOW(window); + BITMASK16(configure_window); + UNUSED(2); + BITFIELD(INT16, configure_window_mask, x); + BITFIELD(INT16, configure_window_mask, y); + BITFIELD(CARD16, configure_window_mask, width); + BITFIELD(CARD16, configure_window_mask, height); + BITFIELD(CARD16, configure_window_mask, border_width); + BITFIELD(WINDOW, configure_window_mask, sibling); + BITFIELD(ENUM8, configure_window_mask, stack_mode); + PAD(); + break; + + case 13: /* CirculateWindow */ + ENUM8(direction); + REQUEST_LENGTH(); + WINDOW(window); + break; + + case 14: /* GetGeometry */ + case 15: /* QueryTree */ + UNUSED(1); + REQUEST_LENGTH(); + DRAWABLE(drawable); + break; + + case 16: /* InternAtom */ + BOOL(only_if_exists); + REQUEST_LENGTH(); + v16 = FIELD16(name_length); + UNUSED(2); + STRING8(name, v16); + PAD(); + break; + + case 17: /* GetAtomName */ + UNUSED(1); + REQUEST_LENGTH(); + ATOM(atom); + break; + + case 18: /* ChangeProperty */ + ENUM8(mode); + REQUEST_LENGTH(); + WINDOW(window); + ATOM(property); + ATOM(type); + CARD8(format); + UNUSED(3); + v32 = CARD32(data_length); + LISTofBYTE(data, v32); + PAD(); + break; + + case 19: /* DeleteProperty */ + UNUSED(1); + REQUEST_LENGTH(); + WINDOW(window); + ATOM(property); + break; + + case 20: /* GetProperty */ + BOOL(delete); + REQUEST_LENGTH(); + WINDOW(window); + ATOM(property); + ATOM(get_property_type); + CARD32(long_offset); + CARD32(long_length); + break; + + case 21: /* ListProperties */ + UNUSED(1); + REQUEST_LENGTH(); + WINDOW(window); + break; + + case 22: /* SetSelectionOwner */ + UNUSED(1); + REQUEST_LENGTH(); + WINDOW(owner); + ATOM(selection); + TIMESTAMP(time); + break; + + case 23: /* GetSelectionOwner */ + UNUSED(1); + REQUEST_LENGTH(); + ATOM(selection); + break; + + case 24: /* ConvertSelection */ + UNUSED(1); + REQUEST_LENGTH(); + WINDOW(requestor); + ATOM(selection); + ATOM(target); + ATOM(property); + TIMESTAMP(time); + break; + + case 26: /* GrabPointer */ + BOOL(owner_events); + REQUEST_LENGTH(); + WINDOW(grab_window); + SETofPOINTEREVENT(pointer_event_mask); + ENUM8(pointer_mode); + ENUM8(keyboard_mode); + WINDOW(confine_to); + CURSOR(cursor); + TIMESTAMP(time); + break; + + case 27: /* UngrabPointer */ + UNUSED(1); + REQUEST_LENGTH(); + TIMESTAMP(time); + break; + + case 28: /* GrabButton */ + BOOL(owner_events); + REQUEST_LENGTH(); + WINDOW(grab_window); + SETofPOINTEREVENT(event_mask); + ENUM8(pointer_mode); + ENUM8(keyboard_mode); + WINDOW(confine_to); + CURSOR(cursor); + BUTTON(button); + UNUSED(1); + SETofKEYMASK(modifiers); + break; + + case 29: /* UngrabButton */ + BUTTON(button); + REQUEST_LENGTH(); + WINDOW(grab_window); + SETofKEYMASK(modifiers); + UNUSED(2); + break; + + case 30: /* ChangeActivePointerGrab */ + UNUSED(1); + REQUEST_LENGTH(); + CURSOR(cursor); + TIMESTAMP(time); + SETofPOINTEREVENT(event_mask); + UNUSED(2); + break; + + case 31: /* GrabKeyboard */ + BOOL(owner_events); + REQUEST_LENGTH(); + WINDOW(grab_window); + TIMESTAMP(time); + ENUM8(pointer_mode); + ENUM8(keyboard_mode); + UNUSED(2); + break; + + case 32: /* UngrabKeyboard */ + UNUSED(1); + REQUEST_LENGTH(); + TIMESTAMP(time); + break; + + case 33: /* GrabKey */ + BOOL(owner_events); + REQUEST_LENGTH(); + WINDOW(grab_window); + SETofKEYMASK(modifiers); + KEYCODE(key); + ENUM8(pointer_mode); + ENUM8(keyboard_mode); + UNUSED(3); + break; + + case 34: /* UngrabKey */ + KEYCODE(key); + REQUEST_LENGTH(); + WINDOW(grab_window); + SETofKEYMASK(modifiers); + UNUSED(2); + break; + + case 35: /* AllowEvents */ + ENUM8(allow_events_mode); + REQUEST_LENGTH(); + TIMESTAMP(time); + break; + + case 36: /* GrabServer */ + UNUSED(1); + REQUEST_LENGTH(); + break; + + case 37: /* UngrabServer */ + UNUSED(1); + REQUEST_LENGTH(); + break; + + case 38: /* QueryPointer */ + UNUSED(1); + REQUEST_LENGTH(); + WINDOW(window); + break; + + case 39: /* GetMotionEvents */ + UNUSED(1); + REQUEST_LENGTH(); + WINDOW(window); + TIMESTAMP(start); + TIMESTAMP(stop); + break; + + case 40: /* TranslateCoordinates */ + UNUSED(1); + REQUEST_LENGTH(); + WINDOW(src_window); + WINDOW(dst_window); + INT16(src_x); + INT16(src_y); + break; + + case 41: /* WarpPointer */ + UNUSED(1); + REQUEST_LENGTH(); + WINDOW(warp_pointer_src_window); + WINDOW(warp_pointer_dst_window); + INT16(src_x); + INT16(src_y); + CARD16(src_width); + CARD16(src_height); + INT16(dst_x); + INT16(dst_y); + break; + + case 42: /* SetInputFocus */ + ENUM8(revert_to); + REQUEST_LENGTH(); + WINDOW(focus); + TIMESTAMP(time); + break; + + case 43: /* GetInputFocus */ + UNUSED(1); + REQUEST_LENGTH(); + break; + + case 44: /* QueryKeymap */ + UNUSED(1); + REQUEST_LENGTH(); + break; + + case 45: /* OpenFont */ + UNUSED(1); + REQUEST_LENGTH(); + FONT(fid); + v16 = FIELD16(name_length); + UNUSED(2); + STRING8(name, v16); + PAD(); + break; + + case 46: /* CloseFont */ + UNUSED(1); + REQUEST_LENGTH(); + FONT(font); + break; + + case 47: /* QueryFont */ + UNUSED(1); + REQUEST_LENGTH(); + FONTABLE(font); + break; + + case 48: /* QueryTextExtents */ + v8 = BOOL(odd_length); + REQUEST_LENGTH(); + FONTABLE(font); + STRING16(string16, (nextp - p - (v8 ? 2 : 0)) / 2); + PAD(); + break; + + case 49: /* ListFonts */ + UNUSED(1); + REQUEST_LENGTH(); + CARD16(max_names); + v16 = FIELD16(pattern_length); + STRING8(pattern, v16); + PAD(); + break; + + case 50: /* ListFontsWithInfo */ + UNUSED(1); + REQUEST_LENGTH(); + CARD16(max_names); + v16 = FIELD16(pattern_length); + STRING8(pattern, v16); + PAD(); + break; + + case 51: /* SetFontPath */ + UNUSED(1); + REQUEST_LENGTH(); + v16 = CARD16(str_number_in_path); + UNUSED(2); + LISTofSTRING8(path, v16); + PAD(); + break; + + case 52: /* GetFontPath */ + UNUSED(1); + REQUEST_LENGTH(); + break; + + case 53: /* CreatePixmap */ + CARD8(depth); + REQUEST_LENGTH(); + PIXMAP(pid); + DRAWABLE(drawable); + CARD16(width); + CARD16(height); + break; + + case 54: /* FreePixmap */ + UNUSED(1); + REQUEST_LENGTH(); + PIXMAP(pixmap); + break; + + case 55: /* CreateGC */ + UNUSED(1); + REQUEST_LENGTH(); + GCONTEXT(cid); + DRAWABLE(drawable); + gcAttributes(); + break; + + case 56: /* ChangeGC */ + UNUSED(1); + REQUEST_LENGTH(); + GCONTEXT(gc); + gcAttributes(); + break; + + case 57: /* CopyGC */ + UNUSED(1); + REQUEST_LENGTH(); + GCONTEXT(src_gc); + GCONTEXT(dst_gc); + gcMask(); + break; + + case 58: /* SetDashes */ + UNUSED(1); + REQUEST_LENGTH(); + GCONTEXT(gc); + CARD16(dash_offset); + v16 = FIELD16(dashes_length); + LISTofCARD8(dashes, v16); + PAD(); + break; + + case 59: /* SetClipRectangles */ + ENUM8(ordering); + REQUEST_LENGTH(); + GCONTEXT(gc); + INT16(clip_x_origin); + INT16(clip_y_origin); + LISTofRECTANGLE(rectangles); + break; + + case 60: /* FreeGC */ + UNUSED(1); + REQUEST_LENGTH(); + GCONTEXT(gc); + break; + + case 61: /* ClearArea */ + BOOL(exposures); + REQUEST_LENGTH(); + WINDOW(window); + INT16(x); + INT16(y); + CARD16(width); + CARD16(height); + break; + + case 62: /* CopyArea */ + UNUSED(1); + REQUEST_LENGTH(); + DRAWABLE(src_drawable); + DRAWABLE(dst_drawable); + GCONTEXT(gc); + INT16(src_x); + INT16(src_y); + INT16(dst_x); + INT16(dst_y); + CARD16(width); + CARD16(height); + break; + + case 63: /* CopyPlane */ + UNUSED(1); + REQUEST_LENGTH(); + DRAWABLE(src_drawable); + DRAWABLE(dst_drawable); + GCONTEXT(gc); + INT16(src_x); + INT16(src_y); + INT16(dst_x); + INT16(dst_y); + CARD16(width); + CARD16(height); + CARD32(bit_plane); + break; + + case 64: /* PolyPoint */ + ENUM8(coordinate_mode); + v16 = REQUEST_LENGTH(); + DRAWABLE(drawable); + GCONTEXT(gc); + LISTofPOINT(points, v16 - 12); + break; + + case 65: /* PolyLine */ + ENUM8(coordinate_mode); + v16 = REQUEST_LENGTH(); + DRAWABLE(drawable); + GCONTEXT(gc); + LISTofPOINT(points, v16 - 12); + break; + + case 66: /* PolySegment */ + UNUSED(1); + REQUEST_LENGTH(); + DRAWABLE(drawable); + GCONTEXT(gc); + LISTofSEGMENT(segments); + break; + + case 67: /* PolyRectangle */ + UNUSED(1); + REQUEST_LENGTH(); + DRAWABLE(drawable); + GCONTEXT(gc); + LISTofRECTANGLE(rectangles); + break; + + case 68: /* PolyArc */ + UNUSED(1); + REQUEST_LENGTH(); + DRAWABLE(drawable); + GCONTEXT(gc); + LISTofARC(arcs); + break; + + case 69: /* FillPoly */ + UNUSED(1); + v16 = REQUEST_LENGTH(); + DRAWABLE(drawable); + GCONTEXT(gc); + ENUM8(shape); + ENUM8(coordinate_mode); + UNUSED(2); + LISTofPOINT(points, v16 - 16); + break; + + case 70: /* PolyFillRectangle */ + UNUSED(1); + REQUEST_LENGTH(); + DRAWABLE(drawable); + GCONTEXT(gc); + LISTofRECTANGLE(rectangles); + break; + + case 71: /* PolyFillArc */ + UNUSED(1); + REQUEST_LENGTH(); + DRAWABLE(drawable); + GCONTEXT(gc); + LISTofARC(arcs); + break; + + case 72: /* PutImage */ + ENUM8(image_format); + v16 = REQUEST_LENGTH(); + DRAWABLE(drawable); + GCONTEXT(gc); + CARD16(width); + CARD16(height); + INT16(dst_x); + INT16(dst_y); + CARD8(left_pad); + CARD8(depth); + UNUSED(2); + LISTofBYTE(data, v16 - 24); + PAD(); + break; + + case 73: /* GetImage */ + ENUM8(image_pixmap_format); + REQUEST_LENGTH(); + DRAWABLE(drawable); + INT16(x); + INT16(y); + CARD16(width); + CARD16(height); + CARD32(plane_mask); + break; + + case 74: /* PolyText8 */ + UNUSED(1); + v16 = REQUEST_LENGTH(); + DRAWABLE(drawable); + GCONTEXT(gc); + INT16(x); + INT16(y); + LISTofTEXTITEM8(items); + PAD(); + break; + + case 75: /* PolyText16 */ + UNUSED(1); + v16 = REQUEST_LENGTH(); + DRAWABLE(drawable); + GCONTEXT(gc); + INT16(x); + INT16(y); + LISTofTEXTITEM16(items); + PAD(); + break; + + case 76: /* ImageText8 */ + v8 = FIELD8(string_length); + REQUEST_LENGTH(); + DRAWABLE(drawable); + GCONTEXT(gc); + INT16(x); + INT16(y); + STRING8(string, v8); + PAD(); + break; + + case 77: /* ImageText16 */ + v8 = FIELD8(string_length); + REQUEST_LENGTH(); + DRAWABLE(drawable); + GCONTEXT(gc); + INT16(x); + INT16(y); + STRING16(string16, v8); + PAD(); + break; + + case 78: /* CreateColormap */ + ENUM8(alloc); + REQUEST_LENGTH(); + COLORMAP(mid); + WINDOW(window); + VISUALID(visual); + break; + + case 79: /* FreeColormap */ + UNUSED(1); + REQUEST_LENGTH(); + COLORMAP(cmap); + break; + + case 80: /* CopyColormapAndFree */ + UNUSED(1); + REQUEST_LENGTH(); + COLORMAP(mid); + COLORMAP(src_cmap); + break; + + case 81: /* InstallColormap */ + UNUSED(1); + REQUEST_LENGTH(); + COLORMAP(cmap); + break; + + case 82: /* UninstallColormap */ + UNUSED(1); + REQUEST_LENGTH(); + COLORMAP(cmap); + break; + + case 83: /* ListInstalledColormaps */ + UNUSED(1); + REQUEST_LENGTH(); + WINDOW(window); + break; + + case 84: /* AllocColor */ + UNUSED(1); + REQUEST_LENGTH(); + COLORMAP(cmap); + CARD16(red); + CARD16(green); + CARD16(blue); + UNUSED(2); + break; + + case 85: /* AllocNamedColor */ + UNUSED(1); + REQUEST_LENGTH(); + COLORMAP(cmap); + v16 = FIELD16(name_length); + UNUSED(2); + STRING8(name, v16); + PAD(); + break; + + case 86: /* AllocColorCells */ + BOOL(contiguous); + REQUEST_LENGTH(); + COLORMAP(cmap); + CARD16(colors); + CARD16(planes); + break; + + case 87: /* AllocColorPlanes */ + BOOL(contiguous); + REQUEST_LENGTH(); + COLORMAP(cmap); + CARD16(colors); + CARD16(reds); + CARD16(greens); + CARD16(blues); + break; + + case 88: /* FreeColors */ + UNUSED(1); + v16 = REQUEST_LENGTH(); + COLORMAP(cmap); + CARD32(plane_mask); + LISTofCARD32(pixels, v16 - 12); + break; + + case 89: /* StoreColors */ + UNUSED(1); + v16 = REQUEST_LENGTH(); + COLORMAP(cmap); + LISTofCOLORITEM(color_items, v16 - 8); + break; + + case 90: /* StoreNamedColor */ + COLOR_FLAGS(color); + REQUEST_LENGTH(); + COLORMAP(cmap); + CARD32(pixel); + v16 = FIELD16(name_length); + UNUSED(2); + STRING8(name, v16); + PAD(); + break; + + case 91: /* QueryColors */ + UNUSED(1); + v16 = REQUEST_LENGTH(); + COLORMAP(cmap); + LISTofCARD32(pixels, v16 - 8); + break; + + case 92: /* LookupColor */ + UNUSED(1); + REQUEST_LENGTH(); + COLORMAP(cmap); + v16 = FIELD16(name_length); + UNUSED(2); + STRING8(name, v16); + PAD(); + break; + + case 93: /* CreateCursor */ + UNUSED(1); + REQUEST_LENGTH(); + CURSOR(cid); + PIXMAP(source_pixmap); + PIXMAP(mask); + CARD16(fore_red); + CARD16(fore_green); + CARD16(fore_blue); + CARD16(back_red); + CARD16(back_green); + CARD16(back_blue); + CARD16(x); + CARD16(y); + break; + + case 94: /* CreateGlyphCursor */ + UNUSED(1); + REQUEST_LENGTH(); + CURSOR(cid); + FONT(source_font); + FONT(mask_font); + CARD16(source_char); + CARD16(mask_char); + CARD16(fore_red); + CARD16(fore_green); + CARD16(fore_blue); + CARD16(back_red); + CARD16(back_green); + CARD16(back_blue); + break; + + case 95: /* FreeCursor */ + UNUSED(1); + REQUEST_LENGTH(); + CURSOR(cursor); + break; + + case 96: /* RecolorCursor */ + UNUSED(1); + REQUEST_LENGTH(); + CURSOR(cursor); + CARD16(fore_red); + CARD16(fore_green); + CARD16(fore_blue); + CARD16(back_red); + CARD16(back_green); + CARD16(back_blue); + break; + + case 97: /* QueryBestSize */ + ENUM8(class); + REQUEST_LENGTH(); + DRAWABLE(drawable); + CARD16(width); + CARD16(height); + break; + + case 98: /* QueryExtension */ + UNUSED(1); + REQUEST_LENGTH(); + v16 = FIELD16(name_length); + UNUSED(2); + STRING8(name, v16); + PAD(); + break; + + case 99: /* ListExtensions */ + UNUSED(1); + REQUEST_LENGTH(); + break; + + case 100: /* ChangeKeyboardMapping */ + v8 = FIELD8(keycode_count); + REQUEST_LENGTH(); + KEYCODE(first_keycode); + v8_2 = FIELD8(keysyms_per_keycode); + UNUSED(2); + LISTofKEYSYM(keysyms, v8, v8_2); + break; + + case 101: /* GetKeyboardMapping */ + UNUSED(1); + REQUEST_LENGTH(); + KEYCODE(first_keycode); + FIELD8(count); + UNUSED(2); + break; + + case 102: /* ChangeKeyboardControl */ + UNUSED(1); + REQUEST_LENGTH(); + BITMASK32(keyboard_value); + BITFIELD(INT8, keyboard_value_mask, key_click_percent); + BITFIELD(INT8, keyboard_value_mask, bell_percent); + BITFIELD(INT16, keyboard_value_mask, bell_pitch); + BITFIELD(INT16, keyboard_value_mask, bell_duration); + BITFIELD(INT16, keyboard_value_mask, led); + BITFIELD(ENUM8, keyboard_value_mask, led_mode); + BITFIELD(KEYCODE, keyboard_value_mask, keyboard_key); + BITFIELD(ENUM8, keyboard_value_mask, auto_repeat_mode); + break; + + case 103: /* GetKeyboardControl */ + UNUSED(1); + REQUEST_LENGTH(); + break; + + case 104: /* Bell */ + INT8(percent); + REQUEST_LENGTH(); + break; + + case 105: /* ChangePointerControl */ + UNUSED(1); + REQUEST_LENGTH(); + INT16(acceleration_numerator); + INT16(acceleration_denominator); + INT16(threshold); + BOOL(do_acceleration); + BOOL(do_threshold); + break; + + case 106: /* GetPointerControl */ + UNUSED(1); + REQUEST_LENGTH(); + break; + + case 107: /* SetScreenSaver */ + UNUSED(1); + REQUEST_LENGTH(); + INT16(timeout); + INT16(interval); + ENUM8(prefer_blanking); + ENUM8(allow_exposures); + UNUSED(2); + break; + + case 108: /* GetScreenSaver */ + UNUSED(1); + REQUEST_LENGTH(); + break; + + case 109: /* ChangeHosts */ + ENUM8(change_host_mode); + REQUEST_LENGTH(); + ENUM8(family); + UNUSED(1); + v16 = CARD16(address_length); + LISTofCARD8(address, v16); + break; + + case 110: /* ListHosts */ + UNUSED(1); + REQUEST_LENGTH(); + break; + + case 111: /* SetAccessControl */ + ENUM8(access_mode); + REQUEST_LENGTH(); + break; + + case 112: /* SetCloseDownMode */ + ENUM8(close_down_mode); + REQUEST_LENGTH(); + break; + + case 113: /* KillClient */ + UNUSED(1); + REQUEST_LENGTH(); + CARD32(resource); + break; + + case 114: /* RotateProperties */ + UNUSED(1); + v16 = REQUEST_LENGTH(); + WINDOW(window); + CARD16(property_number); + INT16(delta); + LISTofATOM(properties, (v16 - 12)); + break; + + case 115: /* ForceScreenSaver */ + ENUM8(screen_saver_mode); + REQUEST_LENGTH(); + break; + + case 116: /* SetPointerMapping */ + v8 = FIELD8(map_length); + REQUEST_LENGTH(); + LISTofCARD8(map, v8); + PAD(); + break; + + case 117: /* GetPointerMapping */ + UNUSED(1); + REQUEST_LENGTH(); + break; + + case 118: /* SetModifierMapping */ + v8 = FIELD8(keycodes_per_modifier); + REQUEST_LENGTH(); + LISTofKEYCODE(keycodes, v8); + break; + + case 119: /* GetModifierMapping */ + UNUSED(1); + REQUEST_LENGTH(); + break; + + case 127: /* NoOperation */ + UNUSED(1); + REQUEST_LENGTH(); + break; + } + if (p < nextp) + proto_tree_add_item(t, hf_x11_undecoded, tvb, p - pp, nextp - p, little_endian); + p = nextp; + left = nextLeft; + } +} + +/************************************************************************ + *** *** + *** G U E S S I N G T H E B Y T E O R D E R I N G *** + *** *** + ************************************************************************/ + +static GTree *byte_ordering_cache = NULL; +static GMemChunk *address_chunk = NULL; +static GMemChunk *ipv4_chunk = NULL; +static GMemChunk *ipv6_chunk = NULL; + +static gint compareAddresses(gconstpointer aa, gconstpointer bb) +{ + const address *a = (const address *)aa; + const address *b = (const address *)bb; + int c = b -> type - a -> type; + if (c) return c; + c = b -> len - a -> len; + if (c) return c; + return memcmp(b -> data, a -> data, a -> len); +} + +/* If we can't guess, we return TRUE (that is little_endian), cause + I'm developing on a Linux box :-). The (non-)guess isn't cached + however, so we may have more luck next time. I'm quite conservative + in my assertions, cause once it's cached, it's stay in cache, and + we may be fooled up by a packet starting with the end of a request + started in a previous packet... +*/ + +static int little_endian_value_16(const u_char *p) +{ + return p[0] + p[1] * 256; +} + +static int big_endian_value_16(const u_char *p) +{ + return p[0] * 256 + p[1]; +} + +static int little_endian_value_32(const u_char *p) +{ + return p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24; +} + +static int big_endian_value_32(const u_char *p) +{ + return p[3] | p[2] << 8 | p[1] << 16 | p[0] << 24; +} + +int numberOfBitSetTable[] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 }; + +int numberOfBitSet(const u_char *p, int maskLength) +{ + int res = 0; + while(maskLength--) { + int c = *p++; + res += numberOfBitSetTable[c & 0xf] + numberOfBitSetTable[c >> 4]; + } + return res; +} + +static int listOfStringLengthConsistent(const u_char *p, int length, int listLength, int left) +{ + if (listLength > length) return FALSE; + while(listLength--) { + int l; + if (left <= 0) return TRUE; + l = *p; + if (!l) break; + l++; + if (l > length) return FALSE; + if (l > left) return TRUE; + p += l; + length -= l; + left -= l; + } + if (length > 3) return FALSE; + return TRUE; +} + +static int rounded4(int n) +{ + int remainder = n % 4; + int res = n / 4; + if (remainder) res++; + return res; +} + +/* We assume the order to be consistent, until proven wrong. */ + +static gboolean consistentWithOrder(int length, int left, const u_char *p, int (*v16)(const u_char *)) +{ + switch(*p) { + case 1: /* CreateWindow */ + return left < 32 || length == 8 + numberOfBitSet(p + 7 * 4, 4); + + case 2: /* ChangeWindowAttributes */ + case 56: /* ChangeGC */ + return left < 12 || length == 3 + numberOfBitSet(p + 8, 4); + + case 3: /* GetWindowAttributes */ + case 4: /* DestroyWindow */ + case 5: /* DestroySubwindows */ + case 6: /* ChangeSaveSet */ + case 8: /* MapWindow */ + case 9: /* MapSubWindow */ + case 10: /* UnmapWindow */ + case 11: /* UnmapSubwindows */ + case 13: /* CirculateWindow */ + case 14: /* GetGeometry */ + case 15: /* QueryTree */ + case 17: /* GetAtomName */ + case 21: /* ListProperties */ + case 23: /* GetSelectionOwner */ + case 27: /* UngrabPointer */ + case 32: /* UngrabKeyboard */ + case 35: /* AllowEvents */ + case 38: /* QueryPointer */ + case 46: /* CloseFont */ + case 47: /* QueryFont */ + case 54: /* FreePixmap */ + case 60: /* FreeGC */ + case 79: /* FreeColormap */ + case 81: /* InstallColormap */ + case 82: /* UninstallColormap */ + case 83: /* ListInstalledColormaps */ + case 95: /* FreeCursor */ + case 101: /* GetKeyboardMapping */ + case 113: /* KillClient */ + return length == 2; + + case 7: /* ReparentWindow */ + case 22: /* SetSelectionOwner */ + case 30: /* ChangeActivePointerGrab */ + case 31: /* GrabKeyboard */ + case 33: /* GrabKey */ + case 39: /* GetMotionEvents */ + case 40: /* TranslateCoordinates */ + case 53: /* CreatePixmap */ + case 57: /* CopyGC */ + case 61: /* ClearArea */ + case 78: /* CreateColormap */ + case 84: /* AllocColor */ + case 87: /* AllocColorPlanes */ + return length == 4; + + case 12: /* ConfigureWindow */ + return left < 10 || length == 3 + numberOfBitSet(p + 8, 2); + + case 16: /* InternAtom */ + case 98: /* QueryExtension */ + return left < 6 || length == 2 + rounded4(v16(p + 4)); + + case 18: /* ChangeProperty */ + { + int multiplier, type; + if (left < 17) return TRUE; + type = p[16]; + if (type != 8 && type != 16 && type != 32) return FALSE; + multiplier = type == 8 ? 1 : type == 16 ? 2 : 4; + if (left < 24) return TRUE; + return length == 6 + rounded4((v16 == little_endian_value_16 ? little_endian_value_32 : big_endian_value_32)(p + 20) * multiplier); + } + + case 19: /* DeleteProperty */ + case 29: /* UngrabButton */ + case 34: /* UngrabKey */ + case 42: /* SetInputFocus */ + case 80: /* CopyColormapAndFree */ + case 86: /* AllocColorCells */ + case 97: /* QueryBestSize */ + case 105: /* ChangePointerControl */ + case 107: /* SetScreenSaver */ + return length == 3; + + case 20: /* GetProperty */ + case 24: /* ConvertSelection */ + case 26: /* GrabPointer */ + case 28: /* GrabButton */ + case 41: /* WarpPointer */ + return length == 6; + + case 25: /* SendEvent */ + return length == 11; + + case 36: /* GrabServer */ + case 37: /* UngrabServer */ + case 43: /* GetInputFocus */ + case 44: /* QueryKeymap */ + case 52: /* GetFontPath */ + case 99: /* ListExtensions */ + case 103: /* GetKeyboardControl */ + case 104: /* Bell */ + case 106: /* GetPointerControl */ + case 108: /* GetScreenSaver */ + case 110: /* ListHosts */ + case 111: /* SetAccessControl */ + case 112: /* SetCloseDownMode */ + case 115: /* ForceScreenSaver */ + case 117: /* GetPointerMapping */ + case 119: /* GetModifierMapping */ + return length == 1; + + case 45: /* OpenFont */ + case 85: /* AllocNamedColor */ + case 92: /* LookupColor */ + return left < 10 || length == 3 + rounded4(v16(p + 8)); + + case 48: /* QueryTextExtents */ + return length >= 2; + + case 49: /* ListFonts */ + case 50: /* ListFontsWithInfo */ + case 109: /* ChangeHosts */ + return left < 8 || length == 2 + rounded4(v16(p + 6)); + + case 51: /* SetFontPath */ + if (length < 2) return FALSE; + if (left < 8) return TRUE; + return listOfStringLengthConsistent(p + 8, (length - 2) * 4, v16(p + 4), left); + + case 55: /* CreateGC */ + return left < 16 || length == 4 + numberOfBitSet(p + 12, 4); + + case 58: /* SetDashes */ + return left < 12 || length == 3 + rounded4(v16(p + 10)); + + case 59: /* SetClipRectangles */ + case 66: /* PolySegment */ + case 67: /* PolyRectangle */ + case 70: /* PolyFillRectangle */ + return length >= 3 && (length - 3) % 2 == 0; + + case 62: /* CopyArea */ + return length == 7; + + case 63: /* CopyPlane */ + case 93: /* CreateCursor */ + case 94: /* CreateGlyphCursor */ + return length == 8; + + case 64: /* PolyPoint */ + case 65: /* PolyLine */ + case 88: /* FreeColors */ + return length >= 3; + + case 68: /* PolyArc */ + case 71: /* PolyFillArc */ + return length >= 3 && (length - 3) % 3 == 0; + + case 69: /* FillPoly */ + case 76: /* ImageText8 */ + return length >= 4; + + case 72: /* PutImage */ + return length >= 6; + + case 73: /* GetImage */ + case 96: /* RecolorCursor */ + return length == 5; + + case 74: /* PolyText8 */ + if (length < 4) return FALSE; + return TRUE; /* We don't perform many controls on this one */ + + case 75: /* PolyText16 */ + if (length < 4) return FALSE; + return TRUE; /* We don't perform many controls on this one */ + + case 77: /* ImageText16 */ + return length >= 4; + + case 89: /* StoreColors */ + return length > 2 && (length - 2) % 3 == 0; + + case 90: /* StoreNamedColor */ + return left < 14 || length == 4 + rounded4(v16(p + 12)); + + case 91: /* QueryColors */ + return length >= 2; + + case 100: /* ChangeKeyboardMapping */ + return left < 6 || length == 2 + p[1] * p[5]; + + case 102: /* ChangeKeyboardControl */ + return left < 6 || length == 2 + numberOfBitSet(p + 4, 2); + + case 114: /* RotateProperties */ + return left < 10 || length == 3 + v16(p + 8); + + case 116: /* SetPointerMapping */ + return length == 1 + rounded4(p[1]); + + case 118: /* SetModifierMapping */ + return length == 1 + p[1] * 2; + + case 127: /* NoOperation */ + return length >= 1; + + default: + return TRUE; + } +} + +/* -1 means doesn't match, +1 means match, 0 means don't know */ + +static int x_endian_match(const u_char *p, int left, int (*v16)(const u_char *)) +{ + int nextLeft; + const u_char *nextp; + int atLeastOne = 0; + + for(;; p = nextp, left = nextLeft) { + int length; + if (left < 4) return atLeastOne; + length = v16(p + 2); + if (!length) return -1; + nextp = p + length * 4; + nextLeft = left - length * 4; + if (!consistentWithOrder(length, left, p, v16)) return -1; + atLeastOne = 1; + } +} + +static gboolean +guess_byte_ordering(const u_char *p, int left) +{ + /* With X the client gives the byte ordering for the protocol, + and the port on the server tells us we're speaking X. */ + + int le, be, decision, decisionToCache; + + address *addr = pi.srcport == pi.match_port ? &pi.net_dst : &pi.net_src; + gint32 cache = GPOINTER_TO_INT(g_tree_lookup(byte_ordering_cache, addr)); + if (cache) return cache > 0 ? TRUE : FALSE; + if (pi.srcport == pi.match_port) return TRUE; /* We don't try to guess on a reply / event for now */ + + le = x_endian_match(p, left, little_endian_value_16); + be = x_endian_match(p, left, big_endian_value_16); + + /* remember that "decision" really means "little_endian". */ + if (le == be) + /* We have no reason to believe it's little- rather than + big-endian, so we guess the shortest length is the + right one. + */ + if (left < 4) /* Not even a way to get the length. We're biased + toward little endianness here (essentially the + x86 world right now). Decoding won't go very far + anyway. + */ + decision = TRUE; + else + decision = little_endian_value_16(p + 2) <= big_endian_value_16(p + 2); + else + decision = le >= be; + + decisionToCache = (le < 0 && be > 0) || (le > 0 && be < 0); + if (decisionToCache) { + /* We encode the decision as 1 for TRUE and -1 for FALSE + to be able to distinguish between FALSE and no value in + the cache when recalling the value. + */ + int address_length; + char *address_data; + address *cached; + if (addr -> type == AT_IPv4) { + address_length = 4; + address_data = g_mem_chunk_alloc(ipv4_chunk); + } else if (addr -> type == AT_IPv6) { + address_length = 16; + address_data = g_mem_chunk_alloc(ipv6_chunk); + } else { + address_length = addr -> len; + address_data = g_malloc(address_length); + } + cached = g_mem_chunk_alloc(address_chunk); + memcpy(address_data, addr -> data, address_length); + SET_ADDRESS(cached, addr -> type, addr -> len, address_data); + g_tree_insert(byte_ordering_cache, cached, GINT_TO_POINTER(decision ? 1 : -1)); + } + + /* + fprintf(stderr, "packet %d\tle %d\tbe %d\tlittle_endian %d\tcache %d\n", + pi.fd -> num, le, be, decision, decisionToCache); + */ + return decision; +} + +/************************************************************************ + *** *** + *** I N I T I A L I Z A T I O N A N D M A I N *** + *** *** + ************************************************************************/ + +static void +dissect_x11_request(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) +{ +/* Set up structures we will need to add the protocol subtree and manage it */ + proto_item *ti; + proto_tree *x11_tree; + +/* Make entries in Protocol column and Info column on summary display */ + if (check_col(fd, COL_PROTOCOL)) + col_add_str(fd, COL_PROTOCOL, "X11"); + +/* This field shows up as the "Info" column in the display; you should make + it, if possible, summarize what's in the packet, so that a user looking + at the list of packets can tell what type of packet it is. + + "col_add_fstr()" can be used instead of "col_add_str()"; it takes + "printf()"-like arguments. */ + if (check_col(fd, COL_INFO)) + col_add_str(fd, COL_INFO, "X11 request"); + +/* In the interest of speed, if "tree" is NULL, don't do any work not + necessary to generate protocol tree items. */ + if (!tree) return; +/* NOTE: The offset and length values in the previous call to + "proto_tree_add_item()" define what data bytes to highlight in the hex + display window when the line in the protocol tree display + corresponding to that item is selected. + + END_OF_FRAME is a handy way to highlight all data from the offset to + the end of the packet. */ + ti = proto_tree_add_item(tree, proto_x11, tvb, offset, END_OF_FRAME, FALSE); + x11_tree = proto_item_add_subtree(ti, ett_x11); + +/* Code to process the packet goes here */ + + p = pd + offset; + left = fd -> cap_len - offset; + pp = pd; + tvb = pi.compat_top_tvb; + little_endian = guess_byte_ordering(pd + offset, left); + dissect_x11_request_loop(x11_tree); + if (left) + dissect_data(pp, p - pp, fd, x11_tree); +} + +static void +dissect_x11_event(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) +{ +/* Set up structures we will need to add the protocol subtree and manage it */ + proto_item *ti; + proto_tree *x11_tree; + +/* Make entries in Protocol column and Info column on summary display */ + if (check_col(fd, COL_PROTOCOL)) + col_add_str(fd, COL_PROTOCOL, "X11"); + +/* This field shows up as the "Info" column in the display; you should make + it, if possible, summarize what's in the packet, so that a user looking + at the list of packets can tell what type of packet it is. + + "col_add_fstr()" can be used instead of "col_add_str()"; it takes + "printf()"-like arguments. */ + if (check_col(fd, COL_INFO)) + col_add_str(fd, COL_INFO, "X11 event"); + +/* In the interest of speed, if "tree" is NULL, don't do any work not + necessary to generate protocol tree items. */ + if (tree) { +/* NOTE: The offset and length values in the previous call to + "proto_tree_add_item()" define what data bytes to highlight in the hex + display window when the line in the protocol tree display + corresponding to that item is selected. + + END_OF_FRAME is a handy way to highlight all data from the offset to + the end of the packet. */ + ti = proto_tree_add_item(tree, proto_x11, tvb, offset, END_OF_FRAME, FALSE); + x11_tree = proto_item_add_subtree(ti, ett_x11); + +/* Code to process the packet goes here */ + + dissect_data(pd, offset, fd, tree); + } +} + +static void +dissect_x11(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) +{ + if (pi.destport == TCP_PORT_X11 || pi.destport == TCP_PORT_X11_2 || pi.destport == TCP_PORT_X11_3) + dissect_x11_request(pd, offset, fd, tree); + else + dissect_x11_event(pd, offset, fd, tree); +} + +/* Register the protocol with Ethereal */ +void proto_register_x11(void) +{ + +/* Setup list of header fields */ + static hf_register_info hf[] = { +/* + { &hf_x11_FIELDABBREV, + { "FIELDNAME", "x11.FIELDABBREV", + FIELDTYPE, FIELDBASE, FIELDCONVERT, BITMASK, + "FIELDDESCR" } + }, +*/ +#include "packet-x11-register-info.h" + }; + +/* Setup protocol subtree array */ + static gint *ett[] = { + &ett_x11, + &ett_x11_request, + }; + +/* Register the protocol name and description */ + proto_x11 = proto_register_protocol("X11", "x11"); + +/* Required function calls to register the header fields and subtrees used */ + proto_register_field_array(proto_x11, hf, array_length(hf)); + proto_register_subtree_array(ett, array_length(ett)); + + byte_ordering_cache = g_tree_new(compareAddresses); + address_chunk = g_mem_chunk_new("x11 byte ordering address cache", sizeof(address), + sizeof(address) * 128, G_ALLOC_ONLY); + ipv4_chunk = g_mem_chunk_new("x11 byte ordering ipv4 address cache", 4, 4 * 128, G_ALLOC_ONLY); + ipv6_chunk = g_mem_chunk_new("x11 byte ordering ipv6 address cache", 16, 16 * 128, G_ALLOC_ONLY); +}; + + +void +proto_reg_handoff_x11(void) +{ + dissector_add("tcp.port", TCP_PORT_X11, dissect_x11); + dissector_add("tcp.port", TCP_PORT_X11_2, dissect_x11); + dissector_add("tcp.port", TCP_PORT_X11_3, dissect_x11); +} |