// // FileOperations.swift // Docsis Toolkit // // Created by Kilian Hofmann on 19.06.17. // Copyright © 2017 Kilian Hofmann. All rights reserved. // import Cocoa class FileOperations: NSObject { // MARK: - Timestamp related // 15 in threshold indicates some error static func encodeTimeStamp(stamp: String, threshold: String) -> UInt32 { let mappingEncode: Dictionary = ["-" : 0, "62.18": 1, "58.21": 2, "57": 3, "59.18": 4, "55.21": 5, "54": 6, "56.18": 7, "52.21": 8, "51": 9] let separated: Array = stamp.components(separatedBy: ":") let hours: UInt32 = UInt32(separated[0])! << 16 let minutes: UInt32 = UInt32(separated[1])! << 10 let seconds: UInt32 = UInt32(separated[2])! << 4 let thresholdI: UInt32 = mappingEncode[threshold] ?? 15 return hours | seconds | minutes | thresholdI } static func decodeTimestamp(stamp: UInt32) -> (String, String) { let mappingDecode: Dictionary = [0: "-", 1: "62.18", 2: "58.21", 3: "57", 4: "59.18", 5: "55.21", 6: "54", 7: "56.18", 8: "52.21", 9: "51", 15: "-"] let threshold: UInt32 = stamp & 0b1111 let seconds: UInt32 = (stamp >> 4) & 0b111111 let minutes: UInt32 = (stamp >> 10) & 0b111111 let hours: UInt32 = (stamp >> 16) & 0b11111 return ("\(String(format: "%02d", hours)):\(String(format: "%02d", minutes)):\(String(format: "%02d", seconds))", mappingDecode[threshold] ?? "\(15)") } // MARK: - Loss log related static func log(data: String, toLog path: String) { let dataToWrite = encodeTimeStamp(stamp: data, threshold: "") let file: UnsafeMutableRawPointer = UnsafeMutableRawPointer.allocate(byteCount: 3, alignment: 1) file.storeBytes(of: dataToWrite, as: UInt32.self) do { let fileData: NSMutableData = try NSMutableData(contentsOf: URL(fileURLWithPath: path)) fileData.append(file, length: 3) fileData.write(to: URL(fileURLWithPath: path), atomically: true) } catch _ { let fileData: NSMutableData = NSMutableData() fileData.append(file, length: 3) fileData.write(to: URL(fileURLWithPath: path), atomically: true) } file.deallocate() } static func log(data: String, toData out: inout Data) { let dataToWrite = encodeTimeStamp(stamp: data, threshold: "") let file: UnsafeMutableRawPointer = UnsafeMutableRawPointer.allocate(byteCount: 3, alignment: 1) file.storeBytes(of: dataToWrite, as: UInt32.self) let fileData: NSMutableData = NSMutableData() fileData.append(file, length: 3) out.append(fileData as Data) file.deallocate() } static func load(log Data: NSData) -> [String]? { var returnString: [String] = [] var i: Int = 0 while i < Data.length { let data: UnsafeMutableRawPointer = UnsafeMutableRawPointer.allocate(byteCount: 3, alignment: 1) Data.getBytes(data, range: NSRange(location: i, length: 3)) returnString.append("\(decodeTimestamp(stamp: data.load(as: UInt32.self)).0)\n") data.deallocate() i += 3 } if returnString.count > 0 { return returnString } return nil } // MARK: - Frequency logging (encoding) static func logUpstream(data: String, toFrequencyLog path: String) { let separated: Array = data.components(separatedBy: ";") var encodedTime: UInt32 = encodeTimeStamp(stamp: separated[0], threshold: separated[2]) // NaN Used for - var encodedPower: Int32 = Int32.min if (Double(separated[1]) != nil) { encodedPower = Int32(Double(Double(separated[1])! * 100.0)) } var stringSize: UInt8 = UInt8(separated[3].lengthOfBytes(using: .ascii)) let fileContent: NSMutableData = NSMutableData() fileContent.append(&stringSize, length: 1) fileContent.append(&encodedTime, length: 3) fileContent.append(&encodedPower, length: 4) fileContent.append(separated[3].data(using: .ascii)!) do { let fileData: NSMutableData = try NSMutableData(contentsOf: URL(fileURLWithPath: path)) fileData.append(fileContent as Data) fileData.write(to: URL(fileURLWithPath: path), atomically: true) } catch _ { fileContent.write(to: URL(fileURLWithPath: path), atomically: true) } } static func logUpstream(data: String, toData out: inout Data) { let separated: Array = data.components(separatedBy: ";") var encodedTime: UInt32 = encodeTimeStamp(stamp: separated[0], threshold: separated[2]) // NaN Used for - var encodedPower: Int32 = Int32.min if (Double(separated[1]) != nil) { encodedPower = Int32(Double(Double(separated[1])! * 100.0)) } var stringSize: UInt8 = UInt8(separated[3].lengthOfBytes(using: .ascii)) let fileContent: NSMutableData = NSMutableData() fileContent.append(&stringSize, length: 1) fileContent.append(&encodedTime, length: 3) fileContent.append(&encodedPower, length: 4) fileContent.append(separated[3].data(using: .ascii)!) out.append(fileContent as Data) } static func logDownstream(data: String, toFrequencyLog path: String) { let separated: Array = data.components(separatedBy: ";") var encodedTime: UInt32 = encodeTimeStamp(stamp: separated[0], threshold: "") // NaN Used for - var encodedPower: Int32 = Int32.min if (Double(separated[1]) != nil) { encodedPower = Int32(Double(Double(separated[1])! * 100.0)) } var encodedSNR = UInt8(separated[2]) ?? UInt8.max let fileContent: NSMutableData = NSMutableData() fileContent.append(&encodedTime, length: 3) fileContent.append(&encodedPower, length: 4) fileContent.append(&encodedSNR, length: 1) do { let fileData: NSMutableData = try NSMutableData(contentsOf: URL(fileURLWithPath: path)) fileData.append(fileContent as Data) fileData.write(to: URL(fileURLWithPath: path), atomically: true) } catch _ { fileContent.write(to: URL(fileURLWithPath: path), atomically: true) } } static func logDownstream(data: String, toData out: inout Data) { let separated: Array = data.components(separatedBy: ";") var encodedTime: UInt32 = encodeTimeStamp(stamp: separated[0], threshold: "") // NaN Used for - var encodedPower: Int32 = Int32.min if (Double(separated[1]) != nil) { encodedPower = Int32(Double(Double(separated[1])! * 100.0)) } var encodedSNR = UInt8(separated[2]) ?? UInt8.max let fileContent: NSMutableData = NSMutableData() fileContent.append(&encodedTime, length: 3) fileContent.append(&encodedPower, length: 4) fileContent.append(&encodedSNR, length: 1) out.append(fileContent as Data) } // MARK: - Frequency loading (decoding) static func loadUpstream(log data: NSData) -> [String]? { var variableAdjust: Int = 0 var returnString: [String] = [] while variableAdjust < data.length { // 1 for size // 3 for time and threshold // 4 for Power // var String let decodedSize: UInt8 = data.bytes.load(fromByteOffset: variableAdjust, as: UInt8.self) variableAdjust += 1 let retTimePtr: UnsafeMutableRawPointer = UnsafeMutableRawPointer.allocate(byteCount: 3, alignment: 1) data.getBytes(retTimePtr, range: NSRange(location: variableAdjust, length: 3)) variableAdjust += 3 let encodedTime: UInt32 = retTimePtr.load(as: UInt32.self) retTimePtr.deallocate() let decodedTimeStamp = decodeTimestamp(stamp: encodedTime).0 let decodedThreshold = decodeTimestamp(stamp: encodedTime).1 let retPwrPtr: UnsafeMutableRawPointer = UnsafeMutableRawPointer.allocate(byteCount: 4, alignment: 1) data.getBytes(retPwrPtr, range: NSRange(location: variableAdjust, length: 4)) var decodedPower: Any = retPwrPtr.load(as: Int32.self) retPwrPtr.deallocate() if decodedPower as! Int32 == Int32.min { decodedPower = "-" } variableAdjust += 4 let retStringPtr: UnsafeMutableRawPointer = UnsafeMutableRawPointer.allocate(byteCount: Int(decodedSize), alignment: 1) data.getBytes(retStringPtr, range: NSRange(location: variableAdjust, length: Int(decodedSize))) var retString: String = String(cString: retStringPtr.assumingMemoryBound(to: UInt8.self)) retStringPtr.deallocate() retString = String(retString[.. 0 { return returnString } return nil } static func loadDownstream(log data: NSData) -> [String]? { var variableAdjust: Int = 0 var returnString: [String] = [] while variableAdjust < data.length { // 3 for time // 4 for Power // 1 for SNR let retTimePtr: UnsafeMutableRawPointer = UnsafeMutableRawPointer.allocate(byteCount: 3, alignment: 1) data.getBytes(retTimePtr, range: NSRange(location: variableAdjust, length: 3)) variableAdjust += 3 let encodedTime: UInt32 = retTimePtr.load(as: UInt32.self) let decodedTimeStamp = decodeTimestamp(stamp: encodedTime).0 let retPwrPtr: UnsafeMutableRawPointer = UnsafeMutableRawPointer.allocate(byteCount: 4, alignment: 1) data.getBytes(retPwrPtr, range: NSRange(location: variableAdjust, length: 4)) var decodedPower: Any = retPwrPtr.load(as: Int32.self) retPwrPtr.deallocate() if decodedPower as! Int32 == Int32.min { decodedPower = "-" } variableAdjust += 4 var decodedSNR: Any = data.bytes.load(fromByteOffset: variableAdjust, as: UInt8.self) if decodedSNR as! UInt8 == UInt8.max { decodedSNR = "-" } variableAdjust += 1 var entry: String = "" guard decodedPower is Int32 else { entry.append("\(decodedTimeStamp);\(decodedPower as! String);") guard decodedSNR is UInt8 else { entry.append("\(decodedSNR as! String)") returnString.append(entry) continue } entry.append("\(decodedSNR as! UInt8)") returnString.append(entry) continue } entry.append("\(decodedTimeStamp);\((Double(decodedPower as! Int32) / 100.0));") guard decodedSNR is UInt8 else { entry.append("\(decodedSNR as! String)") returnString.append(entry) continue } entry.append("\(decodedSNR as! UInt8)") returnString.append(entry) } if returnString.count > 0 { return returnString } return nil } // MARK: - Convert static func convertLoss(log path: String, toFile pathOut: String) { do { var data: [String] = NSString(data: try NSData(contentsOfFile: path) as Data, encoding: String.Encoding.ascii.rawValue)!.components(separatedBy: "\n") data.removeLast() var dataOut: Data = Data() for entry in data { log(data: entry, toData: &dataOut) } (dataOut as NSData).write(toFile: pathOut, atomically: true) } catch { return } } static func convertUpstream(log path: String, toFile pathOut: String) { do { var data: [String] = NSString(data: try NSData(contentsOfFile: path) as Data, encoding: String.Encoding.ascii.rawValue)!.components(separatedBy: "\n") data.removeLast() data.removeFirst() var dataOut: Data = Data() for var entry in data { if entry.components(separatedBy: ";").count < 4 { entry.append(";-") } logUpstream(data: entry, toData: &dataOut) } (dataOut as NSData).write(toFile: pathOut, atomically: true) } catch { return } } static func convertDownstream(log path: String, toFile pathOut: String) { do { var data: [String] = NSString(data: try NSData(contentsOfFile: path) as Data, encoding: String.Encoding.ascii.rawValue)!.components(separatedBy: "\n") data.removeLast() data.removeFirst() var dataOut: Data = Data() for entry in data { logDownstream(data: entry, toData: &dataOut) } (dataOut as NSData).write(toFile: pathOut, atomically: true) } catch { return } } }