diff --git a/Sources/InfomaniakCore/Extensions/Data+Compression.swift b/Sources/InfomaniakCore/Extensions/Data+Compression.swift new file mode 100644 index 0000000..002c912 --- /dev/null +++ b/Sources/InfomaniakCore/Extensions/Data+Compression.swift @@ -0,0 +1,50 @@ +/* + Infomaniak Core - iOS + Copyright (C) 2023 Infomaniak Network SA + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +import Foundation + +/// LZFSE Wrapper +@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *) +public extension Data { + /// Compressed data using a zstd like algorithm: lzfse + func compressed() -> Self? { + guard let data = try? (self as NSData).compressed(using: .lzfse) as Data else { + return nil + } + return data + } + + /// Decompressed data from a lzfse buffer + func decompressed() -> Self? { + guard let data = try? (self as NSData).decompressed(using: .lzfse) as Data else { + return nil + } + return data + } + + // MARK: - String helpers + + /// Decompressed string from a lzfse buffer + func decompressedString() -> String? { + guard let decompressedData = decompressed() else { + return nil + } + let string = String(decoding: decompressedData, as: UTF8.self) + return string + } +} diff --git a/Sources/InfomaniakCore/Extensions/String+Compression.swift b/Sources/InfomaniakCore/Extensions/String+Compression.swift new file mode 100644 index 0000000..21d59cb --- /dev/null +++ b/Sources/InfomaniakCore/Extensions/String+Compression.swift @@ -0,0 +1,35 @@ +/* + Infomaniak Core - iOS + Copyright (C) 2023 Infomaniak Network SA + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +import Foundation + +/// LZFSE Wrapper +@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *) +public extension String { + func compressed() -> Data? { + guard let data = data(using: .utf8), + let compressed = data.compressed() else { + return nil + } + return compressed + } + + static func decompressed(from data: Data) -> Self? { + data.decompressedString() + } +} diff --git a/Tests/InfomaniakCoreTests/UTCompression.swift b/Tests/InfomaniakCoreTests/UTCompression.swift new file mode 100644 index 0000000..5d58a15 --- /dev/null +++ b/Tests/InfomaniakCoreTests/UTCompression.swift @@ -0,0 +1,54 @@ +/* + Infomaniak Core - iOS + Copyright (C) 2023 Infomaniak Network SA + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +import InfomaniakCore +import XCTest + +@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *) +final class UTCompression: XCTestCase { + func testCompression() { + // GIVEN + let lowEntropy = "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + let lowEntropyData = lowEntropy.data(using: .utf8)! + + // WHEN + guard let highEntropy = lowEntropy.compressed() else { + XCTFail("Unexpected") + return + } + + // THEN + XCTAssertLessThan(highEntropy.count, lowEntropyData.count, "Compressed message should be smaller") + } + + func testCompressionDecompression() { + // GIVEN + let lowEntropy = "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + + // WHEN + guard let highEntropy = lowEntropy.compressed() else { + XCTFail("Unexpected") + return + } + + let decompressedString = highEntropy.decompressedString() + + // THEN + XCTAssertEqual(lowEntropy, decompressedString) + } +}