I really don’t know where to post stupid questions… so here we are:
I’m currently building a file parser and I’m looking for a way to represent different data structures within a datastream.
I got the basic functionality working and can parse the given file but my code is all over the place and not well maintainable. The problem that I have is, that Swift Dicts can’t have different types so I’m relying on a pattern like [String: Any] to represent different binaries like UInt32, UInt16 and Strings.
Currently using an ugly mix of switch to parse different font formats.
Is there a better way? Like using a struct, enum, class? (Unfortunately I think I need a way to iterate over the properties(?)) Maybe Pointers are the solution, but I digged not into it.
Disclosure: I’m really new to all that binary stuff and bitwise stuff (also not a pro in swift). Anyway, I hope I expressed my self in a way you can understand my problem.
Best,
G
EDIT:
I’m now looking into Decodable and a custom Decoder...
enum Number {
case integer (Int)
case natural (UInt)
case real (Double)
case bool (Bool)
}
var zeros = [String : Number] ()
zeros ["Z"] = .integer (0)
zeros ["N"] = .natural (0)
zeros ["R"] = .real (0)
zeros ["B"] = .bool(false)
for (k, v) in zeros {
print (k, v)
}
// prints
Z integer(0)
N natural(0)
B bool(false)
R real(0.0)
enum FileHeader {
case signature (UInt32)
case length (UInt32)
case offset (UInt16)
...
}
Thats right? I’ll give it a try.
Edit:
Ah sorry. You mean to represent the structure as a dict in a typesafe way...
Edit 2: @ibex10 But accessing the value is complicated, isn't it?
I'm now doing something like this:
enum BinaryType {
case uint32 (UInt32)
case uint16 (UInt16)
case uint8 (UInt8)
case string (String)
var string: String? {
switch self {
case let .string(val):
return val
default:
return nil
}
}
var uint32: UInt32? {
switch self {
case let .uint32(val):
return val
case let .uint16(val):
return UInt32(val)
case let .uint8(val):
return UInt32(val)
case .string:
return nil
}
}
}
But that seems odd...
Edit 3:
Found that syntax – looks fancy..
guard case .uint32(let val) = enumVar else { return nil }
// do something with val
I meant your idea with enum but I missed the point..
The problem with using a struct is, that I cant programatically fill the struct based on the properties, because the files are structured differently.
But maybe I miss something.. what I really looking for is the best practice to decode a binary file into structured data which I can access easily. This solutions are just my simple ideas, because I don't know anything about that, I think.