mirror of
https://github.com/GayPizzaSpecifications/darwin-apk.git
synced 2025-08-03 05:30:54 +00:00
decode index checksum too cus why not
also dumps prettier package descriptions to a file now wahoo I have good priorities
This commit is contained in:
@ -8,12 +8,14 @@ let package = Package(
|
||||
],
|
||||
dependencies: [
|
||||
.package(url: "https://github.com/apple/swift-argument-parser", from: "1.5.0"),
|
||||
.package(url: "https://github.com/apple/swift-algorithms", from: "1.2.0"),
|
||||
.package(url: "https://github.com/tsolomko/SWCompression", from: "4.8.6"),
|
||||
],
|
||||
targets: [
|
||||
.target(
|
||||
name: "darwin-apk",
|
||||
dependencies: [
|
||||
.product(name: "Algorithms", package: "swift-algorithms"),
|
||||
.product(name: "SWCompression", package: "SWCompression"),
|
||||
],
|
||||
path: "Sources/apk"),
|
||||
|
@ -29,3 +29,9 @@ extension ApkIndex {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension ApkIndex: CustomStringConvertible {
|
||||
var description: String {
|
||||
self.packages.map(String.init).joined(separator: "\n")
|
||||
}
|
||||
}
|
||||
|
116
Sources/apk/Index/ApkIndexDigest.swift
Normal file
116
Sources/apk/Index/ApkIndexDigest.swift
Normal file
@ -0,0 +1,116 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import Foundation
|
||||
import Algorithms
|
||||
import CryptoKit
|
||||
|
||||
struct ApkIndexDigest {
|
||||
let type: DigestType
|
||||
let data: Data
|
||||
|
||||
init?(type: DigestType, data: Data) {
|
||||
let len = switch type {
|
||||
case .md5: 16
|
||||
case .sha1: 20
|
||||
case .sha256: 32
|
||||
}
|
||||
guard len == data.count else {
|
||||
return nil
|
||||
}
|
||||
self.type = type
|
||||
self.data = data
|
||||
}
|
||||
|
||||
init?(decode: String) {
|
||||
enum Encoding { case hex, base64 }
|
||||
let getEncoding = { (c: Character) -> Encoding? in
|
||||
switch c {
|
||||
case "Q": .base64
|
||||
case "X": .hex
|
||||
default: nil
|
||||
}
|
||||
}
|
||||
let getDigestType = { (c: Character) -> DigestType? in
|
||||
switch c {
|
||||
case "1": .sha1
|
||||
case "2": .sha256
|
||||
default: nil
|
||||
}
|
||||
}
|
||||
|
||||
let hexData = { (from: Substring) -> Data? in
|
||||
// Ensure even number of characters
|
||||
guard from.count & ~0x1 == from.count else { return nil }
|
||||
//FIXME: will explode on encountering non-hexadecimal characters, works for now tho
|
||||
return Data(from.map(\.hexDigitValue).lazy
|
||||
.chunks(ofCount: 2)
|
||||
.map { UInt8($0.last!! + $0.first!! << 4) })
|
||||
}
|
||||
|
||||
if decode.count < 2 {
|
||||
return nil
|
||||
} else if _slowPath(decode.first!.isHexDigit) {
|
||||
// Legacy MD5 hex digest mode
|
||||
guard decode.count != 32, let decoded = hexData(decode[...]) else {
|
||||
return nil
|
||||
}
|
||||
self.init(type: .md5, data: decoded)
|
||||
} else {
|
||||
// First two characters are a letter for the encoding type:
|
||||
// - 'X': hex digest
|
||||
// - 'Q': base64 string
|
||||
// ...and a number for the hash digest type:
|
||||
// - '1': SHA-1
|
||||
// - '2': SHA-256 (SHA-2)
|
||||
guard
|
||||
let encoding = getEncoding(decode.first!),
|
||||
let digest = getDigestType(decode[decode.index(after: decode.startIndex)])
|
||||
else { return nil }
|
||||
let dataString = decode[decode.index(decode.startIndex, offsetBy: 2)...]
|
||||
|
||||
// The remaining characters are the encoded digest
|
||||
var decoded: Data? = nil
|
||||
if _fastPath(encoding == .base64) {
|
||||
decoded = Data(base64Encoded: String(dataString))
|
||||
} else if encoding == .hex {
|
||||
decoded = hexData(dataString)
|
||||
}
|
||||
|
||||
guard let decoded = decoded else {
|
||||
return nil
|
||||
}
|
||||
self.init(type: digest, data: decoded)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension ApkIndexDigest: Equatable, Hashable {
|
||||
@inlinable static func == (lhs: Self, rhs: Self) -> Bool {
|
||||
lhs.type == rhs.type && lhs.data == rhs.data
|
||||
}
|
||||
|
||||
func hash(into hasher: inout Hasher) {
|
||||
//self.type.hash(into: &hasher)
|
||||
self.data.hash(into: &hasher)
|
||||
}
|
||||
}
|
||||
|
||||
extension ApkIndexDigest {
|
||||
enum DigestType {
|
||||
case md5, sha1, sha256
|
||||
}
|
||||
}
|
||||
|
||||
extension ApkIndexDigest.DigestType: CustomStringConvertible {
|
||||
var description: String {
|
||||
switch self {
|
||||
case .md5: "MD5"
|
||||
case .sha1: "SHA-1"
|
||||
case .sha256: "SHA-256"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension ApkIndexDigest: CustomStringConvertible {
|
||||
var description: String { "[\(self.type)] \(self.data.map { String(format: "%02X", $0) }.joined())" }
|
||||
}
|
@ -3,7 +3,7 @@
|
||||
import Foundation
|
||||
|
||||
struct ApkIndexPackage: Hashable {
|
||||
let indexChecksum: String //TODO: Decode cus why not
|
||||
let indexChecksum: ApkIndexDigest
|
||||
let name: String
|
||||
let version: String
|
||||
let architecture: String?
|
||||
@ -30,7 +30,7 @@ struct ApkIndexPackage: Hashable {
|
||||
extension ApkIndexPackage {
|
||||
init(raw rawEntry: ApkRawIndexEntry) throws(Self.ParseError) {
|
||||
// Required fields
|
||||
var indexChecksum: String? = nil
|
||||
var indexChecksum: ApkIndexDigest? = nil
|
||||
var name: String? = nil
|
||||
var version: String? = nil
|
||||
var description: String? = nil
|
||||
@ -70,7 +70,10 @@ extension ApkIndexPackage {
|
||||
do { dependencies = try ApkIndexDependency.extract(record.value) }
|
||||
catch { throw .badValue(key: record.key) }
|
||||
case "C":
|
||||
indexChecksum = record.value // base64-encoded SHA1 hash prefixed with "Q1"
|
||||
guard let digest = ApkIndexDigest(decode: record.value) else {
|
||||
throw .badValue(key: record.key)
|
||||
}
|
||||
indexChecksum = digest
|
||||
case "S":
|
||||
guard let value = UInt64(record.value, radix: 10) else {
|
||||
throw .badValue(key: record.key)
|
||||
@ -152,7 +155,45 @@ extension ApkIndexPackage {
|
||||
}
|
||||
|
||||
extension ApkIndexPackage: CustomStringConvertible {
|
||||
var description: String { "pkg(\(self.name))" }
|
||||
var description: String {
|
||||
var s = String()
|
||||
s += "index checksum: \(self.indexChecksum)\n"
|
||||
s += "name: --------- \(self.name)\n"
|
||||
s += "version: ------ \(self.version)\n"
|
||||
if let architecture = self.architecture {
|
||||
s += "architecture: - \(architecture)\n"
|
||||
}
|
||||
s += "package size: - \(self.packageSize) byte(s) (\(self.packageSize.formatted(.byteCount(style: .file))))\n"
|
||||
s += "installed size: \(self.installedSize) byte(s) (\(self.installedSize.formatted(.byteCount(style: .file))))\n"
|
||||
s += "description: -- \(self.packageDescription)\n"
|
||||
s += "url: ---------- \(self.url)\n"
|
||||
s += "license: ------ \(self.license)\n"
|
||||
if let origin = self.origin {
|
||||
s += "origin: ------- \(origin)\n"
|
||||
}
|
||||
if let maintainer = self.maintainer {
|
||||
s += "maintainer: --- \(maintainer)\n"
|
||||
}
|
||||
if let buildTime = self.buildTime {
|
||||
s += "build time: --- \(buildTime)\n"
|
||||
}
|
||||
if let commit = self.commit {
|
||||
s += "commit: ------- \(commit)\n"
|
||||
}
|
||||
if let providerPrio = self.providerPriority {
|
||||
s += "provider prio: \(providerPrio)\n"
|
||||
}
|
||||
if !self.dependencies.isEmpty {
|
||||
s += "dependencies: - \(self.dependencies.map(String.init).joined(separator: " "))\n"
|
||||
}
|
||||
if !self.provides.isEmpty {
|
||||
s += "provides: ----- \(self.provides.map { $0.name }.joined(separator: " "))\n"
|
||||
}
|
||||
if !self.installIf.isEmpty {
|
||||
s += "install if: --- \(self.installIf.map { $0.name }.joined(separator: " "))\n"
|
||||
}
|
||||
return s
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate extension Optional {
|
||||
|
@ -42,13 +42,10 @@ public struct ApkIndexUpdater {
|
||||
do {
|
||||
let tables = try repositories.map { try readIndex(URL(filePath: $0.localName)) }
|
||||
index = ApkIndex.merge(tables)
|
||||
try index.description.write(to: URL(fileURLWithPath: "packages.txt"), atomically: false, encoding: .utf8)
|
||||
} catch {
|
||||
fatalError(error.localizedDescription)
|
||||
}
|
||||
|
||||
for package in index.packages {
|
||||
print("\(package.name):", package.dependencies)
|
||||
}
|
||||
}
|
||||
|
||||
private func readIndex(_ indexURL: URL) throws -> ApkIndex {
|
||||
|
Reference in New Issue
Block a user