Permalink
Browse files

Major refactor of packet builder

I decided to ditch the Packet class name and go with a Form module
that contains a BaseForm which child classes inherit from.

I've created a few tests so you can see how the BaseForm class
works and how packets can be read and sent over a socket to
an X11 server
  • Loading branch information...
1 parent a503b83 commit ad10e78306cfc4136b5dd762feb11ced2a7bdc6e @rramsden committed May 21, 2012
Showing with 274 additions and 236 deletions.
  1. +208 −0 lib/X11/form.rb
  2. +0 −102 lib/X11/packet.rb
  3. +0 −84 lib/X11/packets/display.rb
  4. +66 −0 test/form_test.rb
  5. +0 −50 test/packet_test.rb
View
@@ -0,0 +1,208 @@
+module X11
+ module Form
+ # A form object is an X11 packet definition. We use forms to encode
+ # and decode X11 packets as we send and receive them over a socket.
+ #
+ # We can create a packet definition as follows:
+ #
+ # class Point < BaseForm
+ # field :x, Int8
+ # field :y, Int8
+ # end
+ #
+ # p = Point.new(10,20)
+ # p.x => 10
+ # p.y => 20
+ # p.to_packet => "\n\x14"
+ #
+ # You can also read from a socket:
+ #
+ # Point.from_packet(socket) => #<Point @x=10 @y=20>
+ #
+ class BaseForm
+ include X11::Type
+
+ # initialize field accessors
+ def initialize(*params)
+ self.class.fields.each do |f|
+ param = params.shift
+ instance_variable_set("@#{f.name}", param)
+ end
+ end
+
+ def to_packet
+ # fetch class level instance variable holding defined fields
+ structs = self.class.instance_variable_get("@structs")
+
+ packet = structs.map do |s|
+ # fetch value of field set in initialization
+ value = instance_variable_get("@#{s.name}")
+
+ case s.type
+ when :field
+ if value.is_a?(BaseForm)
+ value.to_packet
+ else
+ s.type_klass.pack(value)
+ end
+ when :unused
+ "\x00" * s.size
+ when :length
+ s.type_klass.pack(value.size)
+ when :string
+ s.type_klass.pack(value)
+ when :list
+ value.collect do |obj|
+ obj.to_packet
+ end
+ end
+ end.join
+ end
+
+ class << self
+ def from_packet(socket)
+ # fetch class level instance variable holding defined fields
+
+ form = new
+ lengths = {}
+
+ @structs.each do |s|
+ case s.type
+ when :field
+ val = if s.type_klass.superclass == BaseForm
+ s.type_klass.from_packet(socket)
+ else
+ s.type_klass.unpack( socket.read(s.type_klass.size) )
+ end
+ form.instance_variable_set("@#{s.name}", val)
+ when :unused
+ socket.read(s.size)
+ when :length
+ size = s.type_klass.unpack( socket.read(s.type_klass.size) )
+ lengths[s.name] = size
+ when :string
+ val = s.type_klass.unpack(socket, lengths[s.name])
+ form.instance_variable_set("@#{s.name}", val)
+ when :list
+ val = lengths[s.name].times.collect do
+ s.type_klass.from_packet(socket)
+ end
+ form.instance_variable_set("@#{s.name}", val)
+ end
+ end
+
+ return form
+ end
+
+ def field(*args)
+ name, type_klass, type = args
+ class_eval { attr_accessor name }
+
+ s = OpenStruct.new
+ s.name = name
+ s.type = (type == nil ? :field : type)
+ s.type_klass = type_klass
+
+ @structs ||= []
+ @structs << s
+ end
+
+ def unused(size)
+ s = OpenStruct.new
+ s.size = size
+ s.type = :unused
+
+ @structs ||= []
+ @structs << s
+ end
+
+ def fields
+ @structs.dup.delete_if{|s| s.type == :unused or s.type == :length}
+ end
+ end
+ end
+
+ ##
+ ## X11 Packet Defintions
+ ##
+
+ class ClientHandshake < BaseForm
+ field :byte_order, Uint8
+ unused 1
+ field :protocol_major_version, Uint16
+ field :protocol_minor_version, Uint16
+ field :auth_proto_name, Uint16, :length
+ field :auth_proto_data, Uint16, :length
+ unused 2
+ field :auth_proto_name, String8, :string
+ field :auth_proto_data, String8, :string
+ end
+
+ class FormatInfo < BaseForm
+ field :depth, Uint8
+ field :bits_per_pixel, Uint8
+ field :scanline_pad, Uint8
+ unused 5
+ end
+
+ class VisualInfo < BaseForm
+ field :visual_id, VisualID
+ field :qlass, Uint8
+ field :bits_per_rgb_value, Uint8
+ field :colormap_entries, Uint16
+ field :red_mask, Uint32
+ field :green_mask, Uint32
+ field :blue_mask, Uint32
+ unused 4
+ end
+
+ class DepthInfo < BaseForm
+ field :depth, Uint8
+ unused 1
+ field :visuals, Uint16, :length
+ unused 4
+ field :visuals, VisualInfo, :list
+ end
+
+ class ScreenInfo < BaseForm
+ field :root, Window
+ field :default_colormap, Colormap
+ field :white_pixel, Colornum
+ field :black_pixel, Colornum
+ field :current_input_masks, Mask
+ field :width_in_pixels, Uint16
+ field :height_in_pixels, Uint16
+ field :width_in_millimeters, Uint16
+ field :height_in_millimeters, Uint16
+ field :min_installed_maps, Uint16
+ field :max_installed_maps, Uint16
+ field :root_visual, VisualID
+ field :backing_stores, Uint8
+ field :save_unders, Bool
+ field :root_depth, Uint8
+ field :depths, Uint8,:length
+ field :depths, DepthInfo, :list
+ end
+
+ class DisplayInfo < BaseForm
+ field :release_number, Uint32
+ field :resource_id_base, Uint32
+ field :resource_id_mask, Uint32
+ field :motion_buffer_size, Uint32
+ field :vendor, Uint16, :length
+ field :maximum_request_length, Uint16
+ field :screens, Uint8, :length
+ field :formats, Uint8, :length
+ field :image_byte_order, Signifigance
+ field :bitmap_bit_order, Signifigance
+ field :bitmap_format_scanline_unit, Uint8
+ field :bitmap_format_scanline_pad, Uint8
+ field :min_keycode, KeyCode
+ field :max_keycode, KeyCode
+ unused 4
+ field :vendor, String8, :string
+ field :formats, FormatInfo, :list
+ field :screens, ScreenInfo, :list
+ end
+ end
+end
View
@@ -1,102 +0,0 @@
-module X11
- module Packet
-
- class BasePacket
- include X11::Type
-
- class << self
- def create(*parameters)
- lengths = lengths_for(parameters)
-
- packet = @structs.map do |s|
- case s.type
- when :field
- s.type_klass.pack(parameters.shift)
- when :unused
- "\x00" * s.size
- when :length
- s.type_klass.pack(lengths[s.name])
- when :string
- s.type_klass.pack(parameters.shift)
- when :list
- parameters.shift.each do |obj|
- s.type_klass.create(*obj)
- end
- end
- end
-
- ((@opcode ? [X11::Type::Int8.pack(@opcode)] : []) + packet).join
- end
-
- def read(socket)
- lengths = {}
- values = {}
-
- @structs.each do |s|
- case s.type
- when :field
- values[s.name] = s.type_klass.unpack( socket.read(s.type_klass.size) )
- when :unused
- socket.read(s.size)
- when :length
- size = s.type_klass.unpack( socket.read(s.type_klass.size) )
- lengths[s.name] = size
- when :string
- values[s.name] = s.type_klass.unpack(socket, lengths[s.name])
- when :list
- values[s.name] = lengths[s.name].times.collect do
- s.type_klass.read(socket)
- end
- end
- end
-
- OpenStruct.new(values)
- end
-
- def field(*args)
- name, type_klass, type = args
- s = Struct.new(:name, :type_klass, :type).new
- s.name = name
- s.type = (type == nil ? :field : type)
- s.type_klass = type_klass
-
- @structs ||= []
- @structs << s
- end
-
- def unused(size)
- s = Struct.new(:size, :type).new
- s.size = size
- s.type = :unused
-
- @structs ||= []
- @structs << s
- end
-
- def opcode(value)
- @opcode = value
- end
-
- private
-
- def lengths_for(args)
- args = args.dup
- lengths = {}
-
- fields.each do |s|
- value = args.shift
- lengths[s.name] = value.size if s.type == :list or s.type == :string
- end
-
- return lengths
- end
-
- def fields
- @structs.dup.delete_if do |s|
- s.type == :unused or s.type == :length
- end
- end
- end
- end
- end
-end
View
@@ -1,84 +0,0 @@
-module X11
- module Packet
-
- class ClientHandshake < BasePacket
- field :byte_order, Uint8
- unused 1
- field :protocol_major_version, Uint16
- field :protocol_minor_version, Uint16
- field :auth_proto_name, Uint16, :length
- field :auth_proto_data, Uint16, :length
- unused 2
- field :auth_proto_name, String8, :string
- field :auth_proto_data, String8, :string
- end
-
- class FormatInfo < BasePacket
- field :depth, Uint8
- field :bits_per_pixel, Uint8
- field :scanline_pad, Uint8
- unused 5
- end
-
- class VisualInfo < BasePacket
- field :visual_id, VisualID
- field :qlass, Uint8
- field :bits_per_rgb_value, Uint8
- field :colormap_entries, Uint16
- field :red_mask, Uint32
- field :green_mask, Uint32
- field :blue_mask, Uint32
- unused 4
- end
-
- class DepthInfo < BasePacket
- field :depth, Uint8
- unused 1
- field :visuals, Uint16, :length
- unused 4
- field :visuals, VisualInfo, :list
- end
-
- class ScreenInfo < BasePacket
- field :root, Window
- field :default_colormap, Colormap
- field :white_pixel, Colornum
- field :black_pixel, Colornum
- field :current_input_masks, EventMask
- field :width_in_pixels, Uint16
- field :height_in_pixels, Uint16
- field :width_in_millimeters, Uint16
- field :height_in_millimeters, Uint16
- field :min_installed_maps, Uint16
- field :max_installed_maps, Uint16
- field :root_visual, VisualID
- field :backing_stores, Uint8
- field :save_unders, Bool
- field :root_depth, Uint8
- field :depths, Uint8,:length
- field :depths, DepthInfo, :list
- end
-
- class DisplayInfo < BasePacket
- field :release_number, Uint32
- field :resource_id_base, Uint32
- field :resource_id_mask, Uint32
- field :motion_buffer_size, Uint32
- field :vendor, Uint16, :length
- field :maximum_request_length, Uint16
- field :screens, Uint8, :length
- field :formats, Uint8, :length
- field :image_byte_order, Signifigance
- field :bitmap_bit_order, Signifigance
- field :bitmap_format_scanline_unit, Uint8
- field :bitmap_format_scanline_pad, Uint8
- field :min_keycode, KeyCode
- field :max_keycode, KeyCode
- unused 4
- field :vendor, String8, :string
- field :formats, FormatInfo, :list
- field :screens, ScreenInfo, :list
- end
-
- end
-end
Oops, something went wrong.

0 comments on commit ad10e78

Please sign in to comment.