HaishinKit.swift/Sources/RTMP/AMF3Serializer.swift

573 lines
16 KiB
Swift

import Foundation
final class AMFReference {
var strings: [String] = []
var objects: [Any] = []
func getString(_ index: Int) throws -> String {
if strings.count <= index {
throw AMFSerializerError.outOfIndex
}
return strings[index]
}
func getObject(_ index: Int) throws -> Any {
if objects.count <= index {
throw AMFSerializerError.outOfIndex
}
return objects[index]
}
func indexOf<T: Equatable>(_ value: T) -> Int? {
for (index, data) in objects.enumerated() {
if let data: T = data as? T, data == value {
return index
}
}
return nil
}
func indexOf(_ value: [Int32]) -> Int? {
nil
}
func indexOf(_ value: [UInt32]) -> Int? {
nil
}
func indexOf(_ value: [Double]) -> Int? {
nil
}
func indexOf(_ value: [Any?]) -> Int? {
nil
}
func indexOf(_ value: ASObject) -> Int? {
for (index, data) in objects.enumerated() {
if let data: ASObject = data as? ASObject, data.description == value.description {
return index
}
}
return nil
}
func indexOf(_ value: String) -> Int? {
strings.firstIndex(of: value)
}
}
// MARK: -
/**
AMF3 Serializer
- seealso: http://wwwimages.adobe.com/www.adobe.com/content/dam/Adobe/en/devnet/amf/pdf/amf-file-format-spec.pdf
*/
final class AMF3Serializer: ByteArray {
enum `Type`: UInt8 {
case undefined = 0x00
case null = 0x01
case boolFalse = 0x02
case boolTrue = 0x03
case integer = 0x04
case number = 0x05
case string = 0x06
case xml = 0x07
case date = 0x08
case array = 0x09
case object = 0x0A
case xmlString = 0x0B
case byteArray = 0x0C
case vectorInt = 0x0D
case vectorUInt = 0x0E
case vectorNumber = 0x0F
case vectorObject = 0x10
case dictionary = 0x11
}
var reference = AMFReference()
}
extension AMF3Serializer: AMFSerializer {
// MARK: AMFSerializer
@discardableResult
func serialize(_ value: Any?) -> Self {
if value == nil {
return writeUInt8(Type.null.rawValue)
}
switch value {
case let value as Int:
return serialize(Double(value))
case let value as UInt:
return serialize(Double(value))
case let value as Int8:
return serialize(Double(value))
case let value as UInt8:
return serialize(Double(value))
case let value as Int16:
return serialize(Double(value))
case let value as UInt16:
return serialize(Double(value))
case let value as Int32:
return serialize(Double(value))
case let value as UInt32:
return serialize(Double(value))
case let value as Float:
return serialize(Double(value))
case let value as Double:
return serialize(Double(value))
case let value as Date:
return serialize(value)
case let value as String:
return serialize(value)
case let value as Bool:
return serialize(value)
case let value as ASArray:
return serialize(value)
case let value as ASObject:
return serialize(value)
default:
return writeUInt8(Type.undefined.rawValue)
}
}
func deserialize() throws -> Any? {
guard let type = Type(rawValue: try readUInt8()) else {
throw AMFSerializerError.deserialize
}
position -= 1
switch type {
case .undefined:
position += 1
return kASUndefined
case .null:
position += 1
return nil
case .boolFalse:
return try deserialize() as Bool
case .boolTrue:
return try deserialize() as Bool
case .integer:
return try deserialize() as Int
case .number:
return try deserialize() as Double
case .string:
return try deserialize() as String
case .xml:
return try deserialize() as ASXMLDocument
case .date:
return try deserialize() as Date
case .array:
return try deserialize() as ASArray
case .object:
return try deserialize() as ASObject
case .xmlString:
return try deserialize() as ASXML
case .byteArray:
return try deserialize() as ByteArray
case .vectorInt:
return try deserialize() as [Int32]
case .vectorUInt:
return try deserialize() as [UInt32]
case .vectorNumber:
return try deserialize() as [Double]
case .vectorObject:
return try deserialize() as [Any?]
case .dictionary:
assertionFailure("Unsupported")
return nil
}
}
/**
- seealso: 3.4 false Type
- seealso: 3.5 true type
*/
@discardableResult
func serialize(_ value: Bool) -> Self {
writeUInt8(value ? Type.boolTrue.rawValue: Type.boolFalse.rawValue)
}
func deserialize() throws -> Bool {
switch try readUInt8() {
case Type.boolTrue.rawValue:
return true
case Type.boolFalse.rawValue:
return false
default:
throw AMFSerializerError.deserialize
}
}
/**
- seealso: 3.6 integer type
*/
@discardableResult
func serialize(_ value: Int) -> Self {
writeUInt8(Type.integer.rawValue).serializeU29(value)
}
func deserialize() throws -> Int {
guard try readUInt8() == Type.integer.rawValue else {
throw AMFSerializerError.deserialize
}
return try deserializeU29()
}
/**
- seealso: 3.7 double type
*/
@discardableResult
func serialize(_ value: Double) -> Self {
writeUInt8(Type.number.rawValue).writeDouble(value)
}
func deserialize() throws -> Double {
guard try readUInt8() == Type.number.rawValue else {
throw AMFSerializerError.deserialize
}
return try readDouble()
}
/**
- seealso: 3.8 String type
*/
@discardableResult
func serialize(_ value: String) -> Self {
writeUInt8(Type.string.rawValue).serializeUTF8(value)
}
func deserialize() throws -> String {
guard try readUInt8() == Type.string.rawValue else {
throw AMFSerializerError.deserialize
}
return try deserializeUTF8()
}
/**
- seealso: 3.9 XML type
*/
@discardableResult
func serialize(_ value: ASXMLDocument) -> Self {
writeUInt8(Type.xml.rawValue)
if let index: Int = reference.indexOf(value) {
return serializeU29(index << 1)
}
reference.objects.append(value)
let utf8 = Data(value.description.utf8)
return serialize(utf8.count << 1 | 0x01).writeBytes(utf8)
}
func deserialize() throws -> ASXMLDocument {
guard try readUInt8() == Type.xml.rawValue else {
throw AMFSerializerError.deserialize
}
let refs: Int = try deserializeU29()
if (refs & 0x01) == 0 {
guard let document: ASXMLDocument = try reference.getObject(refs >> 1) as? ASXMLDocument else {
throw AMFSerializerError.deserialize
}
return document
}
let document = ASXMLDocument(data: try readUTF8Bytes(refs >> 1))
reference.objects.append(document)
return document
}
/**
- seealso: 3.10 Date type
*/
@discardableResult
func serialize(_ value: Date) -> Self {
writeUInt8(Type.date.rawValue)
if let index: Int = reference.indexOf(value) {
return serializeU29(index << 1)
}
reference.objects.append(value)
return serializeU29(0x01).writeDouble(value.timeIntervalSince1970 * 1000)
}
func deserialize() throws -> Date {
guard try readUInt8() == Type.date.rawValue else {
throw AMFSerializerError.deserialize
}
let refs: Int = try deserializeU29()
if (refs & 0x01) == 0 {
guard let date: Date = try reference.getObject(refs >> 1) as? Date else {
throw AMFSerializerError.deserialize
}
return date
}
let date = Date(timeIntervalSince1970: try readDouble() / 1000)
reference.objects.append(date)
return date
}
/**
- seealso: 3.11 Array type
*/
@discardableResult
func serialize(_ value: ASArray) -> Self {
writeUInt8(Type.array.rawValue)
if let index: Int = reference.indexOf(value) {
return serializeU29(index << 1)
}
reference.objects.append(value)
serialize(value.length << 1 | 0x01)
for (key, value) in value.dict {
serialize(key).serialize(value)
}
serialize("")
for value in value.data {
serialize(value)
}
return self
}
func deserialize() throws -> ASArray {
guard try readUInt8() == Type.array.rawValue else {
throw AMFSerializerError.deserialize
}
return ASArray()
}
/**
- seealso: 3.12 Object type
- note: ASObject = Dictionary<String, Any?>
*/
@discardableResult
func serialize(_ value: ASObject) -> Self {
writeUInt8(Type.object.rawValue)
if let index: Int = reference.indexOf(value) {
return serializeU29(index << 1)
}
reference.objects.append(value)
for (key, value) in value {
serialize(key).serialize(value)
}
return serialize("")
}
func deserialize() throws -> ASObject {
guard try readUInt8() == Type.object.rawValue else {
throw AMFSerializerError.deserialize
}
return ASObject()
}
/**
- seealso: 3.13 XML type
*/
@discardableResult
func serialize(_ value: ASXML) -> Self {
writeUInt8(Type.xmlString.rawValue)
if let index: Int = reference.indexOf(value) {
return serializeU29(index << 1)
}
reference.objects.append(value)
let utf8 = Data(value.description.utf8)
return serialize(utf8.count << 1 | 0x01).writeBytes(utf8)
}
func deserialize() throws -> ASXML {
guard try readUInt8() == Type.xml.rawValue else {
throw AMFSerializerError.deserialize
}
let refs: Int = try deserializeU29()
if (refs & 0x01) == 0 {
guard let xml: ASXML = try reference.getObject(refs >> 1) as? ASXML else {
throw AMFSerializerError.deserialize
}
return xml
}
let xml = ASXML(data: try readUTF8Bytes(refs >> 1))
reference.objects.append(xml)
return xml
}
/**
- seealso: 3.14 ByteArray type
- note: flash.utils.ByteArray = lf.ByteArray
*/
@discardableResult
func serialize(_ value: ByteArray) -> Self {
self
}
func deserialize() throws -> ByteArray {
ByteArray()
}
/**
- seealso: 3.15 Vector Type, vector-int-type
*/
@discardableResult
func serialize(_ value: [Int32]) -> Self {
writeUInt8(Type.vectorInt.rawValue)
if let index: Int = reference.indexOf(value) {
return serializeU29(index << 1)
}
reference.objects.append(value)
serializeU29(value.count << 1 | 0x01).writeUInt8(0x00)
for v in value {
writeInt32(v)
}
return self
}
func deserialize() throws -> [Int32] {
guard try readUInt8() == Type.vectorInt.rawValue else {
throw AMFSerializerError.deserialize
}
return []
}
/**
- seealso: 3.15 Vector Type, vector-uint-type
*/
@discardableResult
func serialize(_ value: [UInt32]) -> Self {
writeUInt8(Type.vectorUInt.rawValue)
if let index: Int = reference.indexOf(value) {
return serializeU29(index << 1)
}
reference.objects.append(value)
serializeU29(value.count << 1 | 0x01).writeUInt8(0x00)
for v in value {
writeUInt32(v)
}
return self
}
func deserialize() throws -> [UInt32] {
guard try readUInt8() == Type.vectorUInt.rawValue else {
throw AMFSerializerError.deserialize
}
return []
}
/**
- seealso: 3.15 Vector Type, vector-number-type
*/
@discardableResult
func serialize(_ value: [Double]) -> Self {
writeUInt8(Type.vectorNumber.rawValue)
if let index: Int = reference.indexOf(value) {
return serializeU29(index << 1)
}
reference.objects.append(value)
serializeU29(value.count << 1 | 0x01).writeUInt8(0x00)
for v in value {
writeDouble(v)
}
return self
}
func deserialize() throws -> [Double] {
guard try readUInt8() == Type.vectorNumber.rawValue else {
throw AMFSerializerError.deserialize
}
return []
}
/**
- seealso: 3.15 Vector Type, vector-object-type
*/
@discardableResult
func serialize(_ value: [Any?]) -> Self {
writeUInt8(Type.vectorObject.rawValue)
if let index: Int = reference.indexOf(value) {
return serializeU29(index << 1)
}
reference.objects.append(value)
serializeU29(value.count << 1 | 0x01).serializeUTF8("*")
for v in value {
serialize(v)
}
return self
}
func deserialize() throws -> [Any?] {
guard try readUInt8() == Type.array.rawValue else {
throw AMFSerializerError.deserialize
}
return []
}
/**
- seealso: 1.3.1 Variable Length Unsigned 29-bit Integer Encoding
*/
@discardableResult
private func serializeU29(_ value: Int) -> Self {
if value < Int(Int32.min) || Int(Int32.max) < value {
return serialize(Double(value))
}
let value = UInt32(value)
switch UInt32(0) {
case value & 0xFFFFFF80:
return writeUInt8(UInt8(value & 0x7f))
case value & 0xFFFFC000:
return writeUInt8(UInt8(value >> 7 | 0x80))
.writeUInt8(UInt8(value & 0x7F))
case value & 0xFFE00000:
return writeUInt8(UInt8(value >> 14 | 0x80))
.writeUInt8(UInt8(value >> 7 | 0x80))
.writeUInt8(UInt8(value & 0x7F))
default:
return writeUInt8(UInt8(value >> 22 | 0x80))
.writeUInt8(UInt8(value >> 15 | 0x80))
.writeUInt8(UInt8(value >> 8 | 0x80))
.writeUInt8(UInt8(value & 0xFF))
}
}
private func deserializeU29() throws -> Int {
var count: Int = 1
var result: Int = 0
var byte: UInt8 = try readUInt8()
while byte & 0x80 != 0 && count < 4 {
result <<= 7
result |= Int(byte & 0x7F)
byte = try readUInt8()
count += 1
}
if count < 4 {
result <<= 7
result |= Int(byte)
} else {
result <<= 8
result |= Int(byte)
}
return result
}
/**
- seealso: 1.3.2 Strings and UTF-8
*/
@discardableResult
private func serializeUTF8(_ value: String) -> Self {
if value.isEmpty {
return serializeU29(0x01)
}
if let index: Int = reference.indexOf(value) {
return serializeU29(index << 1)
}
let utf8 = Data(value.utf8)
reference.strings.append(value)
return serializeU29(utf8.count << 1 | 0x01).writeBytes(utf8)
}
private func deserializeUTF8() throws -> String {
let ref: Int = try deserializeU29()
if (ref & 0x01) == 0 {
return try reference.getString(ref >> 1)
}
let string: String = try readUTF8Bytes(length)
reference.strings.append(string)
return string
}
}