mirror of
https://github.com/iv-org/protodec.git
synced 2025-01-24 06:00:59 -05:00
Fix decoding Bit32 and Bit64
This commit is contained in:
parent
5b60fe7736
commit
e746d93c18
100
src/protodec.cr
100
src/protodec.cr
@ -37,22 +37,6 @@ struct VarLong
|
|||||||
|
|
||||||
result
|
result
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.to_io(io : IO, value : Int64)
|
|
||||||
io.write_byte 0x00 if value == 0x00
|
|
||||||
value = value.to_u64
|
|
||||||
|
|
||||||
while value != 0
|
|
||||||
byte = (value & 0x7f).to_u8
|
|
||||||
value >>= 7
|
|
||||||
|
|
||||||
if value != 0
|
|
||||||
byte |= 0x80
|
|
||||||
end
|
|
||||||
|
|
||||||
io.write_byte byte
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
struct ProtoBuf::Any
|
struct ProtoBuf::Any
|
||||||
@ -64,7 +48,8 @@ struct ProtoBuf::Any
|
|||||||
end
|
end
|
||||||
|
|
||||||
alias Type = Int64 |
|
alias Type = Int64 |
|
||||||
Bytes |
|
Float64 |
|
||||||
|
Array(UInt8) |
|
||||||
String |
|
String |
|
||||||
Hash(Int32, Type)
|
Hash(Int32, Type)
|
||||||
|
|
||||||
@ -73,6 +58,15 @@ struct ProtoBuf::Any
|
|||||||
def initialize(@raw : Type)
|
def initialize(@raw : Type)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.likely_string?(bytes)
|
||||||
|
return bytes.all? { |byte| {'\t'.ord, '\n'.ord, '\r'.ord}.includes?(byte) || 0x20 <= byte <= 0x7e }
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.likely_base64?(string)
|
||||||
|
decoded = URI.unescape(URI.unescape(string))
|
||||||
|
return decoded.size % 4 == 0 && decoded.match(/[A-Za-z0-9_+\/-]+=+/)
|
||||||
|
end
|
||||||
|
|
||||||
def self.parse(io : IO)
|
def self.parse(io : IO)
|
||||||
from_io(io, ignore_exceptions: true)
|
from_io(io, ignore_exceptions: true)
|
||||||
end
|
end
|
||||||
@ -89,40 +83,64 @@ struct ProtoBuf::Any
|
|||||||
case type
|
case type
|
||||||
when Tag::VarInt
|
when Tag::VarInt
|
||||||
value = io.read_bytes(VarLong)
|
value = io.read_bytes(VarLong)
|
||||||
|
when Tag::Bit32
|
||||||
|
value = io.read_bytes(Int32)
|
||||||
|
bytes = IO::Memory.new
|
||||||
|
value.to_io(bytes, IO::ByteFormat::LittleEndian)
|
||||||
|
bytes.rewind
|
||||||
|
|
||||||
|
begin
|
||||||
|
value = bytes.read_bytes(Float32, format: IO::ByteFormat::LittleEndian).to_f64
|
||||||
|
rescue ex
|
||||||
|
value = value.to_i64
|
||||||
|
end
|
||||||
when Tag::Bit64
|
when Tag::Bit64
|
||||||
value = Bytes.new(8)
|
value = io.read_bytes(Int64)
|
||||||
io.read_fully(value)
|
bytes = IO::Memory.new
|
||||||
|
value.to_io(bytes, IO::ByteFormat::LittleEndian)
|
||||||
|
bytes.rewind
|
||||||
|
|
||||||
|
begin
|
||||||
|
value = bytes.read_bytes(Float64, format: IO::ByteFormat::LittleEndian)
|
||||||
|
rescue ex
|
||||||
|
end
|
||||||
when Tag::LengthDelimited
|
when Tag::LengthDelimited
|
||||||
bytes = Bytes.new(io.read_bytes(VarLong))
|
size = io.read_bytes(VarLong)
|
||||||
|
raise "Invalid size" if size > 2**20
|
||||||
|
|
||||||
|
bytes = Bytes.new(size)
|
||||||
io.read_fully(bytes)
|
io.read_fully(bytes)
|
||||||
|
|
||||||
if bytes.empty?
|
if bytes.empty?
|
||||||
value = ""
|
value = ""
|
||||||
else
|
else
|
||||||
begin
|
if likely_string?(bytes)
|
||||||
value = from_io(IO::Memory.new(Base64.decode(URI.unescape(String.new(bytes))))).raw
|
value = String.new(bytes)
|
||||||
rescue ex
|
|
||||||
if bytes.all? { |byte| {'\t'.ord, '\n'.ord, '\r'.ord}.includes?(byte) || byte >= 0x20 }
|
if likely_base64?(value)
|
||||||
value = String.new(bytes)
|
|
||||||
else
|
|
||||||
begin
|
begin
|
||||||
value = from_io(IO::Memory.new(bytes)).raw
|
value = from_io(IO::Memory.new(Base64.decode(URI.unescape(URI.unescape(value)))), ignore_exceptions: true).raw
|
||||||
rescue ex
|
rescue ex
|
||||||
value = bytes
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
value = from_io(IO::Memory.new(bytes)).raw
|
||||||
|
rescue ex
|
||||||
|
value = bytes.to_a
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
when Tag::Bit32
|
|
||||||
value = Bytes.new(4)
|
|
||||||
io.read_fully(value)
|
|
||||||
else
|
else
|
||||||
break if ignore_exceptions
|
|
||||||
raise "Invalid type #{type}"
|
raise "Invalid type #{type}"
|
||||||
end
|
end
|
||||||
|
|
||||||
item[field] = value.as(Type)
|
item[field] = value.as(Type)
|
||||||
end
|
end
|
||||||
|
rescue ex
|
||||||
|
if !ignore_exceptions
|
||||||
|
raise ex
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
item
|
item
|
||||||
@ -141,23 +159,29 @@ end
|
|||||||
enum InputType
|
enum InputType
|
||||||
Base64
|
Base64
|
||||||
Hex
|
Hex
|
||||||
|
Raw
|
||||||
end
|
end
|
||||||
|
|
||||||
input_type = InputType::Hex
|
input_type = InputType::Hex
|
||||||
|
|
||||||
OptionParser.parse! do |parser|
|
OptionParser.parse! do |parser|
|
||||||
parser.banner = "Usage: protodec [arguments]\n"
|
parser.banner = <<-'END_USAGE'
|
||||||
|
Usage: protodec [arguments]
|
||||||
|
Command-line decoder for arbitrary protobuf data.
|
||||||
|
END_USAGE
|
||||||
parser.on("-d", "--decode", "STDIN is Base64-encoded") { input_type = InputType::Base64 }
|
parser.on("-d", "--decode", "STDIN is Base64-encoded") { input_type = InputType::Base64 }
|
||||||
parser.on("-h", "--help", "Show this help") { puts parser }
|
parser.on("-r", "--raw", "STDIN is raw binary data") { input_type = InputType::Raw }
|
||||||
|
parser.on("-h", "--help", "Show this help") { puts parser; exit(0) }
|
||||||
end
|
end
|
||||||
|
|
||||||
input = STDIN.gets_to_end
|
input = STDIN.gets_to_end
|
||||||
case input_type
|
case input_type
|
||||||
when InputType::Hex
|
|
||||||
array = input.split("-").map &.to_i(16).to_u8
|
|
||||||
input = Slice.new(array.size) { |i| array[i] }
|
|
||||||
when InputType::Base64
|
when InputType::Base64
|
||||||
input = Base64.decode(URI.unescape(input))
|
input = Base64.decode(URI.unescape(URI.unescape(input)))
|
||||||
|
when InputType::Hex
|
||||||
|
array = input.strip.split(/[- ,]+/).map &.to_i(16).to_u8
|
||||||
|
input = Slice.new(array.size) { |i| array[i] }
|
||||||
|
when InputType::Raw
|
||||||
end
|
end
|
||||||
|
|
||||||
pp ProtoBuf::Any.parse(IO::Memory.new(input)).raw
|
pp ProtoBuf::Any.parse(IO::Memory.new(input)).raw
|
||||||
|
Loading…
Reference in New Issue
Block a user