eb2d6593dc
arguments to "proto_tree_add_text()", and to "proto_tree_add_XXX()" calls that add FT_NONE or FT_PROTO items to the protocol tree, with -1. Replace some calls to "tvb_length()" or "tvb_length_remaining()" with calls to "tvb_reported_length()" and "tvb_reported_length_remaining()", as those give the actual length of the data in the packet, not just the data that happened to be captured. svn path=/trunk/; revision=4605
2951 lines
82 KiB
C
2951 lines
82 KiB
C
/* packet-x11.c
|
|
* Routines for X11 dissection
|
|
* Copyright 2000, Christophe Tronche <ch.tronche@computer.org>
|
|
*
|
|
* $Id: packet-x11.c,v 1.29 2002/01/24 09:20:52 guy Exp $
|
|
*
|
|
* Ethereal - Network traffic analyzer
|
|
* By Gerald Combs <gerald@ethereal.com>
|
|
* 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 <assert.h>
|
|
#include <ctype.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#ifdef HAVE_SYS_TYPES_H
|
|
# include <sys/types.h>
|
|
#endif
|
|
|
|
#include <string.h>
|
|
#include <glib.h>
|
|
#include <epan/packet.h>
|
|
|
|
#define cVALS(x) (const value_string*)(x)
|
|
|
|
/* Initialize the protocol and registered fields */
|
|
static int proto_x11 = -1;
|
|
|
|
#include "x11-declarations.h"
|
|
|
|
/* Initialize the subtree pointers */
|
|
static gint ett_x11 = -1;
|
|
static gint ett_x11_request = -1;
|
|
|
|
static dissector_handle_t data_handle;
|
|
|
|
#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[] = {
|
|
{ 0xFFFFFFFF, "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 int cur_offset; /* The current offset in the frame */
|
|
static int next_offset = 0; /* Offset of the next request in the frame */
|
|
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 VALUE8(tvb, offset) (tvb_get_guint8(tvb, offset))
|
|
#define VALUE16(tvb, offset) (little_endian ? tvb_get_letohs(tvb, offset) : tvb_get_ntohs(tvb, offset))
|
|
#define VALUE32(tvb, offset) (little_endian ? tvb_get_letohl(tvb, offset) : tvb_get_ntohl(tvb, offset))
|
|
|
|
#define FIELD8(name) (field8(tvb, hf_x11_##name))
|
|
#define FIELD16(name) (field16(tvb, hf_x11_##name))
|
|
#define FIELD32(name) (field32(tvb, hf_x11_##name))
|
|
|
|
#define BITFIELD(TYPE, position, name) {\
|
|
if (lastMask._value & proto_registrar_get_nth(hf_x11_##position##_##name) -> bitmask) {\
|
|
int unused;\
|
|
int save = cur_offset;\
|
|
proto_tree_add_item(lastMask._tree, hf_x11_##position##_##name, tvb, lastMask._offset, \
|
|
lastMask._zone, little_endian); \
|
|
TYPE(name);\
|
|
unused = save + 4 - cur_offset;\
|
|
if (unused)\
|
|
proto_tree_add_item(t, hf_x11_unused, tvb, cur_offset, unused, little_endian);\
|
|
cur_offset = 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(tvb, t, hf_x11_##name); }
|
|
#define BITGRAVITY(name) { gravity(tvb, #name, hf_x11_##name, "Forget"); }
|
|
#define BITMASK8(name) { bitmask(tvb, hf_x11_##name##_mask, 1); }
|
|
#define BITMASK16(name) { bitmask(tvb, hf_x11_##name##_mask, 2); }
|
|
#define BITMASK32(name) { bitmask(tvb, hf_x11_##name##_mask, 4); }
|
|
#define BOOL(name) (add_boolean(tvb, #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(tvb, 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(tvb, hf_x11_##name, (next_offset - cur_offset) / 12); }
|
|
#define LISTofATOM(name, length) { listOfAtom(tvb, hf_x11_##name, (length) / 4); }
|
|
#define LISTofBYTE(name, length) { listOfByte(tvb, hf_x11_##name, (length)); }
|
|
#define LISTofCARD8(name, length) { listOfByte(tvb, hf_x11_##name, (length)); }
|
|
#define LISTofCARD32(name, length) { listOfCard32(tvb, hf_x11_##name, hf_x11_##name##_item, (length) / 4); }
|
|
#define LISTofCOLORITEM(name, length) { listOfColorItem(tvb, hf_x11_##name, (length) / 12); }
|
|
#define LISTofKEYCODE(name, length) { listOfKeycode(tvb, hf_x11_##name, (length)); }
|
|
#define LISTofKEYSYM(name, keycode_count, keysyms_per_keycode) { \
|
|
listOfKeysyms(tvb, hf_x11_##name, hf_x11_##name##_item, (keycode_count), (keysyms_per_keycode)); }
|
|
#define LISTofPOINT(name, length) { listOfPoint(tvb, hf_x11_##name, (length) / 4); }
|
|
#define LISTofRECTANGLE(name) { listOfRectangle(tvb, hf_x11_##name, (next_offset - cur_offset) / 8); }
|
|
#define LISTofSEGMENT(name) { listOfSegment(tvb, hf_x11_##name, (next_offset - cur_offset) / 8); }
|
|
#define LISTofSTRING8(name, length) { listOfString8(tvb, hf_x11_##name, hf_x11_##name##_string, (length)); }
|
|
#define LISTofTEXTITEM8(name) { listOfTextItem(tvb, hf_x11_##name, FALSE); }
|
|
#define LISTofTEXTITEM16(name) { listOfTextItem(tvb, hf_x11_##name, TRUE); }
|
|
#define OPCODE() { opcode = FIELD8(opcode); }
|
|
#define PIXMAP(name) { FIELD32(name); }
|
|
#define REQUEST_LENGTH() (requestLength(tvb))
|
|
#define SETofEVENT(name) { setOfEvent(tvb); }
|
|
#define SETofDEVICEEVENT(name) { setOfDeviceEvent(tvb);}
|
|
#define SETofKEYMASK(name) { setOfKeyMask(tvb); }
|
|
#define SETofPOINTEREVENT(name) { setOfPointerEvent(tvb); }
|
|
#define STRING8(name, length) { string8(tvb, #name, hf_x11_##name, length); }
|
|
#define STRING16(name, length) { string16(tvb, hf_x11_##name, hf_x11_##name##_bytes, length); }
|
|
#define TIMESTAMP(name){ timestamp(tvb, #name, hf_x11_##name); }
|
|
#define UNDECODED(x) { proto_tree_add_item(t, hf_x11_undecoded, tvb, cur_offset, x, little_endian); p += x; }
|
|
#define UNUSED(x) { proto_tree_add_item(t, hf_x11_unused, tvb, cur_offset, x, little_endian); cur_offset += x; }
|
|
#define PAD() { if (next_offset - cur_offset > 0) proto_tree_add_item(t, hf_x11_unused, tvb, cur_offset, next_offset - cur_offset, little_endian); cur_offset = next_offset; }
|
|
#define WINDOW(name) { FIELD32(name); }
|
|
#define WINGRAVITY(name) { gravity(tvb, #name, hf_x11_##name, "Unmap"); }
|
|
|
|
#define VISUALID(name) { gint32 v = VALUE32(tvb, cur_offset); \
|
|
proto_tree_add_uint_format(t, hf_x11_##name, tvb, cur_offset, 4, v, "Visualid: 0x%08x%s", v, \
|
|
v ? "" : " (CopyFromParent)"); cur_offset += 4; }
|
|
|
|
/************************************************************************
|
|
*** ***
|
|
*** D E C O D I N G F I E L D S ***
|
|
*** ***
|
|
************************************************************************/
|
|
|
|
static void atom(tvbuff_t *tvb, proto_tree *t, int hf)
|
|
{
|
|
const char *interpretation = NULL;
|
|
|
|
guint32 v = VALUE32(tvb, cur_offset);
|
|
if (v >= 1 && v < array_length(atom_predefined_interpretation))
|
|
interpretation = atom_predefined_interpretation[v];
|
|
else if (v)
|
|
interpretation = "Not a predefined atom";
|
|
else {
|
|
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, cur_offset, 4, v, "%s: %u (%s)",
|
|
proto_registrar_get_nth(hf) -> name, v, interpretation);
|
|
cur_offset += 4;
|
|
}
|
|
|
|
static void bitmask(tvbuff_t *tvb, int hf, int size)
|
|
{
|
|
lastMask._value = size == 2 ? VALUE16(tvb, cur_offset) : VALUE32(tvb, cur_offset);
|
|
lastMask._offset = cur_offset;
|
|
lastMask._zone = size;
|
|
lastMask._tree = proto_tree_add_uint(t, hf, tvb, cur_offset, size, lastMask._value);
|
|
cur_offset += size;
|
|
}
|
|
|
|
static guint32 add_boolean(tvbuff_t *tvb, const char *nameAsChar, int hf)
|
|
{
|
|
guint32 v = VALUE8(tvb, cur_offset);
|
|
proto_tree_add_boolean(t, hf, tvb, cur_offset, 1, v);
|
|
cur_offset += 1;
|
|
return v;
|
|
}
|
|
|
|
static void colorFlags(tvbuff_t *tvb, proto_tree *t)
|
|
{
|
|
unsigned do_red_green_blue = VALUE8(tvb, cur_offset);
|
|
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, cur_offset, 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, cur_offset, 1,
|
|
do_red_green_blue & 0x1);
|
|
if (do_red_green_blue & 0x2)
|
|
proto_tree_add_boolean(tt, hf_x11_coloritem_flags_do_green, tvb, cur_offset, 1,
|
|
do_red_green_blue & 0x2);
|
|
if (do_red_green_blue & 0x4)
|
|
proto_tree_add_boolean(tt, hf_x11_coloritem_flags_do_blue, tvb, cur_offset, 1,
|
|
do_red_green_blue & 0x4);
|
|
if (do_red_green_blue & 0xf8)
|
|
proto_tree_add_boolean(tt, hf_x11_coloritem_flags_unused, tvb, cur_offset, 1,
|
|
do_red_green_blue & 0xf8);
|
|
} else
|
|
proto_tree_add_uint_format(t, hf_x11_coloritem_flags, tvb, cur_offset, 1, do_red_green_blue,
|
|
"flags: none");
|
|
cur_offset++;
|
|
}
|
|
|
|
static void gravity(tvbuff_t *tvb, const char *nameAsChar, int hf, const char *nullInterpretation)
|
|
{
|
|
guint8 v = VALUE8(tvb, cur_offset);
|
|
if (!v)
|
|
proto_tree_add_uint_format(t, hf, tvb, cur_offset, 1, v, "%s: 0 (%s)", nameAsChar,
|
|
nullInterpretation);
|
|
else
|
|
proto_tree_add_uint(t, hf, tvb, cur_offset, 1, v);
|
|
cur_offset += 1;
|
|
}
|
|
|
|
static void listOfArc(tvbuff_t *tvb, int hf, int length)
|
|
{
|
|
proto_tree *tt = proto_tree_add_item(t, hf, tvb, cur_offset, length * 8, little_endian);
|
|
while(length--) {
|
|
gint16 x = VALUE16(tvb, cur_offset);
|
|
gint16 y = VALUE16(tvb, cur_offset + 2);
|
|
guint16 width = VALUE16(tvb, cur_offset + 4);
|
|
guint16 height = VALUE16(tvb, cur_offset + 6);
|
|
gint16 angle1 = VALUE16(tvb, cur_offset + 8);
|
|
gint16 angle2 = VALUE16(tvb, cur_offset + 10);
|
|
|
|
proto_tree *ttt = proto_tree_add_none_format(tt, hf_x11_arc, tvb, cur_offset, 12,
|
|
"arc: %dx%d+%d+%d, angle %d -> %d (%f degrees -> %f degrees)",
|
|
width, height, x, y, angle1, angle2,
|
|
angle1 / 64.0, angle2 / 64.0);
|
|
proto_tree_add_int(ttt, hf_x11_arc_x, tvb, cur_offset, 2, x); cur_offset += 2;
|
|
proto_tree_add_int(ttt, hf_x11_arc_y, tvb, cur_offset, 2, y); cur_offset += 2;
|
|
proto_tree_add_uint(ttt, hf_x11_arc_width, tvb, cur_offset, 2, y); cur_offset += 2;
|
|
proto_tree_add_uint(ttt, hf_x11_arc_height, tvb, cur_offset, 2, y); cur_offset += 2;
|
|
proto_tree_add_int(ttt, hf_x11_arc_angle1, tvb, cur_offset, 2, y); cur_offset += 2;
|
|
proto_tree_add_int(ttt, hf_x11_arc_angle2, tvb, cur_offset, 2, y); cur_offset += 2;
|
|
}
|
|
}
|
|
|
|
static void listOfAtom(tvbuff_t *tvb, int hf, int length)
|
|
{
|
|
proto_tree *tt = proto_tree_add_item(t, hf, tvb, cur_offset, length * 4, little_endian);
|
|
while(length--) {
|
|
if (cur_offset + 4 > next_offset) {
|
|
/* List runs past end of message. */
|
|
return;
|
|
}
|
|
atom(tvb, tt, hf_x11_properties_item);
|
|
}
|
|
}
|
|
|
|
static void listOfByte(tvbuff_t *tvb, int hf, int length)
|
|
{
|
|
if (cur_offset + length > next_offset) {
|
|
/* List runs past end of message. */
|
|
length = next_offset - cur_offset;
|
|
}
|
|
if (length <= 0) length = 1;
|
|
proto_tree_add_item(t, hf, tvb, cur_offset, length, little_endian);
|
|
cur_offset += length;
|
|
}
|
|
|
|
static void listOfCard32(tvbuff_t *tvb, int hf, int hf_item, int length)
|
|
{
|
|
proto_tree *tt = proto_tree_add_item(t, hf, tvb, cur_offset, length * 4, little_endian);
|
|
while(length--) {
|
|
if (cur_offset + 4 > next_offset) {
|
|
/* List runs past end of message. */
|
|
return;
|
|
}
|
|
proto_tree_add_uint(tt, hf_item, tvb, cur_offset, 4, VALUE32(tvb, cur_offset));
|
|
cur_offset += 4;
|
|
}
|
|
}
|
|
|
|
static void listOfColorItem(tvbuff_t *tvb, int hf, int length)
|
|
{
|
|
proto_tree *tt = proto_tree_add_item(t, hf, tvb, cur_offset, 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 (cur_offset + 12 > next_offset) {
|
|
/* List runs past end of message. */
|
|
return;
|
|
}
|
|
red = VALUE16(tvb, cur_offset + 4);
|
|
green = VALUE16(tvb, cur_offset + 6);
|
|
blue = VALUE16(tvb, cur_offset + 8);
|
|
do_red_green_blue = VALUE8(tvb, cur_offset + 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_none_format(tt, hf_x11_coloritem, tvb, cur_offset, 12, "%s", buffer);
|
|
proto_tree_add_item(ttt, hf_x11_coloritem_pixel, tvb, cur_offset, 4, little_endian); cur_offset += 4;
|
|
proto_tree_add_item(ttt, hf_x11_coloritem_red, tvb, cur_offset, 2, little_endian); cur_offset += 2;
|
|
proto_tree_add_item(ttt, hf_x11_coloritem_green, tvb, cur_offset, 2, little_endian); cur_offset += 2;
|
|
proto_tree_add_item(ttt, hf_x11_coloritem_blue, tvb, cur_offset, 2, little_endian); cur_offset += 2;
|
|
colorFlags(tvb, ttt);
|
|
proto_tree_add_item(ttt, hf_x11_coloritem_unused, tvb, cur_offset, 1, little_endian); cur_offset++;
|
|
}
|
|
}
|
|
|
|
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(tvbuff_t *tvb, int hf, int length)
|
|
{
|
|
char buffer[1024];
|
|
proto_tree *tt = proto_tree_add_item(t, hf, tvb, cur_offset, length * 8, little_endian);
|
|
|
|
while(length--) {
|
|
char *bp = buffer;
|
|
const char **m;
|
|
int i;
|
|
|
|
if (cur_offset + 8 > next_offset) {
|
|
/* List runs past end of message. */
|
|
return;
|
|
}
|
|
for(i = 8, m = modifiers; i; i--, m++) {
|
|
u_char c = tvb_get_guint8(tvb, cur_offset);
|
|
cur_offset++;
|
|
if (c) bp += sprintf(bp, " %s=%d", *m, c);
|
|
}
|
|
|
|
proto_tree_add_bytes_format(tt, hf_x11_keycodes_item, tvb, cur_offset - 8, 8, tvb_get_ptr(tvb, cur_offset - 8, 8), "item: %s", buffer);
|
|
}
|
|
}
|
|
|
|
static void listOfKeysyms(tvbuff_t *tvb, int hf, int hf_item, int keycode_count, int keysyms_per_keycode)
|
|
{
|
|
proto_tree *tt = proto_tree_add_item(t, hf, tvb, cur_offset, keycode_count * keysyms_per_keycode * 4, little_endian);
|
|
proto_tree *ttt;
|
|
int i;
|
|
char buffer[128];
|
|
char *bp;
|
|
|
|
while(keycode_count--) {
|
|
if (cur_offset + keysyms_per_keycode * 4 > next_offset) {
|
|
/* List runs past end of message. */
|
|
return;
|
|
}
|
|
bp = buffer + sprintf(buffer, "keysyms:");
|
|
for(i = 0; i < keysyms_per_keycode; i++) {
|
|
bp += sprintf(bp, " %s", keysymString(VALUE32(tvb, cur_offset + i * 4)));
|
|
}
|
|
*bp = '\0';
|
|
ttt = proto_tree_add_none_format(tt, hf_item, tvb, cur_offset, keysyms_per_keycode * 4,
|
|
"%s", buffer);
|
|
for(i = keysyms_per_keycode; i; i--) {
|
|
guint32 v = VALUE32(tvb, cur_offset);
|
|
proto_tree_add_uint_format(ttt, hf_x11_keysyms_item_keysym, tvb, cur_offset, 4, v,
|
|
"keysym: 0x%08x (%s)", v, keysymString(v));
|
|
cur_offset += 4;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void listOfPoint(tvbuff_t *tvb, int hf, int length)
|
|
{
|
|
proto_tree *tt = proto_tree_add_item(t, hf, tvb, cur_offset, length * 4, little_endian);
|
|
while(length--) {
|
|
gint16 x, y;
|
|
proto_tree *ttt;
|
|
|
|
if (cur_offset + 4 > next_offset) {
|
|
/* List runs past end of message. */
|
|
return;
|
|
}
|
|
x = VALUE16(tvb, cur_offset);
|
|
y = VALUE16(tvb, cur_offset + 2);
|
|
|
|
ttt = proto_tree_add_none_format(tt, hf_x11_point, tvb, cur_offset, 4, "point: (%d,%d)", x, y);
|
|
proto_tree_add_int(ttt, hf_x11_point_x, tvb, cur_offset, 2, x); cur_offset += 2;
|
|
proto_tree_add_int(ttt, hf_x11_point_y, tvb, cur_offset, 2, y); cur_offset += 2;
|
|
}
|
|
}
|
|
|
|
static void listOfRectangle(tvbuff_t *tvb, int hf, int length)
|
|
{
|
|
proto_tree *tt = proto_tree_add_item(t, hf, tvb, cur_offset, length * 8, little_endian);
|
|
while(length--) {
|
|
gint16 x, y;
|
|
unsigned width, height;
|
|
proto_tree *ttt;
|
|
|
|
if (cur_offset + 8 > next_offset) {
|
|
/* List runs past end of message. */
|
|
return;
|
|
}
|
|
x = VALUE16(tvb, cur_offset);
|
|
y = VALUE16(tvb, cur_offset + 2);
|
|
width = VALUE16(tvb, cur_offset + 4);
|
|
height = VALUE16(tvb, cur_offset + 6);
|
|
|
|
ttt = proto_tree_add_none_format(tt, hf_x11_rectangle, tvb, cur_offset, 8,
|
|
"rectangle: %dx%d+%d+%d", width, height, x, y);
|
|
proto_tree_add_int(ttt, hf_x11_rectangle_x, tvb, cur_offset, 2, x); cur_offset += 2;
|
|
proto_tree_add_int(ttt, hf_x11_rectangle_y, tvb, cur_offset, 2, y); cur_offset += 2;
|
|
proto_tree_add_uint(ttt, hf_x11_rectangle_width, tvb, cur_offset, 2, width); cur_offset += 2;
|
|
proto_tree_add_uint(ttt, hf_x11_rectangle_height, tvb, cur_offset, 2, height); cur_offset += 2;
|
|
}
|
|
}
|
|
|
|
static void listOfSegment(tvbuff_t *tvb, int hf, int length)
|
|
{
|
|
proto_tree *tt = proto_tree_add_item(t, hf, tvb, cur_offset, length * 8, little_endian);
|
|
while(length--) {
|
|
gint16 x1, y1, x2, y2;
|
|
proto_tree *ttt;
|
|
|
|
if (cur_offset + 8 > next_offset) {
|
|
/* List runs past end of message. */
|
|
return;
|
|
}
|
|
x1 = VALUE16(tvb, cur_offset);
|
|
y1 = VALUE16(tvb, cur_offset + 2);
|
|
x2 = VALUE16(tvb, cur_offset + 4);
|
|
y2 = VALUE16(tvb, cur_offset + 6);
|
|
|
|
ttt = proto_tree_add_none_format(tt, hf_x11_segment, tvb, cur_offset, 8,
|
|
"segment: (%d,%d)-(%d,%d)", x1, y1, x2, y2);
|
|
proto_tree_add_item(ttt, hf_x11_segment_x1, tvb, cur_offset, 2, little_endian); cur_offset += 2;
|
|
proto_tree_add_item(ttt, hf_x11_segment_y1, tvb, cur_offset, 2, little_endian); cur_offset += 2;
|
|
proto_tree_add_item(ttt, hf_x11_segment_x2, tvb, cur_offset, 2, little_endian); cur_offset += 2;
|
|
proto_tree_add_item(ttt, hf_x11_segment_y2, tvb, cur_offset, 2, little_endian); cur_offset += 2;
|
|
}
|
|
}
|
|
|
|
/* XXX - the protocol tree code should handle non-printable characters.
|
|
Note that "non-printable characters" may depend on your locale.... */
|
|
static void stringCopy(char *dest, const char *source, int length)
|
|
{
|
|
u_char c;
|
|
while(length--) {
|
|
c = *source++;
|
|
if (!isgraph(c) && c != ' ') c = '.';
|
|
*dest++ = c;
|
|
}
|
|
*dest++ = '\0';
|
|
}
|
|
|
|
static void listOfString8(tvbuff_t *tvb, int hf, int hf_item, int length)
|
|
{
|
|
char *s = NULL;
|
|
guint allocated = 0;
|
|
proto_tree *tt;
|
|
int i;
|
|
|
|
/* Compute total length */
|
|
|
|
int scanning_offset = cur_offset; /* Scanning pointer */
|
|
int l;
|
|
for(i = length; i; i--) {
|
|
l = tvb_get_guint8(tvb, scanning_offset);
|
|
scanning_offset += 1 + l;
|
|
}
|
|
|
|
tt = proto_tree_add_item(t, hf, tvb, cur_offset, scanning_offset - cur_offset, little_endian);
|
|
|
|
while(length--) {
|
|
unsigned l = VALUE8(tvb, cur_offset);
|
|
if (allocated < (l + 1)) {
|
|
/* g_realloc doesn't work ??? */
|
|
g_free(s);
|
|
s = g_malloc(l + 1);
|
|
allocated = l + 1;
|
|
}
|
|
stringCopy(s, tvb_get_ptr(tvb, cur_offset + 1, l), l); /* Nothing better for now. We need a better string handling API. */
|
|
proto_tree_add_string_format(tt, hf_item, tvb, cur_offset, l + 1, s, "\"%s\"", s);
|
|
cur_offset += l + 1;
|
|
}
|
|
g_free(s);
|
|
}
|
|
|
|
#define STRING16_MAX_DISPLAYED_LENGTH 150
|
|
|
|
static int stringIsActuallyAn8BitString(tvbuff_t *tvb, int offset, unsigned length)
|
|
{
|
|
if (length > STRING16_MAX_DISPLAYED_LENGTH) length = STRING16_MAX_DISPLAYED_LENGTH;
|
|
for(; length > 0; cur_offset += 2, length--) {
|
|
if (tvb_get_guint8(tvb, cur_offset))
|
|
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(tvbuff_t *tvb, proto_tree *t,
|
|
int hf, int hf_bytes,
|
|
int offset, unsigned length,
|
|
char **s, int *sLength)
|
|
{
|
|
int truncated = FALSE;
|
|
unsigned l = length / 2;
|
|
|
|
if (stringIsActuallyAn8BitString(tvb, offset, l)) {
|
|
char *dp;
|
|
int soffset = offset;
|
|
|
|
if (l > STRING16_MAX_DISPLAYED_LENGTH) {
|
|
truncated = TRUE;
|
|
l = STRING16_MAX_DISPLAYED_LENGTH;
|
|
}
|
|
if (*sLength < (int) l + 3) {
|
|
g_free(*s);
|
|
*s = g_malloc(l + 3);
|
|
*sLength = l + 3;
|
|
}
|
|
dp = *s;
|
|
*dp++ = '"';
|
|
if (truncated) l -= 3;
|
|
|
|
while(l--) {
|
|
soffset++;
|
|
*dp++ = tvb_get_guint8(tvb, soffset);
|
|
soffset++;
|
|
}
|
|
*dp++ = '"';
|
|
|
|
/* If truncated, add an ellipsis */
|
|
if (truncated) { *dp++ = '.'; *dp++ = '.'; *dp++ = '.'; }
|
|
|
|
*dp++ = '\0';
|
|
proto_tree_add_string_format(t, hf, tvb, offset, length, tvb_get_ptr(tvb, offset, length), "%s: %s",
|
|
proto_registrar_get_nth(hf) -> name, *s);
|
|
} else
|
|
proto_tree_add_item(t, hf_bytes, tvb, offset, length, little_endian);
|
|
|
|
}
|
|
|
|
static void listOfTextItem(tvbuff_t *tvb, int hf, int sizeIs16)
|
|
{
|
|
int allocated = 0;
|
|
char *s = NULL;
|
|
proto_tree *tt;
|
|
guint32 fid;
|
|
|
|
/* Compute total length */
|
|
|
|
int scanning_offset = cur_offset; /* Scanning pointer */
|
|
int l; /* Length of an individual item */
|
|
int n = 0; /* Number of items */
|
|
|
|
while(scanning_offset < next_offset) {
|
|
l = tvb_get_guint8(tvb, scanning_offset);
|
|
scanning_offset++;
|
|
if (!l) break;
|
|
n++;
|
|
scanning_offset += l == 255 ? 4 : l + (sizeIs16 ? l : 0) + 1;
|
|
}
|
|
|
|
tt = proto_tree_add_item(t, hf, tvb, cur_offset, scanning_offset - cur_offset, little_endian);
|
|
|
|
while(n--) {
|
|
unsigned l = VALUE8(tvb, cur_offset);
|
|
if (l == 255) { /* Item is a font */
|
|
fid = tvb_get_ntohl(tvb, cur_offset + 1);
|
|
proto_tree_add_uint(tt, hf_x11_textitem_font, tvb, cur_offset, 5, fid);
|
|
cur_offset += 5;
|
|
} else { /* Item is a string */
|
|
proto_tree *ttt;
|
|
gint8 delta = VALUE8(tvb, cur_offset + 1);
|
|
if (sizeIs16) l += l;
|
|
if ((unsigned) allocated < l + 1) {
|
|
/* g_realloc doesn't work ??? */
|
|
g_free(s);
|
|
s = g_malloc(l + 1);
|
|
allocated = l + 1;
|
|
}
|
|
stringCopy(s, tvb_get_ptr(tvb, cur_offset + 2, l), l);
|
|
ttt = proto_tree_add_none_format(tt, hf_x11_textitem_string, tvb, cur_offset, l + 2,
|
|
"textitem (string): delta = %d, \"%s\"",
|
|
delta, s);
|
|
proto_tree_add_item(ttt, hf_x11_textitem_string_delta, tvb, cur_offset + 1, 1, little_endian);
|
|
if (sizeIs16)
|
|
string16_with_buffer_preallocated(tvb, ttt, hf_x11_textitem_string_string16,
|
|
hf_x11_textitem_string_string16_bytes,
|
|
cur_offset + 2, l,
|
|
&s, &allocated);
|
|
else
|
|
proto_tree_add_string_format(ttt, hf_x11_textitem_string_string8, tvb,
|
|
cur_offset + 2, l, s, "\"%s\"", s);
|
|
cur_offset += l + 2;
|
|
}
|
|
}
|
|
g_free(s);
|
|
}
|
|
|
|
static guint32 field8(tvbuff_t *tvb, int hf)
|
|
{
|
|
guint32 v = VALUE8(tvb, cur_offset);
|
|
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, cur_offset, 1, v, "%s: %u (%s)", nameAsChar, v, enumValue);
|
|
else
|
|
proto_tree_add_item(t, hf, tvb, cur_offset, 1, little_endian);
|
|
cur_offset += 1;
|
|
return v;
|
|
}
|
|
|
|
static guint32 field16(tvbuff_t *tvb, int hf)
|
|
{
|
|
guint32 v = VALUE16(tvb, cur_offset);
|
|
proto_tree_add_item(t, hf, tvb, cur_offset, 2, v);
|
|
cur_offset += 2;
|
|
return v;
|
|
}
|
|
|
|
static guint32 field32(tvbuff_t *tvb, int hf)
|
|
{
|
|
guint32 v = VALUE32(tvb, cur_offset);
|
|
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, cur_offset, 4, v, "%s: 0x%08x (%s)", nameAsChar, v, enumValue);
|
|
else
|
|
proto_tree_add_uint_format(t, hf, tvb, cur_offset, 4, v,
|
|
hfi -> display == BASE_DEC ? "%s: %u" : "%s: 0x%08x",
|
|
nameAsChar, v);
|
|
cur_offset += 4;
|
|
return v;
|
|
}
|
|
|
|
static void gcAttributes(tvbuff_t *tvb)
|
|
{
|
|
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(tvbuff_t *tvb)
|
|
{
|
|
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(tvbuff_t *tvb)
|
|
{
|
|
guint32 res = VALUE16(tvb, cur_offset) * 4;
|
|
proto_tree_add_uint(t, hf_x11_request_length, tvb, cur_offset, 2, res);
|
|
cur_offset += 2;
|
|
return res;
|
|
}
|
|
|
|
static void setOfEvent(tvbuff_t *tvb)
|
|
{
|
|
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(tvbuff_t *tvb)
|
|
{
|
|
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(tvbuff_t *tvb)
|
|
{
|
|
struct maskStruct save = lastMask;
|
|
lastMask._value = VALUE16(tvb, cur_offset);
|
|
lastMask._offset = cur_offset;
|
|
lastMask._zone = 2;
|
|
if (lastMask._value == 0x8000)
|
|
proto_tree_add_uint_format(t, hf_x11_modifiers_mask_AnyModifier, tvb, cur_offset, 2, 0x8000,
|
|
"modifiers-masks: 0x8000 (AnyModifier)");
|
|
else {
|
|
lastMask._tree = proto_tree_add_uint(t, hf_x11_modifiers_mask, tvb, cur_offset, 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;
|
|
cur_offset += 2;
|
|
}
|
|
|
|
static void setOfPointerEvent(tvbuff_t *tvb)
|
|
{
|
|
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(tvbuff_t *tvb, const char *nameAsChar, int hf, unsigned length)
|
|
{
|
|
char *s = g_malloc(length + 1);
|
|
stringCopy(s, tvb_get_ptr(tvb, cur_offset, length), length);
|
|
proto_tree_add_string_format(t, hf, tvb, cur_offset, length, s, "%s: %s", nameAsChar, s);
|
|
g_free(s);
|
|
cur_offset += length;
|
|
}
|
|
|
|
/* The length is the length of the _byte_zone_ (twice the length of the string) */
|
|
|
|
static void string16(tvbuff_t *tvb, int hf, int hf_bytes, unsigned length)
|
|
{
|
|
char *s = NULL;
|
|
unsigned l = 0;
|
|
length += length;
|
|
string16_with_buffer_preallocated(tvb, t, hf, hf_bytes, cur_offset, length, &s, &l);
|
|
g_free(s);
|
|
cur_offset += length;
|
|
}
|
|
|
|
static void timestamp(tvbuff_t *tvb, const char *nameAsChar, int hf)
|
|
{
|
|
guint32 v = VALUE32(tvb, cur_offset);
|
|
if (!v)
|
|
proto_tree_add_uint_format(t, hf, tvb, cur_offset, 4, 0, "%s: 0 (CurrentTime)", nameAsChar);
|
|
else
|
|
proto_tree_add_uint(t, hf, tvb, cur_offset, 4, v);
|
|
cur_offset += 4;
|
|
}
|
|
|
|
static void windowAttributes(tvbuff_t *tvb)
|
|
{
|
|
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 int dissect_x11_request_loop(tvbuff_t *tvb, proto_tree *root)
|
|
{
|
|
int left = tvb_reported_length(tvb), nextLeft;
|
|
proto_item *ti;
|
|
guint8 v8, v8_2;
|
|
guint16 v16;
|
|
guint32 v32;
|
|
|
|
/* The X11 data stream to the server is just a sequence of requests,
|
|
each of which contains a length; for now, we dissect all the
|
|
requests in this frame until we run out of data in the frame.
|
|
Eventually, we should handle requests that cross frame
|
|
boundaries.
|
|
|
|
Note that "in this frame" refers to everything in the frame
|
|
as it appeared in the wire, not as it was captured; we want
|
|
an exception to be thrown if we go past the end of the
|
|
captured data in the frame without going past the end of the
|
|
data in the frame. */
|
|
for(;;) {
|
|
int length, opcode;
|
|
|
|
/* fprintf(stderr, "Starting loop, left = %d, cur_offset = %d\n", left, cur_offset); */
|
|
if (left < 4) {
|
|
/* We ran out of data - we don't have enough data in
|
|
the frame to get the length of this request. */
|
|
break;
|
|
}
|
|
length = VALUE16(tvb, cur_offset + 2) * 4;
|
|
/* fprintf(stderr, "length = %d\n", length);*/
|
|
if (left < length) {
|
|
/* We ran out of data - we don't have enough data in
|
|
the frame for the full request. */
|
|
break;
|
|
}
|
|
if (length < 4) {
|
|
/* Bogus message length? */
|
|
break;
|
|
}
|
|
|
|
next_offset = cur_offset + length;
|
|
nextLeft = left - length;
|
|
|
|
ti = proto_tree_add_uint(root, hf_x11_request, tvb, cur_offset, length, tvb_get_guint8(tvb, cur_offset));
|
|
t = proto_item_add_subtree(ti, ett_x11_request);
|
|
|
|
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(tvb);
|
|
break;
|
|
|
|
case 2: /* ChangeWindowAttributes */
|
|
UNUSED(1);
|
|
REQUEST_LENGTH();
|
|
WINDOW(window);
|
|
windowAttributes(tvb);
|
|
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, (next_offset - cur_offset - (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(tvb);
|
|
break;
|
|
|
|
case 56: /* ChangeGC */
|
|
UNUSED(1);
|
|
REQUEST_LENGTH();
|
|
GCONTEXT(gc);
|
|
gcAttributes(tvb);
|
|
break;
|
|
|
|
case 57: /* CopyGC */
|
|
UNUSED(1);
|
|
REQUEST_LENGTH();
|
|
GCONTEXT(src_gc);
|
|
GCONTEXT(dst_gc);
|
|
gcMask(tvb);
|
|
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 (cur_offset < next_offset)
|
|
proto_tree_add_item(t, hf_x11_undecoded, tvb, cur_offset, next_offset - cur_offset, little_endian);
|
|
cur_offset = next_offset;
|
|
left = nextLeft;
|
|
}
|
|
|
|
return left;
|
|
}
|
|
|
|
/************************************************************************
|
|
*** ***
|
|
*** 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...
|
|
*/
|
|
|
|
int numberOfBitSetTable[] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 };
|
|
|
|
int numberOfBitSet(tvbuff_t *tvb, int offset, int maskLength)
|
|
{
|
|
int res = 0;
|
|
while(maskLength--) {
|
|
int c = tvb_get_guint8(tvb, offset);
|
|
offset++;
|
|
res += numberOfBitSetTable[c & 0xf] + numberOfBitSetTable[c >> 4];
|
|
}
|
|
return res;
|
|
}
|
|
|
|
static int listOfStringLengthConsistent(tvbuff_t *tvb, int offset, int length, int listLength)
|
|
{
|
|
if (listLength > length) return FALSE;
|
|
while(listLength--) {
|
|
int l;
|
|
if (!tvb_bytes_exist(tvb, offset, 1)) return TRUE;
|
|
l = tvb_get_guint8(tvb, offset);
|
|
if (!l) break;
|
|
l++;
|
|
if (l > length) return FALSE;
|
|
if (!tvb_bytes_exist(tvb, offset, l)) return TRUE;
|
|
offset += l;
|
|
length -= 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, tvbuff_t *tvb, int offset, guint16 (*v16)(tvbuff_t *, gint))
|
|
{
|
|
switch(tvb_get_guint8(tvb, offset)) {
|
|
case 1: /* CreateWindow */
|
|
return !tvb_bytes_exist(tvb, offset, 32) || length == 8 + numberOfBitSet(tvb, offset + 7 * 4, 4);
|
|
|
|
case 2: /* ChangeWindowAttributes */
|
|
case 56: /* ChangeGC */
|
|
return !tvb_bytes_exist(tvb, offset, 12) || length == 3 + numberOfBitSet(tvb, offset + 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 !tvb_bytes_exist(tvb, offset, 10) || length == 3 + numberOfBitSet(tvb, offset + 8, 2);
|
|
|
|
case 16: /* InternAtom */
|
|
case 98: /* QueryExtension */
|
|
return !tvb_bytes_exist(tvb, offset, 6) || length == 2 + rounded4(v16(tvb, offset + 4));
|
|
|
|
case 18: /* ChangeProperty */
|
|
{
|
|
int multiplier, type;
|
|
if (!tvb_bytes_exist(tvb, offset, 17)) return TRUE;
|
|
type = tvb_get_guint8(tvb, 16);
|
|
if (type != 8 && type != 16 && type != 32) return FALSE;
|
|
multiplier = type == 8 ? 1 : type == 16 ? 2 : 4;
|
|
if (!tvb_bytes_exist(tvb, offset, 24)) return TRUE;
|
|
return length == 6 + rounded4((v16 == tvb_get_letohs ? tvb_get_letohl : tvb_get_ntohl)(tvb, offset + 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 !tvb_bytes_exist(tvb, offset, 10) || length == 3 + rounded4(v16(tvb, offset + 8));
|
|
|
|
case 48: /* QueryTextExtents */
|
|
return length >= 2;
|
|
|
|
case 49: /* ListFonts */
|
|
case 50: /* ListFontsWithInfo */
|
|
case 109: /* ChangeHosts */
|
|
return !tvb_bytes_exist(tvb, offset, 8) || length == 2 + rounded4(v16(tvb, offset + 6));
|
|
|
|
case 51: /* SetFontPath */
|
|
if (length < 2) return FALSE;
|
|
if (!tvb_bytes_exist(tvb, offset, 8)) return TRUE;
|
|
return listOfStringLengthConsistent(tvb, offset + 8, (length - 2) * 4, v16(tvb, offset + 4));
|
|
|
|
case 55: /* CreateGC */
|
|
return !tvb_bytes_exist(tvb, offset, 16) || length == 4 + numberOfBitSet(tvb, offset + 12, 4);
|
|
|
|
case 58: /* SetDashes */
|
|
return !tvb_bytes_exist(tvb, offset, 12) || length == 3 + rounded4(v16(tvb, offset + 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 !tvb_bytes_exist(tvb, offset, 14) || length == 4 + rounded4(v16(tvb, offset + 12));
|
|
|
|
case 91: /* QueryColors */
|
|
return length >= 2;
|
|
|
|
case 100: /* ChangeKeyboardMapping */
|
|
return !tvb_bytes_exist(tvb, offset, 6) || length == 2 + tvb_get_guint8(tvb, 1) * tvb_get_guint8(tvb, 5);
|
|
|
|
case 102: /* ChangeKeyboardControl */
|
|
return !tvb_bytes_exist(tvb, offset, 6) || length == 2 + numberOfBitSet(tvb, offset + 4, 2);
|
|
|
|
case 114: /* RotateProperties */
|
|
return !tvb_bytes_exist(tvb, offset, 10) || length == 3 + v16(tvb, offset + 8);
|
|
|
|
case 116: /* SetPointerMapping */
|
|
return length == 1 + rounded4(tvb_get_guint8(tvb, 1));
|
|
|
|
case 118: /* SetModifierMapping */
|
|
return length == 1 + tvb_get_guint8(tvb, 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(tvbuff_t *tvb, guint16 (*v16)(tvbuff_t *, gint))
|
|
{
|
|
int offset, nextoffset;
|
|
int atLeastOne = 0;
|
|
|
|
for(offset = 0; tvb_bytes_exist(tvb, offset, 4); offset = nextoffset) {
|
|
int length;
|
|
length = v16(tvb, offset + 2);
|
|
if (!length) return -1;
|
|
nextoffset = offset + length * 4;
|
|
if (!consistentWithOrder(length, tvb, offset, v16)) return -1;
|
|
atLeastOne = 1;
|
|
}
|
|
return atLeastOne;
|
|
}
|
|
|
|
static gboolean
|
|
guess_byte_ordering(tvbuff_t *tvb, packet_info *pinfo)
|
|
{
|
|
/* 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;
|
|
|
|
gboolean is_reply = (pinfo->srcport == pinfo->match_port);
|
|
address *addr = is_reply ? &pinfo->net_dst : &pinfo->net_src;
|
|
gint32 cache = GPOINTER_TO_INT(g_tree_lookup(byte_ordering_cache, addr));
|
|
if (cache) return cache > 0 ? TRUE : FALSE;
|
|
if (is_reply) return TRUE; /* We don't try to guess on a reply / event for now */
|
|
|
|
le = x_endian_match(tvb, tvb_get_letohs);
|
|
be = x_endian_match(tvb, tvb_get_ntohs);
|
|
|
|
/* 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 (!tvb_bytes_exist(tvb, 0, 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 = tvb_get_letohs(tvb, 2) <= tvb_get_ntohs(tvb, 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",
|
|
pinfo->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(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
|
|
{
|
|
/* Set up structures we will need to add the protocol subtree and manage it */
|
|
proto_item *ti;
|
|
proto_tree *x11_tree;
|
|
int left;
|
|
|
|
/* 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. */
|
|
if (check_col(pinfo->cinfo, COL_INFO))
|
|
col_set_str(pinfo->cinfo, 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;
|
|
ti = proto_tree_add_item(tree, proto_x11, tvb, 0, -1, FALSE);
|
|
x11_tree = proto_item_add_subtree(ti, ett_x11);
|
|
|
|
cur_offset = 0;
|
|
little_endian = guess_byte_ordering(tvb, pinfo);
|
|
left = dissect_x11_request_loop(tvb, x11_tree);
|
|
if (left)
|
|
call_dissector(data_handle,tvb_new_subset(tvb, cur_offset,-1, tvb_reported_length_remaining(tvb,cur_offset)), pinfo, x11_tree);
|
|
}
|
|
|
|
static void
|
|
dissect_x11_event(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
|
|
{
|
|
/* Set up structures we will need to add the protocol subtree and manage it */
|
|
proto_item *ti;
|
|
proto_tree *x11_tree;
|
|
|
|
/* 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. */
|
|
if (check_col(pinfo->cinfo, COL_INFO))
|
|
col_set_str(pinfo->cinfo, 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) {
|
|
ti = proto_tree_add_item(tree, proto_x11, tvb, 0, -1, FALSE);
|
|
x11_tree = proto_item_add_subtree(ti, ett_x11);
|
|
|
|
/* Code to process the packet goes here */
|
|
|
|
call_dissector(data_handle,tvb, pinfo, x11_tree);
|
|
}
|
|
}
|
|
|
|
static void
|
|
dissect_x11(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
|
|
{
|
|
if (check_col(pinfo->cinfo, COL_PROTOCOL))
|
|
col_set_str(pinfo->cinfo, COL_PROTOCOL, "X11");
|
|
|
|
if (pinfo->match_port == pinfo->destport)
|
|
dissect_x11_request(tvb, pinfo, tree);
|
|
else
|
|
dissect_x11_event(tvb, pinfo, 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", HFILL }
|
|
},
|
|
*/
|
|
#include "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", "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_handle_t x11_handle;
|
|
|
|
x11_handle = create_dissector_handle(dissect_x11, proto_x11);
|
|
dissector_add("tcp.port", TCP_PORT_X11, x11_handle);
|
|
dissector_add("tcp.port", TCP_PORT_X11_2, x11_handle);
|
|
dissector_add("tcp.port", TCP_PORT_X11_3, x11_handle);
|
|
data_handle = find_dissector("data");
|
|
}
|