rrb 0.0.4 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- 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.
|