rrb 0.0.4 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/rrb/io/buffer.rb +134 -0
- data/lib/rrb/io/message.rb +125 -0
- data/lib/rrb/io/native_readable.rb +123 -0
- data/lib/rrb/io/readable.rb +199 -0
- data/lib/rrb/io/validation.rb +105 -0
- data/lib/rrb/io/writeable.rb +236 -0
- data/{app → lib}/rrb/patches/integer.rb +0 -0
- data/{app → lib}/rrb/patches/set.rb +0 -0
- data/{app → lib}/rrb/patches/string.rb +0 -0
- data/lib/rrb/utils/controller.rb +146 -0
- data/{app → lib}/rrb/utils/environment.rb +0 -0
- data/{app → lib}/rrb/utils/logging.rb +0 -0
- data/{app → lib}/rrb/utils/version.rb +0 -0
- data/{app → lib}/rrb.rb +29 -2
- metadata +26 -40
- data/app/rrb/utils/controller.rb +0 -209
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5fa8cdaebd91d028bc2a93d59e00c45c7d61090f4fb8547b224ed2d78aa7fea9
|
4
|
+
data.tar.gz: 69968f16213b56e75f9a96e18a1d5f2a56c187a783820de396c2453398657a9d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 91e576b8fbf50b633175d3084f18a7abd5d0b24ab1a71a951e4144d889de7078ae66fc7bace3f8aeb384b793d67b11805dbf536cfcf13da1b42325298bd1345c
|
7
|
+
data.tar.gz: '09dcd69d25de941f26dd0551276b45170bbd8464675a95ddeb6dbed6adb145aabc536549db28cff504f049c2fc5b7f55e8603dc48652a0a2b5c7e6144c28dfff'
|
@@ -0,0 +1,134 @@
|
|
1
|
+
# The IO module provides objects, modules, and functions to handle input/output operations.
|
2
|
+
module RuneRb::IO
|
3
|
+
|
4
|
+
# A Buffer object encapsulates a string of binary data and dynamically includes functions to interact with that data depending on the modestring.
|
5
|
+
class Buffer
|
6
|
+
include RuneRb::Utils::Logging
|
7
|
+
|
8
|
+
# @return [Boolean] is {bit_access} enabled?
|
9
|
+
attr_reader :bit_access
|
10
|
+
|
11
|
+
# @return [String] the access mode.
|
12
|
+
attr_reader :mode
|
13
|
+
|
14
|
+
# @return [String] the data.
|
15
|
+
attr_reader :data
|
16
|
+
|
17
|
+
# Construct a new instance of {Buffer}.
|
18
|
+
# @param modestring [String] the mode for the buffer. ['r', 'w']
|
19
|
+
# @param data [String] the data.
|
20
|
+
# @return [Buffer] the created instance.
|
21
|
+
def initialize(modestring, data: '')
|
22
|
+
raise "Invalid mode-string for Buffer! Expecting: r, rn, w, rw Got: #{modestring}" unless /(?i)r|n|w/.match?(modestring)
|
23
|
+
|
24
|
+
@data = data
|
25
|
+
@mode = modestring
|
26
|
+
|
27
|
+
enable_readable if /(?i)r/.match?(modestring)
|
28
|
+
enable_writeable if /(?i)w/.match?(modestring)
|
29
|
+
enable_native_readable if /(?i)n/.match?(modestring)
|
30
|
+
|
31
|
+
self
|
32
|
+
end
|
33
|
+
|
34
|
+
# The length of the underlying data.
|
35
|
+
# @return [Integer]
|
36
|
+
def length
|
37
|
+
@data.length
|
38
|
+
end
|
39
|
+
|
40
|
+
alias size length
|
41
|
+
|
42
|
+
# Fetches a snapshot of the message payload content.
|
43
|
+
# @return [String] a snapshot of the payload
|
44
|
+
def peek
|
45
|
+
@data.force_encoding(Encoding::BINARY)
|
46
|
+
end
|
47
|
+
|
48
|
+
alias snapshot peek
|
49
|
+
|
50
|
+
# Push data directly to the {Buffer#data} object.
|
51
|
+
# @param data [String] the data to write.
|
52
|
+
def push(data = '')
|
53
|
+
@data.concat(data) unless data.empty?
|
54
|
+
end
|
55
|
+
|
56
|
+
alias << push
|
57
|
+
|
58
|
+
def inspect
|
59
|
+
if @mode.include?('w')
|
60
|
+
"[BufferMode:] #{@mode} || [BodyLength:] #{@data.length} || [BitAccess:] #{@bit_access} || [Payload:] #{hex}"
|
61
|
+
else
|
62
|
+
"[BufferMode:] #{@mode} || [BodyLength:] #{@data.length} || [Payload:] #{hex}"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# @return [String] hex representation of the buffer's data.
|
67
|
+
def hex
|
68
|
+
res = ''
|
69
|
+
peek.each_byte { res << "#{_1 < 16 ? '0' : ''}#{_1.to_s(16)} " }
|
70
|
+
res.strip
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
# Enables Writeable functions for the Message.
|
76
|
+
def enable_writeable
|
77
|
+
@bit_access = false
|
78
|
+
@bit_position = 0
|
79
|
+
singleton_class.include(RuneRb::IO::Writeable)
|
80
|
+
end
|
81
|
+
|
82
|
+
# Enables Readable functions for the Message.
|
83
|
+
def enable_readable
|
84
|
+
singleton_class.include(RuneRb::IO::Readable)
|
85
|
+
end
|
86
|
+
|
87
|
+
# Enables Native reading functions for the Message.
|
88
|
+
def enable_native_readable
|
89
|
+
singleton_class.include(RuneRb::IO::NativeReadable)
|
90
|
+
end
|
91
|
+
|
92
|
+
# Mutates the value according to the passed mutation
|
93
|
+
# @param value [Integer] the value to mutate
|
94
|
+
# @param mutation [Symbol] the mutation to apply to the value.
|
95
|
+
def mutate(value, mutation)
|
96
|
+
case mutation
|
97
|
+
when :STD then value
|
98
|
+
when :ADD then value += 128
|
99
|
+
when :NEG then value = -value
|
100
|
+
when :SUB then value -= 128
|
101
|
+
else mutate(value, :STD)
|
102
|
+
end
|
103
|
+
value
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
# Copyright (c) 2022, Patrick W.
|
109
|
+
# All rights reserved.
|
110
|
+
#
|
111
|
+
# Redistribution and use in source and binary forms, with or without
|
112
|
+
# modification, are permitted provided that the following conditions are met:
|
113
|
+
#
|
114
|
+
# * Redistributions of source code must retain the above copyright notice, this
|
115
|
+
# list of conditions and the following disclaimer.
|
116
|
+
#
|
117
|
+
# * Redistributions in binary form must reproduce the above copyright notice,
|
118
|
+
# this list of conditions and the following disclaimer in the documentation
|
119
|
+
# and/or other materials provided with the distribution.
|
120
|
+
#
|
121
|
+
# * Neither the name of the copyright holder nor the names of its
|
122
|
+
# contributors may be used to endorse or promote products derived from
|
123
|
+
# this software without specific prior written permission.
|
124
|
+
#
|
125
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
126
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
127
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
128
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
129
|
+
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
130
|
+
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
131
|
+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
132
|
+
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
133
|
+
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
134
|
+
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
@@ -0,0 +1,125 @@
|
|
1
|
+
# The IO module provides objects, modules, and functions to handle input/output operations.
|
2
|
+
module RuneRb::IO
|
3
|
+
|
4
|
+
# Represents a composable/decomposable network message that is either sent or received via a TCPSocket.
|
5
|
+
class Message
|
6
|
+
include RuneRb::Utils::Logging
|
7
|
+
|
8
|
+
# @return [Struct] the header for the message.
|
9
|
+
attr :header
|
10
|
+
|
11
|
+
# @return [Buffer] the access mode for the message.
|
12
|
+
attr :body
|
13
|
+
|
14
|
+
# Models the heading of a protocol data unit received from a peer socket.
|
15
|
+
# @param op_code [Integer] the Operation Code of the data unit
|
16
|
+
# @param length [Integer] the length of data unit's payload, excluding the header.
|
17
|
+
# @param type [Symbol] the type of header of the data unit.
|
18
|
+
# @return [Struct]
|
19
|
+
Header = Struct.new(:op_code, :length, :type) do
|
20
|
+
|
21
|
+
# Generates a binary string representation of the {Header} object.
|
22
|
+
# @return [String, NilClass] binary representation of the header.
|
23
|
+
def compile_header
|
24
|
+
case self.type
|
25
|
+
when :FIXED then [self.op_code].pack('C') # Fixed packet lengths are known by both the client and server, so no length packing is necesssary
|
26
|
+
when :RAW then ''
|
27
|
+
when :VARIABLE_SHORT then [self.op_code, self.length].pack('Cn') # Variable Short packet lengths fall into the range of a short type and can be packed as such
|
28
|
+
when :VARIABLE_BYTE # Variable Byte packet lengths fall into the range of a byte type and can be packed as such
|
29
|
+
if self.length.nonzero? && self.length.positive?
|
30
|
+
[self.op_code, self.length].pack('Cc')
|
31
|
+
elsif self.length.nonzero? && self.length.negative?
|
32
|
+
self.type = :FIXED
|
33
|
+
compile_header
|
34
|
+
end
|
35
|
+
else compile_header
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def inspect
|
40
|
+
"[Header]: [OpCode]: #{self.op_code} || [Length]: #{self.length}"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# Called when a new Message is created
|
45
|
+
# @param op_code [Integer] the message's operation code.
|
46
|
+
# @param type [Symbol] the message type. [:VARIABLE_BYTE, :VARIABLE_SHORT, :FIXED]
|
47
|
+
# @param body [String, RuneRb::Network::Buffer] an optional body payload for the message.
|
48
|
+
# @return [Message] the instance created.
|
49
|
+
def initialize(op_code: -1, type: :FIXED, body: RuneRb::IO::Buffer.new('rw'))
|
50
|
+
@header = Header.new(op_code, 0, type)
|
51
|
+
@body = case body
|
52
|
+
when RuneRb::IO::Buffer then body
|
53
|
+
when String then RuneRb::IO::Buffer.new('r', data: body)
|
54
|
+
else raise "Invalid body type for message! Expecting: Buffer, String Got: #{body.class}"
|
55
|
+
end
|
56
|
+
update_length
|
57
|
+
|
58
|
+
self
|
59
|
+
end
|
60
|
+
|
61
|
+
# Compiles the {Message} into a string of binary data.
|
62
|
+
# @return [String] binary representation of the message.
|
63
|
+
def compile
|
64
|
+
@header.compile_header + @body.snapshot
|
65
|
+
end
|
66
|
+
|
67
|
+
def inspect
|
68
|
+
"#{@header.inspect} || #{@body.inspect}"
|
69
|
+
end
|
70
|
+
|
71
|
+
# @abstract parses the message object.
|
72
|
+
def parse(_session); end
|
73
|
+
|
74
|
+
# Read data from the {Message#body}
|
75
|
+
# @param type [Symbol] the type of data to read
|
76
|
+
# @param signed [Boolean] should the value be signed
|
77
|
+
# @param mutation [Symbol] the mutation that should be applied to the data
|
78
|
+
# @param order [String] the byte order to read the data in.
|
79
|
+
def read(type: :byte, signed: false, mutation: :STD, order: 'BIG')
|
80
|
+
@body.read(type: type, signed: signed, mutation: mutation, order: order)
|
81
|
+
end
|
82
|
+
|
83
|
+
# Write data to the {Message#body}
|
84
|
+
def write(value, type: :byte, mutation: :STD, order: 'BIG', options: {})
|
85
|
+
@body.write(value, type: type, mutation: mutation, order: order, options: options)
|
86
|
+
update_length
|
87
|
+
self
|
88
|
+
end
|
89
|
+
|
90
|
+
private
|
91
|
+
|
92
|
+
# Updates the length of the <@header>
|
93
|
+
def update_length
|
94
|
+
@header.length = @body.length
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
# Copyright (c) 2022, Patrick W.
|
100
|
+
# All rights reserved.
|
101
|
+
#
|
102
|
+
# Redistribution and use in source and binary forms, with or without
|
103
|
+
# modification, are permitted provided that the following conditions are met:
|
104
|
+
#
|
105
|
+
# * Redistributions of source code must retain the above copyright notice, this
|
106
|
+
# list of conditions and the following disclaimer.
|
107
|
+
#
|
108
|
+
# * Redistributions in binary form must reproduce the above copyright notice,
|
109
|
+
# this list of conditions and the following disclaimer in the documentation
|
110
|
+
# and/or other materials provided with the distribution.
|
111
|
+
#
|
112
|
+
# * Neither the name of the copyright holder nor the names of its
|
113
|
+
# contributors may be used to endorse or promote products derived from
|
114
|
+
# this software without specific prior written permission.
|
115
|
+
#
|
116
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
117
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
118
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
119
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
120
|
+
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
121
|
+
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
122
|
+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
123
|
+
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
124
|
+
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
125
|
+
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
@@ -0,0 +1,123 @@
|
|
1
|
+
# The IO module provides objects, modules, and functions to handle input/output operations.
|
2
|
+
module RuneRb::IO
|
3
|
+
|
4
|
+
# Provides functions to read integer values from a string-based buffer using native ruby methods.
|
5
|
+
module NativeReadable
|
6
|
+
# Read a byte value from the {Buffer#data}
|
7
|
+
# @param signed [Boolean] should the value be signed.
|
8
|
+
# @param mutation [String] mutation that should be applied to the byte value.
|
9
|
+
def read_byte(mutation: :STD, signed: false)
|
10
|
+
mutate(@data.slice!(0)&.unpack1(signed ? 'c' : 'C') || 0, mutation)
|
11
|
+
end
|
12
|
+
|
13
|
+
# Reads a short value from the {Buffer#data}
|
14
|
+
# @param signed [Boolean] should the value be signed.
|
15
|
+
# @param mutation [String] mutation that should be applied to the short value
|
16
|
+
# @param order [String] they byte order to read the short value
|
17
|
+
def read_short(signed: false, mutation: :STD, order: 'BIG')
|
18
|
+
val = 0
|
19
|
+
case order
|
20
|
+
when 'BIG'
|
21
|
+
val += mutate(@data.slice!(0..1).unpack1(signed ? 's>' : 'S>'), mutation)
|
22
|
+
when 'LITTLE'
|
23
|
+
val += mutate(@data.slice!(0..1).unpack1(signed ? 's<' : 'S<'), mutation)
|
24
|
+
else read_short(signed: signed, mutation: mutation, order: 'BIG')
|
25
|
+
end
|
26
|
+
val
|
27
|
+
end
|
28
|
+
|
29
|
+
# Reads a medium value from the {Buffer#data}
|
30
|
+
# @param signed [Boolean] should the value be signed.
|
31
|
+
# @param mutation [String] mutation that should be applied to the medium value
|
32
|
+
# @param order [String] they byte order to read the medium value
|
33
|
+
def read_medium(signed: false, mutation: :STD, order: 'BIG')
|
34
|
+
val = 0
|
35
|
+
case order
|
36
|
+
when 'BIG'
|
37
|
+
val += read_byte(signed: signed) << 16
|
38
|
+
val += read_byte(signed: signed) << 8
|
39
|
+
val += read_byte(signed: signed, mutation: mutation)
|
40
|
+
when 'MIDDLE'
|
41
|
+
val += read_byte(signed: signed) << 8
|
42
|
+
val += read_byte(signed: signed, mutation: mutation)
|
43
|
+
val += read_byte(signed: signed) << 16
|
44
|
+
when 'LITTLE'
|
45
|
+
val += read_byte(signed: signed, mutation: mutation)
|
46
|
+
val += read_byte(signed: signed) << 8
|
47
|
+
val += read_byte(signed: signed) << 16
|
48
|
+
else read_medium(signed: signed, mutation: mutation, order: 'BIG')
|
49
|
+
end
|
50
|
+
val
|
51
|
+
end
|
52
|
+
|
53
|
+
# Reads a integer value from the {Buffer#data}
|
54
|
+
# @param signed [Boolean] should the value be signed.
|
55
|
+
# @param mutation [String] mutation that should be applied to the integer value
|
56
|
+
# @param order [String] they byte order to read the integer value
|
57
|
+
def read_int(signed: false, mutation: :STD, order: 'BIG')
|
58
|
+
val = 0
|
59
|
+
case order
|
60
|
+
when 'BIG'
|
61
|
+
val += mutate(@data.slice!(0..3).unpack1(signed ? 'i>' : 'I>'), mutation)
|
62
|
+
when 'MIDDLE'
|
63
|
+
val += read_byte(signed: signed) << 8
|
64
|
+
val += read_byte(signed: signed, mutation: mutation)
|
65
|
+
val += read_byte(signed: signed) << 24
|
66
|
+
val += read_byte(signed: signed) << 16
|
67
|
+
return val
|
68
|
+
when 'INVERSE_MIDDLE'
|
69
|
+
val += read_byte(signed: signed) << 16
|
70
|
+
val += read_byte(signed: signed) << 24
|
71
|
+
val += read_byte(signed: signed, mutation: mutation)
|
72
|
+
val += read_byte(signed: signed) << 8
|
73
|
+
return val
|
74
|
+
when 'LITTLE'
|
75
|
+
val += mutate(@data.slice!(0..3).unpack1(signed ? 'i<' : 'I<'), mutation)
|
76
|
+
else read_int(signed: signed, mutation: mutation, order: 'BIG')
|
77
|
+
end
|
78
|
+
val
|
79
|
+
end
|
80
|
+
|
81
|
+
# Reads a long value from the {Buffer#data}
|
82
|
+
# @param signed [Boolean] should the value be signed.
|
83
|
+
# @param mutation [String] mutation that should be applied to the long value
|
84
|
+
# @param order [String] they byte order to read the long value
|
85
|
+
def read_long(signed: false, mutation: :STD, order: 'BIG')
|
86
|
+
case order
|
87
|
+
when 'BIG'
|
88
|
+
mutate(@data.slice!(0..7).unpack1(signed ? 'q>' : 'Q>'), mutation)
|
89
|
+
when 'LITTLE'
|
90
|
+
mutate(@data.slice!(0..7).unpack1(signed ? 'q<' : 'Q<'), mutation)
|
91
|
+
else read_long(signed: signed, mutation: mutation, order: 'BIG')
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# Copyright (c) 2022, Patrick W.
|
98
|
+
# All rights reserved.
|
99
|
+
#
|
100
|
+
# Redistribution and use in source and binary forms, with or without
|
101
|
+
# modification, are permitted provided that the following conditions are met:
|
102
|
+
#
|
103
|
+
# * Redistributions of source code must retain the above copyright notice, this
|
104
|
+
# list of conditions and the following disclaimer.
|
105
|
+
#
|
106
|
+
# * Redistributions in binary form must reproduce the above copyright notice,
|
107
|
+
# this list of conditions and the following disclaimer in the documentation
|
108
|
+
# and/or other materials provided with the distribution.
|
109
|
+
#
|
110
|
+
# * Neither the name of the copyright holder nor the names of its
|
111
|
+
# contributors may be used to endorse or promote products derived from
|
112
|
+
# this software without specific prior written permission.
|
113
|
+
#
|
114
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
115
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
116
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
117
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
118
|
+
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
119
|
+
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
120
|
+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
121
|
+
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
122
|
+
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
123
|
+
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
@@ -0,0 +1,199 @@
|
|
1
|
+
# The IO module of the Rune.rb framework provides objects, modules, and functions to handle input/output operations.
|
2
|
+
module RuneRb::IO
|
3
|
+
|
4
|
+
# Provides functions for reading integer values from a string-based buffer.
|
5
|
+
module Readable
|
6
|
+
using RuneRb::Patches::IntegerRefinements
|
7
|
+
|
8
|
+
# Read data from the payload according to the option parameter.
|
9
|
+
# @param type [Symbol] the type of database to read
|
10
|
+
# @param mutation [Symbol] an option mutation to apply to the read value.
|
11
|
+
def read(type: :byte, signed: false, mutation: :STD, order: 'BIG', options: {})
|
12
|
+
return unless RuneRb::IO::Validation.validate(self, 'read', { bit_access: @bit_access, mutation: mutation, order: order })
|
13
|
+
|
14
|
+
case type
|
15
|
+
when :bits then read_bits(options[:amount])
|
16
|
+
when :byte then read_byte(signed: signed, mutation: mutation)
|
17
|
+
when :bytes then read_bytes(options[:amount] || 1, mutation: mutation)
|
18
|
+
when :short then read_short(signed: signed, mutation: mutation, order: order)
|
19
|
+
when :medium then read_medium(signed: signed, mutation: mutation, order: order)
|
20
|
+
when :int then read_int(signed: signed, mutation: mutation, order: order)
|
21
|
+
when :long then read_long(signed: signed, mutation: mutation, order: order)
|
22
|
+
when :smart then read_smart(signed: signed, mutation: mutation)
|
23
|
+
when :string then read_string
|
24
|
+
when :reverse_bytes then read_bytes_reverse(options[:amount] || 1, mutation: mutation)
|
25
|
+
else raise "Unrecognized read type! #{type}"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
# Read multiple bytes from the {Buffer#data}
|
32
|
+
# @param amount [Integer] the amount of bytes to read
|
33
|
+
# @param mutation [Symbol] the mutation to apply to read bytes.
|
34
|
+
def read_bytes(amount, mutation)
|
35
|
+
amount.times.each_with_object([]) { |_idx, arr| arr << read_byte(signed: false, mutation: mutation) }
|
36
|
+
end
|
37
|
+
|
38
|
+
# Probably did this wrong
|
39
|
+
# @param amount [Integer] the amount of bytes to read
|
40
|
+
# @param mutation [Symbol] an optional mutation to apply to the result.
|
41
|
+
def read_bytes_reverse(amount, mutation)
|
42
|
+
@data.reverse
|
43
|
+
value = read_bytes(amount, mutation)
|
44
|
+
@data.reverse
|
45
|
+
value
|
46
|
+
end
|
47
|
+
|
48
|
+
# Read a byte value from the {Buffer#data}
|
49
|
+
# @param signed [Boolean] should the value be signed.
|
50
|
+
# @param mutation [String] mutation that should be applied to the byte value.
|
51
|
+
def read_byte(mutation: :STD, signed: false)
|
52
|
+
val = mutate(@data.slice!(0)&.unpack1(signed ? 'c' : 'C') || 0, mutation)
|
53
|
+
signed ? val.signed(:byte) : val.unsigned(:byte)
|
54
|
+
end
|
55
|
+
|
56
|
+
# Reads a short value from the {Buffer#data}
|
57
|
+
# @param signed [Boolean] should the value be signed.
|
58
|
+
# @param mutation [String] mutation that should be applied to the short value
|
59
|
+
# @param order [String] they byte order to read the short value
|
60
|
+
def read_short(signed: false, mutation: :STD, order: 'BIG')
|
61
|
+
val = 0
|
62
|
+
case order
|
63
|
+
when 'BIG'
|
64
|
+
val += read_byte(signed: signed) << 8
|
65
|
+
val += read_byte(mutation: mutation, signed: signed)
|
66
|
+
when 'LITTLE'
|
67
|
+
val += read_byte(mutation: mutation, signed: signed)
|
68
|
+
val += read_byte(signed: signed) << 8
|
69
|
+
else read_short(signed: signed, mutation: mutation, order: 'BIG')
|
70
|
+
end
|
71
|
+
val
|
72
|
+
end
|
73
|
+
|
74
|
+
# Reads a medium value from the {Buffer#data}
|
75
|
+
# @param signed [Boolean] should the value be signed.
|
76
|
+
# @param mutation [String] mutation that should be applied to the medium value
|
77
|
+
# @param order [String] they byte order to read the medium value
|
78
|
+
def read_medium(signed: false, mutation: :STD, order: 'BIG')
|
79
|
+
val = 0
|
80
|
+
case order
|
81
|
+
when 'BIG'
|
82
|
+
val += read_byte(signed: signed) << 16
|
83
|
+
val += read_byte(signed: signed) << 8
|
84
|
+
val += read_byte(signed: signed, mutation: mutation)
|
85
|
+
when 'MIDDLE'
|
86
|
+
val += read_byte(signed: signed) << 8
|
87
|
+
val += read_byte(signed: signed, mutation: mutation)
|
88
|
+
val += read_byte(signed: signed) << 16
|
89
|
+
when 'LITTLE'
|
90
|
+
val += read_byte(signed: signed, mutation: mutation)
|
91
|
+
val += read_byte(signed: signed) << 8
|
92
|
+
val += read_byte(signed: signed) << 16
|
93
|
+
else read_medium(signed: signed, mutation: mutation, order: 'BIG')
|
94
|
+
end
|
95
|
+
val
|
96
|
+
end
|
97
|
+
|
98
|
+
# Reads a integer value from the {Buffer#data}
|
99
|
+
# @param signed [Boolean] should the value be signed.
|
100
|
+
# @param mutation [String] mutation that should be applied to the integer value
|
101
|
+
# @param order [String] they byte order to read the integer value
|
102
|
+
def read_int(signed: false, mutation: :STD, order: 'BIG')
|
103
|
+
val = 0
|
104
|
+
case order
|
105
|
+
when 'BIG'
|
106
|
+
val += read_byte(signed: signed) << 24
|
107
|
+
val += read_byte(signed: signed) << 16
|
108
|
+
val += read_byte(signed: signed) << 8
|
109
|
+
val += read_byte(signed: signed, mutation: mutation)
|
110
|
+
when 'MIDDLE'
|
111
|
+
val += read_byte(signed: signed) << 8
|
112
|
+
val += read_byte(signed: signed, mutation: mutation)
|
113
|
+
val += read_byte(signed: signed) << 24
|
114
|
+
val += read_byte(signed: signed) << 16
|
115
|
+
when 'INVERSE_MIDDLE'
|
116
|
+
val += read_byte(signed: signed) << 16
|
117
|
+
val += read_byte(signed: signed) << 24
|
118
|
+
val += read_byte(signed: signed, mutation: mutation)
|
119
|
+
val += read_byte(signed: signed) << 8
|
120
|
+
when 'LITTLE'
|
121
|
+
val += read_byte(signed: signed, mutation: mutation)
|
122
|
+
val += read_byte(signed: signed) << 8
|
123
|
+
val += read_byte(signed: signed) << 16
|
124
|
+
val += read_byte(signed: signed) << 24
|
125
|
+
else read_int(signed: signed, mutation:mutation, order: 'BIG')
|
126
|
+
end
|
127
|
+
val
|
128
|
+
end
|
129
|
+
|
130
|
+
# Reads a long value from the {Buffer#data}
|
131
|
+
# @param signed [Boolean] should the value be signed.
|
132
|
+
# @param mutation [String] mutation that should be applied to the long value
|
133
|
+
# @param order [String] they byte order to read the long value
|
134
|
+
def read_long(signed: false, mutation: :STD, order: 'BIG')
|
135
|
+
val = 0
|
136
|
+
case order
|
137
|
+
when 'BIG'
|
138
|
+
(RuneRb::IO::BYTE_SIZE * 7).downto(0) { |div| ((div % 8).zero? and div.positive?) ? val |= read_byte(signed: signed) << div : next }
|
139
|
+
val += read_byte(signed: signed, mutation: mutation)
|
140
|
+
when 'LITTLE'
|
141
|
+
val += read_byte(signed: signed, mutation: mutation)
|
142
|
+
(0).upto(RuneRb::IO::BYTE_SIZE * 7) { |div| ((div % 8).zero? and div.positive?) ? val |= read_byte(signed: signed) << div: next }
|
143
|
+
else read_long(signed: signed, mutation: mutation, order: 'BIG')
|
144
|
+
end
|
145
|
+
val
|
146
|
+
end
|
147
|
+
|
148
|
+
# Read a smart value from the {Buffer#data}
|
149
|
+
# @param signed [Boolean] should the value be signed.
|
150
|
+
# @param mutation [String] mutation that should be applied to the long value
|
151
|
+
def read_smart(signed: false, mutation: :STD)
|
152
|
+
val = peek.slice(0).unpack1(signed ? 'c' : 'C')
|
153
|
+
case signed
|
154
|
+
when true then val < 128 ? read_byte(mutation: mutation, signed: signed) - 64 : read_short(mutation: mutation, signed: signed, order: 'BIG') - 49_152
|
155
|
+
when false then val < 128 ? read_byte(mutation: mutation, signed: signed) : read_short(mutation: mutation, signed: signed, order: 'BIG') - 32_768
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
# Reads a string from the {Buffer#data}
|
160
|
+
# @return [String] the resulting string.
|
161
|
+
def read_string
|
162
|
+
val = ''
|
163
|
+
while (res = read_byte; res != 10)
|
164
|
+
break if res == "\n"
|
165
|
+
|
166
|
+
val << res
|
167
|
+
end
|
168
|
+
val
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
# Copyright (c) 2022, Patrick W.
|
174
|
+
# All rights reserved.
|
175
|
+
#
|
176
|
+
# Redistribution and use in source and binary forms, with or without
|
177
|
+
# modification, are permitted provided that the following conditions are met:
|
178
|
+
#
|
179
|
+
# * Redistributions of source code must retain the above copyright notice, this
|
180
|
+
# list of conditions and the following disclaimer.
|
181
|
+
#
|
182
|
+
# * Redistributions in binary form must reproduce the above copyright notice,
|
183
|
+
# this list of conditions and the following disclaimer in the documentation
|
184
|
+
# and/or other materials provided with the distribution.
|
185
|
+
#
|
186
|
+
# * Neither the name of the copyright holder nor the names of its
|
187
|
+
# contributors may be used to endorse or promote products derived from
|
188
|
+
# this software without specific prior written permission.
|
189
|
+
#
|
190
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
191
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
192
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
193
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
194
|
+
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
195
|
+
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
196
|
+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
197
|
+
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
198
|
+
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
199
|
+
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|