Files
Timofey Solomko cf044550f1 [swcomp] Add --multi-decompress option to bz2 command
This option allows to decompress multiple BZip2 archives concatenated together.
2026-05-14 12:42:02 +08:00

96 lines
3.4 KiB
Swift

// Copyright (c) 2026 Timofey Solomko
// Licensed under MIT License
//
// See LICENSE for license information
import Foundation
import SWCompression
import SwiftCLI
// This extension allows to use BZip2.BlockSize as a Key option.
// The extension is empty because there is a default implementation for a ConvertibleFromString when the RawValue type
// of the enum (Int, in this case) is ConvertibleFromString itself.
extension BZip2.BlockSize: ConvertibleFromString {}
final class BZip2Command: Command {
let name = "bz2"
let shortDescription = "Creates or extracts a BZip2 archive"
@Flag("-c", "--compress", description: "Compress an input file into a BZip2 archive")
var compress: Bool
@Flag("-d", "--decompress", description: "Decompress a BZip2 archive")
var decompress: Bool
@Flag("-m", "--multi-decompress", description: "Decompress multiple BZip2 archives concatenated together")
var multiDecompress: Bool
@Key("-b", "--block-size", description: "Set the block size for compression to a multiple of 100k bytes; possible " +
"values are from '1' (default) to '9'")
var blockSize: BZip2.BlockSize?
var optionGroups: [OptionGroup] {
return [.exactlyOne($compress, $decompress, $multiDecompress)]
}
@Param var input: String
@Param var output: String?
func execute() throws {
if decompress {
let inputURL = URL(fileURLWithPath: self.input)
let outputURL: URL
if let outputPath = output {
outputURL = URL(fileURLWithPath: outputPath)
} else if inputURL.pathExtension == "bz2" {
outputURL = inputURL.deletingPathExtension()
} else {
swcompExit(.noOutputPath)
}
let fileData = try Data(contentsOf: inputURL, options: .mappedIfSafe)
let decompressedData = try BZip2.decompress(data: fileData)
try decompressedData.write(to: outputURL)
} else if multiDecompress {
let inputURL = URL(fileURLWithPath: self.input)
let outputURL: URL
if let outputPath = output {
outputURL = URL(fileURLWithPath: outputPath)
} else if inputURL.pathExtension == "bz2" {
outputURL = inputURL.deletingPathExtension()
} else {
swcompExit(.noOutputPath)
}
let fileData = try Data(contentsOf: inputURL, options: .mappedIfSafe)
let output = try BZip2.multiDecompress(data: fileData)
try "".write(to: outputURL, atomically: true, encoding: .utf8)
let handle = try FileHandle(forWritingTo: outputURL)
for data in output {
try handle.write(contentsOf: data)
try handle.synchronize()
}
try handle.close()
} else if compress {
let inputURL = URL(fileURLWithPath: self.input)
let outputURL: URL
if let outputPath = output {
outputURL = URL(fileURLWithPath: outputPath)
} else {
outputURL = inputURL.appendingPathExtension("bz2")
}
let fileData = try Data(contentsOf: inputURL, options: .mappedIfSafe)
let compressedData = BZip2.compress(data: fileData, blockSize: blockSize ?? .one)
try compressedData.write(to: outputURL)
}
}
}