File: main.swift

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (150 lines) | stat: -rw-r--r-- 3,993 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
//===----------------------------------------------------------------------===//
//
// This source file is part of the SwiftCrypto open source project
//
// Copyright (c) 2019 Apple Inc. and the SwiftCrypto project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
// See CONTRIBUTORS.md for the list of SwiftCrypto project authors
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//
import Foundation
import Crypto

let help = """
Usage: crypto-shasum [OPTION]... [FILE]...
Print SHA checksums.
With no FILE, or when FILE is -, read standard input.

  -a, --algorithm   256 (default), 384, 512
"""

enum SupportedHashFunction {
    case sha256
    case sha384
    case sha512

    init?(commandLineFlag flag: String) {
        switch flag {
        case "256":
            self = .sha256
        case "384":
            self = .sha384
        case "512":
            self = .sha512
        default:
            return nil
        }
    }

    func hashLoop(from input: FileHandle) -> Data {
        switch self {
        case .sha256:
            return Data(Self.hashLoop(from: input, with: SHA256.self))
        case .sha384:
            return Data(Self.hashLoop(from: input, with: SHA384.self))
        case .sha512:
            return Data(Self.hashLoop(from: input, with: SHA512.self))
        }
    }

    private static let readSize = 8192

    private static func hashLoop<HF: HashFunction>(from input: FileHandle, with hasher: HF.Type) -> HF.Digest {
        var hasher = HF()

        while true {
            let data = input.readData(ofLength: Self.readSize)
            if data.count == 0 {
                break
            }

            hasher.update(data: data)
        }

        return hasher.finalize()
    }
}


extension String {
    init(hexEncoding data: Data) {
        self = data.map { byte in
            let s = String(byte, radix: 16)
            switch s.count {
            case 0:
                return "00"
            case 1:
                return "0" + s
            case 2:
                return s
            default:
                fatalError("Weirdly hex encoded byte")
            }
        }.joined()
    }
}


func processInputs(_ handles: [String: FileHandle], algorithm: SupportedHashFunction) {
    for (name, fh) in handles {
        let result = algorithm.hashLoop(from: fh)
        print("\(String(hexEncoding: result))  \(name)")
    }
}

func main() {
    var arguments = CommandLine.arguments.dropFirst()
    var algorithm = SupportedHashFunction.sha256  // Default to sha256
    var files = [String: FileHandle]()

    // First get the flags.
    flagsLoop: while let first = arguments.first, first.starts(with: "-") {
        arguments = arguments.dropFirst()

        switch first {
        case "-a", "--algorithm":
            guard let flag = arguments.popFirst(), let newAlgorithm = SupportedHashFunction(commandLineFlag: flag) else {
                print("Unknown algorithm description.")
                return
            }
            algorithm = newAlgorithm

        case "--":
            break flagsLoop  // Everything left is files.

        case "-":
            // Whoops, this is a file. We need to read from stdin. Ignore any further flags, the rest of the arguments are files.
            files["-"] = FileHandle.standardInput
            break flagsLoop

        default:
            print(help)
            return
        }
    }

    // Now the files.
    while let first = arguments.popFirst() {
        // We assume this is a path.
        guard let fh = FileHandle(forReadingAtPath: first) else {
            print("Unable to open \(first)")
            return
        }

        files[first] = fh
    }

    if files.count == 0 {
        // No flags. We assume that means stdin.
        files["-"] = FileHandle.standardInput
    }

    processInputs(files, algorithm: algorithm)
}


main()