steam-condenser 0.13.1 → 0.14.0
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/exceptions/packet_format_exception.rb +12 -5
- data/lib/exceptions/rcon_ban_exception.rb +11 -3
- data/lib/exceptions/rcon_no_auth_exception.rb +10 -3
- data/lib/exceptions/steam_condenser_exception.rb +8 -5
- data/lib/exceptions/timeout_exception.rb +13 -3
- data/lib/exceptions/web_api_exception.rb +31 -23
- data/lib/steam-condenser.rb +9 -3
- data/lib/steam-condenser/community.rb +8 -1
- data/lib/steam-condenser/servers.rb +7 -1
- data/lib/steam-condenser/version.rb +2 -1
- data/lib/steam/community/cacheable.rb +4 -4
- data/lib/steam/community/game_inventory.rb +119 -0
- data/lib/steam/community/game_item.rb +38 -0
- data/lib/steam/community/game_stats.rb +10 -4
- data/lib/steam/community/portal2/portal2_inventory.rb +21 -0
- data/lib/steam/community/portal2/portal2_item.rb +35 -0
- data/lib/steam/community/portal2/portal2_stats.rb +28 -0
- data/lib/steam/community/tf2/tf2_inventory.rb +7 -37
- data/lib/steam/community/tf2/tf2_item.rb +8 -79
- data/lib/steam/community/tf2/tf2_stats.rb +10 -13
- data/lib/steam/community/web_api.rb +1 -0
- data/lib/steam/packets/a2m_get_servers_batch2_packet.rb +37 -4
- data/lib/steam/packets/a2s_info_packet.rb +10 -5
- data/lib/steam/packets/a2s_player_packet.rb +16 -6
- data/lib/steam/packets/a2s_rules_packet.rb +16 -4
- data/lib/steam/packets/a2s_serverquery_getchallenge_packet.rb +11 -5
- data/lib/steam/packets/c2m_checkmd5_packet.rb +10 -4
- data/lib/steam/packets/m2a_server_batch_packet.rb +19 -3
- data/lib/steam/packets/m2c_isvalidmd5_packet.rb +14 -5
- data/lib/steam/packets/m2s_requestrestart_packet.rb +14 -4
- data/lib/steam/packets/rcon/rcon_auth_request.rb +15 -3
- data/lib/steam/packets/rcon/rcon_auth_response.rb +17 -3
- data/lib/steam/packets/rcon/rcon_exec_request.rb +15 -3
- data/lib/steam/packets/rcon/rcon_exec_response.rb +20 -3
- data/lib/steam/packets/rcon/rcon_goldsrc_request.rb +18 -3
- data/lib/steam/packets/rcon/rcon_goldsrc_response.rb +17 -3
- data/lib/steam/packets/rcon/rcon_packet.rb +31 -3
- data/lib/steam/packets/rcon/rcon_packet_factory.rb +15 -5
- data/lib/steam/packets/rcon/rcon_terminator.rb +14 -5
- data/lib/steam/packets/request_with_challenge.rb +10 -5
- data/lib/steam/packets/s2a_info2_packet.rb +14 -5
- data/lib/steam/packets/s2a_info_base_packet.rb +16 -6
- data/lib/steam/packets/s2a_info_detailed_packet.rb +15 -8
- data/lib/steam/packets/s2a_logstring_packet.rb +11 -5
- data/lib/steam/packets/s2a_player_packet.rb +14 -6
- data/lib/steam/packets/s2a_rules_packet.rb +15 -5
- data/lib/steam/packets/s2c_challenge_packet.rb +17 -6
- data/lib/steam/packets/s2m_heartbeat2_packet.rb +18 -4
- data/lib/steam/packets/steam_packet.rb +14 -5
- data/lib/steam/packets/steam_packet_factory.rb +25 -2
- data/lib/steam/servers/game_server.rb +154 -25
- data/lib/steam/servers/goldsrc_server.rb +35 -3
- data/lib/steam/servers/master_server.rb +77 -23
- data/lib/steam/servers/server.rb +42 -3
- data/lib/steam/servers/source_server.rb +35 -11
- data/lib/stringio_additions.rb +48 -3
- data/test/query_tests.rb +4 -4
- metadata +11 -6
@@ -1,15 +1,33 @@
|
|
1
|
-
# This code is free software; you can redistribute it and/or modify it under
|
2
|
-
# terms of the new BSD License.
|
1
|
+
# This code is free software; you can redistribute it and/or modify it under
|
2
|
+
# the terms of the new BSD License.
|
3
3
|
#
|
4
|
-
# Copyright (c) 2008-
|
4
|
+
# Copyright (c) 2008-2011, Sebastian Staudt
|
5
5
|
|
6
6
|
require 'steam/servers/game_server'
|
7
7
|
require 'steam/sockets/goldsrc_socket'
|
8
8
|
|
9
|
+
# This class represents a GoldSrc game server and can be used to query
|
10
|
+
# information about and remotely execute commands via RCON on the server
|
11
|
+
#
|
12
|
+
# A GoldSrc game server is an instance of the Half-Life Dedicated Server (HLDS)
|
13
|
+
# running games using Valve's GoldSrc engine, like Half-Life Deathmatch,
|
14
|
+
# Counter-Strike 1.6 or Team Fortress Classic.
|
15
|
+
#
|
16
|
+
# @author Sebastian Staudt
|
17
|
+
# @see SourceServer
|
9
18
|
class GoldSrcServer
|
10
19
|
|
11
20
|
include GameServer
|
12
21
|
|
22
|
+
# Creates a new instance of a GoldSrc server object
|
23
|
+
#
|
24
|
+
# @param [String] address Either an IP address, a DNS name or one of them
|
25
|
+
# combined with the port number. If a port number is given, e.g.
|
26
|
+
# 'server.example.com:27016' it will override the second argument.
|
27
|
+
# @param [Fixnum] port The port the server is listening on
|
28
|
+
# @raise [SteamCondenserException] if an host name cannot be resolved
|
29
|
+
# @param [Boolean] is_hltv HLTV servers need special treatment, so this is
|
30
|
+
# used to determine if the server is a HLTV server
|
13
31
|
def initialize(address, port = 27015, is_hltv = false)
|
14
32
|
super address, port
|
15
33
|
|
@@ -17,15 +35,29 @@ class GoldSrcServer
|
|
17
35
|
end
|
18
36
|
|
19
37
|
# Initializes the socket to communicate with the GoldSrc server
|
38
|
+
#
|
39
|
+
# @see GoldSrcSocket
|
20
40
|
def init_socket
|
21
41
|
@socket = GoldSrcSocket.new @ip_address, @port, @is_hltv
|
22
42
|
end
|
23
43
|
|
44
|
+
# Saves the password for authenticating the RCON communication with the
|
45
|
+
# server
|
46
|
+
#
|
47
|
+
# @param [String] password The RCON password of the server
|
48
|
+
# @return [true] GoldSrc's RCON does not preauthenticate connections so this
|
49
|
+
# method always returns `true`
|
50
|
+
# @see #rcon_exec
|
24
51
|
def rcon_auth(password)
|
25
52
|
@rcon_password = password
|
26
53
|
true
|
27
54
|
end
|
28
55
|
|
56
|
+
# Remotely executes a command on the server via RCON
|
57
|
+
#
|
58
|
+
# @param [String] command The command to execute on the server via RCON
|
59
|
+
# @return [String] The output of the executed command
|
60
|
+
# @see #rcon_auth
|
29
61
|
def rcon_exec(command)
|
30
62
|
@socket.rcon_exec(@rcon_password, command).strip
|
31
63
|
end
|
@@ -1,5 +1,5 @@
|
|
1
|
-
# This code is free software; you can redistribute it and/or modify it under
|
2
|
-
# terms of the new BSD License.
|
1
|
+
# This code is free software; you can redistribute it and/or modify it under
|
2
|
+
# the terms of the new BSD License.
|
3
3
|
#
|
4
4
|
# Copyright (c) 2008-2011, Sebastian Staudt
|
5
5
|
|
@@ -9,35 +9,59 @@ require 'steam/packets/s2m_heartbeat2_packet'
|
|
9
9
|
require 'steam/servers/server'
|
10
10
|
require 'steam/sockets/master_server_socket'
|
11
11
|
|
12
|
+
# This class represents a Steam master server and can be used to get game
|
13
|
+
# servers which are publicly available
|
14
|
+
#
|
15
|
+
# An intance of this class can be used much like Steam's server browser to get
|
16
|
+
# a list of available game servers, including filters to narrow down the search
|
17
|
+
# results.
|
18
|
+
#
|
19
|
+
# @author Sebastian Staudt
|
12
20
|
class MasterServer
|
13
21
|
|
14
22
|
include Server
|
15
23
|
|
24
|
+
# The master server address to query for GoldSrc game servers
|
16
25
|
GOLDSRC_MASTER_SERVER = 'hl1master.steampowered.com', 27010
|
26
|
+
|
27
|
+
# The master server address to query for GoldSrc game servers
|
17
28
|
SOURCE_MASTER_SERVER = 'hl2master.steampowered.com', 27011
|
18
29
|
|
30
|
+
# The region code for the US east coast
|
19
31
|
REGION_US_EAST_COAST = 0x00
|
32
|
+
|
33
|
+
# The region code for the US west coast
|
20
34
|
REGION_US_WEST_COAST = 0x01
|
35
|
+
|
36
|
+
# The region code for South America
|
21
37
|
REGION_SOUTH_AMERICA = 0x02
|
38
|
+
|
39
|
+
# The region code for Europe
|
22
40
|
REGION_EUROPE = 0x03
|
41
|
+
|
42
|
+
# The region code for Asia
|
23
43
|
REGION_ASIA = 0x04
|
44
|
+
|
45
|
+
# The region code for Australia
|
24
46
|
REGION_AUSTRALIA = 0x05
|
47
|
+
|
48
|
+
# The region code for the Middle East
|
25
49
|
REGION_MIDDLE_EAST = 0x06
|
26
|
-
REGION_AFRICA = 0x07
|
27
|
-
REGION_ALL = 0xFF
|
28
50
|
|
29
|
-
#
|
30
|
-
|
31
|
-
super
|
51
|
+
# The region code for Africa
|
52
|
+
REGION_AFRICA = 0x07
|
32
53
|
|
33
|
-
|
34
|
-
|
54
|
+
# The region code for the whole world
|
55
|
+
REGION_ALL = 0xFF
|
35
56
|
|
36
|
-
# Request a challenge number from the master server.
|
37
|
-
#
|
57
|
+
# Request a challenge number from the master server.
|
58
|
+
#
|
59
|
+
# This is used for further communication with the master server.
|
38
60
|
#
|
39
|
-
# Please note that this is
|
40
|
-
#
|
61
|
+
# @note Please note that this is **not** needed for finding servers using
|
62
|
+
# {#servers}.
|
63
|
+
# @return The challenge number from the master server
|
64
|
+
# @see #send_heartbeat
|
41
65
|
def challenge
|
42
66
|
failsafe do
|
43
67
|
@socket.send C2M_CHECKMD5_Packet.new
|
@@ -46,19 +70,43 @@ class MasterServer
|
|
46
70
|
end
|
47
71
|
|
48
72
|
# Initializes the socket to communicate with the master server
|
73
|
+
#
|
74
|
+
# @see MasterServerSocket
|
49
75
|
def init_socket
|
50
76
|
@socket = MasterServerSocket.new @ip_address, @port
|
51
77
|
end
|
52
78
|
|
79
|
+
# Returns a list of game server matching the given region and filters
|
80
|
+
#
|
81
|
+
# Filtering:
|
82
|
+
# Instead of filtering the results sent by the master server locally, you
|
83
|
+
# should at least use the following filters to narrow down the results sent by
|
84
|
+
# the master server.
|
85
|
+
#
|
86
|
+
# Available filters:
|
87
|
+
#
|
88
|
+
# * `\type\d`: Request only dedicated servers
|
89
|
+
# * `\secure\1`: Request only secure servers
|
90
|
+
# * `\gamedir\[mod]`: Request only servers of a specific mod
|
91
|
+
# * `\map\[mapname]`: Request only servers running a specific map
|
92
|
+
# * `\linux\1`: Request only linux servers
|
93
|
+
# * `\emtpy\1`: Request only **non**-empty servers
|
94
|
+
# * `\full\`: Request only servers **not** full
|
95
|
+
# * `\proxy\1`: Request only spectator proxy servers
|
96
|
+
#
|
97
|
+
# @note Receiving all servers from the master server is taking quite some
|
98
|
+
# time.
|
99
|
+
# @param [Fixnum] region_code The region code to specify a location of the
|
100
|
+
# game servers
|
101
|
+
# @param [String] filters The filters that game servers should match
|
102
|
+
# @return [Array<Array<String>>] A list of game servers matching the given
|
103
|
+
# region and filters
|
104
|
+
# @see A2M_GET_SERVERS_BATCH2_Packet
|
53
105
|
def servers(region_code = MasterServer::REGION_ALL, filters = '')
|
54
|
-
update_servers region_code, filters if @server_array.empty?
|
55
|
-
@server_array
|
56
|
-
end
|
57
|
-
|
58
|
-
def update_servers(region_code, filters)
|
59
106
|
fail_count = 0
|
60
107
|
finished = false
|
61
108
|
current_server = '0.0.0.0:0'
|
109
|
+
server_array = []
|
62
110
|
|
63
111
|
failsafe do
|
64
112
|
begin
|
@@ -70,7 +118,7 @@ class MasterServer
|
|
70
118
|
finished = true
|
71
119
|
else
|
72
120
|
current_server = server
|
73
|
-
|
121
|
+
server_array << server.split(':')
|
74
122
|
end
|
75
123
|
end
|
76
124
|
fail_count = 0
|
@@ -79,16 +127,22 @@ class MasterServer
|
|
79
127
|
end
|
80
128
|
end while !finished
|
81
129
|
end
|
130
|
+
|
131
|
+
server_array
|
82
132
|
end
|
83
133
|
|
84
134
|
# Sends a constructed heartbeat to the master server
|
85
135
|
#
|
86
136
|
# This can be used to check server versions externally.
|
87
137
|
#
|
88
|
-
#
|
89
|
-
#
|
90
|
-
#
|
91
|
-
# packets.
|
138
|
+
# @param [Hash<Symbol, Object>] The data to send with the heartbeat request
|
139
|
+
# @raise [SteamCondenserException] if heartbeat data is missing the
|
140
|
+
# challenge number or the reply cannot be parsed
|
141
|
+
# @return [Array<SteamPacket>] Zero or more reply packets from the server.
|
142
|
+
# Zero means either the heartbeat was accepted by the master or there
|
143
|
+
# was a timeout. So usually it's best to repeat a heartbeat a few
|
144
|
+
# times when not receiving any packets.
|
145
|
+
# @see S2M_HEARTBEAT2_Packet
|
92
146
|
def send_heartbeat(data)
|
93
147
|
failsafe do
|
94
148
|
@socket.send S2M_HEARTBEAT2_Packet.new(data)
|
data/lib/steam/servers/server.rb
CHANGED
@@ -7,10 +7,30 @@ require 'socket'
|
|
7
7
|
|
8
8
|
# This module is included by all classes implementing server functionality
|
9
9
|
#
|
10
|
-
# It provides basic name resolution features
|
10
|
+
# It provides basic name resolution features and the ability to rotate between
|
11
|
+
# different IP addresses belonging to a single DNS name.
|
12
|
+
#
|
13
|
+
# @author Sebastian Staudt
|
11
14
|
module Server
|
12
15
|
|
16
|
+
# Returns a list of host names associated with this server
|
17
|
+
#
|
18
|
+
# @return [Array<String>] The host names of this server
|
19
|
+
attr_reader :host_names
|
20
|
+
|
21
|
+
# Returns a list of IP addresses associated with this server
|
22
|
+
#
|
23
|
+
# @return [Array<String>] The IP addresses of this server
|
24
|
+
attr_reader :ip_addresses
|
25
|
+
|
13
26
|
# Creates a new server instance with the given address and port
|
27
|
+
#
|
28
|
+
# @param [String] address Either an IP address, a DNS name or one of them
|
29
|
+
# combined with the port number. If a port number is given, e.g.
|
30
|
+
# 'server.example.com:27016' it will override the second argument.
|
31
|
+
# @param [Fixnum] port The port the server is listening on
|
32
|
+
# @see init_socket
|
33
|
+
# @raise [SteamCondenserException] if an host name cannot be resolved
|
14
34
|
def initialize(address, port = nil)
|
15
35
|
address = address.to_s
|
16
36
|
address, port = address.split(':', 2) if address.include? ':'
|
@@ -33,8 +53,17 @@ module Server
|
|
33
53
|
|
34
54
|
# Rotate this server's IP address to the next one in the IP list
|
35
55
|
#
|
36
|
-
#
|
37
|
-
#
|
56
|
+
# If this method returns `true`, it indicates that all IP addresses have been
|
57
|
+
# used, hinting at the server(s) being unreachable. An appropriate action
|
58
|
+
# should be taken to inform the user.
|
59
|
+
#
|
60
|
+
# Servers with only one IP address will always cause this method to return
|
61
|
+
# `true` and the sockets will not be reinitialized.
|
62
|
+
#
|
63
|
+
# @return [Boolean] `true`, if the IP list reached its end. If the list
|
64
|
+
# contains only one IP address, this method will instantly return
|
65
|
+
# `true`
|
66
|
+
# @see #init_socket
|
38
67
|
def rotate_ip
|
39
68
|
return true if @ip_addresses.size == 1
|
40
69
|
|
@@ -54,6 +83,9 @@ module Server
|
|
54
83
|
# in the server's IP list and the execution will be repeated for the next IP
|
55
84
|
# address. If the IP rotation reaches the end of the list, the exception will
|
56
85
|
# be reraised.
|
86
|
+
#
|
87
|
+
# @param [Proc] proc The action to be executed in a failsafe way
|
88
|
+
# @see #rotate_ip
|
57
89
|
def failsafe(&proc)
|
58
90
|
begin
|
59
91
|
proc.call
|
@@ -63,4 +95,11 @@ module Server
|
|
63
95
|
end
|
64
96
|
end
|
65
97
|
|
98
|
+
# Initializes the socket(s) to communicate with the server
|
99
|
+
#
|
100
|
+
# @abstract Must be implemented in including classes to prepare sockets for
|
101
|
+
# server communication
|
102
|
+
def init_socket
|
103
|
+
end
|
104
|
+
|
66
105
|
end
|
@@ -1,5 +1,5 @@
|
|
1
|
-
# This code is free software; you can redistribute it and/or modify it under
|
2
|
-
# terms of the new BSD License.
|
1
|
+
# This code is free software; you can redistribute it and/or modify it under
|
2
|
+
# the terms of the new BSD License.
|
3
3
|
#
|
4
4
|
# Copyright (c) 2008-2011, Sebastian Staudt
|
5
5
|
|
@@ -12,20 +12,45 @@ require 'steam/servers/game_server'
|
|
12
12
|
require 'steam/sockets/rcon_socket'
|
13
13
|
require 'steam/sockets/source_socket'
|
14
14
|
|
15
|
+
# This class represents a Source game server and can be used to query
|
16
|
+
# information about and remotely execute commands via RCON on the server
|
17
|
+
#
|
18
|
+
# A Source game server is an instance of the Source Dedicated Server (SrcDS)
|
19
|
+
# running games using Valve's Source engine, like Counter-Strike: Source,
|
20
|
+
# Team Fortress 2 or Left4Dead.
|
21
|
+
#
|
22
|
+
# @author Sebastian Staudt
|
23
|
+
# @see GoldSrcServer
|
15
24
|
class SourceServer
|
16
25
|
|
17
26
|
include GameServer
|
18
27
|
|
28
|
+
# Creates a new instance of a server object representing a Source server,
|
29
|
+
# i.e. SrcDS instance
|
30
|
+
#
|
31
|
+
# @param [String] address Either an IP address, a DNS name or one of them
|
32
|
+
# combined with the port number. If a port number is given, e.g.
|
33
|
+
# 'server.example.com:27016' it will override the second argument.
|
34
|
+
# @param [Fixnum] port The port the server is listening on
|
35
|
+
# @raise [SteamCondenserException] if an host name cannot be resolved
|
19
36
|
def initialize(address, port = 27015)
|
20
37
|
super
|
21
38
|
end
|
22
39
|
|
23
40
|
# Initializes the sockets to communicate with the Source server
|
41
|
+
#
|
42
|
+
# @see RCONSocket
|
43
|
+
# @see SourceSocket
|
24
44
|
def init_socket
|
25
45
|
@rcon_socket = RCONSocket.new @ip_address, @port
|
26
46
|
@socket = SourceSocket.new @ip_address, @port
|
27
47
|
end
|
28
48
|
|
49
|
+
# Authenticates the connection for RCON communication with the server
|
50
|
+
#
|
51
|
+
# @param [String] password The RCON password of the server
|
52
|
+
# @return [Boolean] whether authentication was successful
|
53
|
+
# @see #rcon_exec
|
29
54
|
def rcon_auth(password)
|
30
55
|
@rcon_request_id = rand 2**16
|
31
56
|
|
@@ -38,22 +63,21 @@ class SourceServer
|
|
38
63
|
reply.request_id == @rcon_request_id
|
39
64
|
end
|
40
65
|
|
66
|
+
# Remotely executes a command on the server via RCON
|
67
|
+
#
|
68
|
+
# @param [String] command The command to execute on the server via RCON
|
69
|
+
# @return [String] The output of the executed command
|
70
|
+
# @see #rcon_auth
|
41
71
|
def rcon_exec(command)
|
42
72
|
@rcon_socket.send RCONExecRequest.new(@rcon_request_id, command)
|
43
73
|
@rcon_socket.send RCONTerminator.new(@rcon_request_id)
|
44
|
-
response_packets = []
|
45
74
|
|
75
|
+
response = ''
|
46
76
|
begin
|
47
77
|
response_packet = @rcon_socket.reply
|
48
|
-
redo if response_packet.nil?
|
49
78
|
raise RCONNoAuthException.new if response_packet.is_a? RCONAuthResponse
|
50
|
-
|
51
|
-
end while response_packet.response.size > 0
|
52
|
-
|
53
|
-
response = ''
|
54
|
-
response_packets.each do |packet|
|
55
|
-
response << packet.response
|
56
|
-
end
|
79
|
+
response << response_packet.response
|
80
|
+
end while response.length == 0 || response_packet.response.size > 0
|
57
81
|
|
58
82
|
response.strip
|
59
83
|
end
|
data/lib/stringio_additions.rb
CHANGED
@@ -1,44 +1,89 @@
|
|
1
|
-
# This code is free software; you can redistribute it and/or modify it under
|
2
|
-
# terms of the new BSD License.
|
1
|
+
# This code is free software; you can redistribute it and/or modify it under
|
2
|
+
# the terms of the new BSD License.
|
3
3
|
#
|
4
|
-
# Copyright (c) 2010, Sebastian Staudt
|
4
|
+
# Copyright (c) 2010-2011, Sebastian Staudt
|
5
5
|
|
6
6
|
require 'stringio'
|
7
7
|
|
8
|
+
# This extends the `StringIO` class from Ruby's standard library. It adds some
|
9
|
+
# methods to handle byte-wise input from a `StringIO` object.
|
10
|
+
#
|
11
|
+
# @author Sebastian Staudt
|
8
12
|
class StringIO
|
9
13
|
|
14
|
+
# Creates a new instance of `StringIO` with the given size and fills it with
|
15
|
+
# zero-bytes.
|
16
|
+
#
|
17
|
+
# @param [Fixnum] size The size the new instance should have
|
18
|
+
# @return [StringIO] A new `StringIO` instance with the given size, filled
|
19
|
+
# with zero-bytes
|
10
20
|
def self.allocate(size)
|
11
21
|
new "\0" * size
|
12
22
|
end
|
13
23
|
|
24
|
+
# Reads a single byte from the current position of the byte stream
|
25
|
+
#
|
26
|
+
# @return [Fixnum] The numeric value of the byte at the current position
|
14
27
|
def byte
|
15
28
|
read(1)[0].ord
|
16
29
|
end
|
17
30
|
|
31
|
+
# Reads a floating-point integer (32 bit) from the current position of the
|
32
|
+
# byte stream
|
33
|
+
#
|
34
|
+
# @return [Float] The floating-point integer read from the byte stream
|
18
35
|
def float
|
19
36
|
read(4).unpack('e')[0]
|
20
37
|
end
|
21
38
|
|
39
|
+
# Reads the whole remaining content of the byte stream from the current
|
40
|
+
# position to the end
|
41
|
+
#
|
42
|
+
# @return [String] The remainder of the byte stream starting from the current
|
43
|
+
# position of the byte stream
|
22
44
|
def get
|
23
45
|
read remaining
|
24
46
|
end
|
25
47
|
|
48
|
+
# Reads an unsigned long integer (32 bit) from the current position of the
|
49
|
+
# byte stream
|
50
|
+
#
|
51
|
+
# @return [Fixnum] The unsigned long integer read from the byte stream
|
26
52
|
def long
|
27
53
|
read(4).unpack('V')[0]
|
28
54
|
end
|
29
55
|
|
56
|
+
# Returns the remaining number of bytes from the current position to the end
|
57
|
+
# of the byte stream
|
58
|
+
#
|
59
|
+
# @return [Fixnum] The number of bytes until the end of the stream
|
30
60
|
def remaining
|
31
61
|
size - pos
|
32
62
|
end
|
33
63
|
|
64
|
+
# Reads an unsigned short integer (16 bit) from the current position of the
|
65
|
+
# byte stream
|
66
|
+
#
|
67
|
+
# @return [Fixnum] The unsigned short integer read from the byte stream
|
34
68
|
def short
|
35
69
|
read(2).unpack('v')[0]
|
36
70
|
end
|
37
71
|
|
72
|
+
# Reads a signed long integer (32 bit) from the current position of the byte
|
73
|
+
# stream
|
74
|
+
#
|
75
|
+
# @return [Fixnum] The signed long integer read from the byte stream
|
38
76
|
def signed_long
|
39
77
|
read(4).unpack('l')[0]
|
40
78
|
end
|
41
79
|
|
80
|
+
# Reads a zero-byte terminated string from the current position of the byte
|
81
|
+
# stream
|
82
|
+
#
|
83
|
+
# This reads the stream up until the first occurance of a zero-byte or the
|
84
|
+
# end of the stream. The zero-byte is not included in the returned string.
|
85
|
+
#
|
86
|
+
# @return [String] The zero-byte terminated string read from the byte stream
|
42
87
|
def cstring
|
43
88
|
gets("\0")[0..-2]
|
44
89
|
end
|