Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
449 changes: 449 additions & 0 deletions apple/TablePro/Core/Services/Formatting/BinaryValues/AvroDecoder.swift

Large diffs are not rendered by default.

339 changes: 339 additions & 0 deletions apple/TablePro/Core/Services/Formatting/BinaryValues/AvroSchema.swift

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,33 @@

import Foundation

internal enum BinaryValueFormat: String, Equatable, Sendable {
internal enum BinaryValueFormat: Hashable, Sendable {
case messagePack
case protobuf
case igbinary
case avro(schemaID: String)

var displayName: String {
switch self {
case .messagePack: return "MessagePack"
case .protobuf: return "Protobuf"
case .igbinary: return "igbinary"
case .avro: return "Avro"
}
}
}

internal enum BinaryValueTree: Sendable {
case json(JSONTreeNode)
case protobuf(ProtobufTreeNode)
case php(PhpTreeNode)
}

internal enum BinaryValueDocument: Sendable {
case decoded(tree: BinaryValueTree, text: String, note: String?)
case failed(BinaryValueDecodeError)
// Nothing to judge the bytes by: the format names a schema this Mac no longer has.
case missingSchema
}

// Pure: the grid calls it per cell on the main actor, the viewer off it.
Expand All @@ -48,6 +55,14 @@ internal enum BinaryValueDecoding {
case .protobuf:
let fields = try ProtobufWireDecoder.decode(data, maxValues: budget).fields
text = ProtobufTextWriter.text(fields, multiLine: false, limit: limit)
case .igbinary:
text = PhpSerializeWriter.text(try IgbinaryDecoder.decode(data, maxValues: budget), limit: limit)
case .avro(let schemaID):
guard let schema = AvroSchemaStore.shared.schema(id: schemaID) else { return nil }
let value = try AvroDecoder.decode(
data, schema: schema, maxValues: budget, maxValuesRead: AvroDecoder.maxValuesReadInCell
).value
text = MessagePackTextWriter.json(value, pretty: false, limit: limit)
}
} catch {
return nil
Expand Down Expand Up @@ -92,6 +107,27 @@ internal enum BinaryValueDecoding {
),
note: message.framing.map(framingNote)
)
case .igbinary:
let value = try IgbinaryDecoder.decode(data)
return .decoded(
tree: .php(PhpTreeBuilder.build(from: value)),
text: capped(
PhpSerializeWriter.text(value, limit: writerLimit(forCap: maxViewerTextLength)),
at: maxViewerTextLength
),
note: nil
)
case .avro(let schemaID):
guard let schema = AvroSchemaStore.shared.schema(id: schemaID) else { return .missingSchema }
let message = try AvroDecoder.decode(data, schema: schema)
return .decoded(
tree: .json(MessagePackTreeBuilder.build(from: message.value)),
text: capped(
MessagePackTextWriter.json(message.value, pretty: true, limit: writerLimit(forCap: maxViewerTextLength)),
at: maxViewerTextLength
),
note: message.framing.map(framingNote)
)
}
} catch let error as BinaryValueDecodeError {
return .failed(error)
Expand All @@ -100,6 +136,18 @@ internal enum BinaryValueDecoding {
}
}

private static func framingNote(_ framing: AvroFraming) -> String {
switch framing {
case .confluent(let schemaID):
return String(format: String(localized: "Schema Registry framing: schema ID %lld"), Int(schemaID))
case .singleObject(let fingerprint):
return String(
format: String(localized: "Avro single-object encoding: schema fingerprint %@"),
String(format: "%016llX", fingerprint)
)
}
}

private static func framingNote(_ framing: ProtobufFraming) -> String {
let indexes = framing.messageIndexes.map(String.init).joined(separator: ", ")
return String(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ internal struct BinaryValueDecodeError: Error, Equatable, Sendable {
case integerOutOfRange
case invalidField
case unmatchedGroupEnd
case unknownVersion(UInt32)
case unknownReference(Int)
case indexOutOfRange(Int)
case invalidLength
case otherSchema(fingerprint: UInt64)
}

let kind: Kind
Expand Down Expand Up @@ -42,6 +47,23 @@ internal struct BinaryValueDecodeError: Error, Equatable, Sendable {
return String(format: String(localized: "Byte %lld does not start a valid field."), offset)
case .unmatchedGroupEnd:
return String(format: String(localized: "The group end at byte %lld matches no group start."), offset)
case .unknownVersion(let version):
return String(format: String(localized: "The header names version %lld, which this format does not have."), Int(version))
case .unknownReference(let index):
return String(
format: String(localized: "Byte %lld refers back to item %lld, which comes later or not at all."),
offset,
index
)
case .indexOutOfRange(let index):
return String(format: String(localized: "Byte %lld picks entry %lld, which the schema does not have."), offset, index)
case .invalidLength:
return String(format: String(localized: "The length at byte %lld is negative."), offset)
case .otherSchema(let fingerprint):
return String(
format: String(localized: "The value was written with the schema whose fingerprint is %@, not this column's."),
String(format: "%016llX", fingerprint)
)
}
}
}
Expand Down
Loading
Loading