Skip to content

Commit

Permalink
Add BSD Archive Support (#2)
Browse files Browse the repository at this point in the history
Add BSD Archive Support.
  • Loading branch information
LebJe authored Apr 9, 2021
1 parent 4f3963d commit 5c85f97
Show file tree
Hide file tree
Showing 18 changed files with 273 additions and 257 deletions.
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
# See https://pre-commit.com/hooks.html for more hooks
repos:
- repo: https://github.com/hodovani/pre-commit-swift
rev: master
rev: 0551a937b9f98a839fd98d2c3e6ce0b6c0a1e093
hooks:
- id: swift-format
19 changes: 2 additions & 17 deletions .swiftformat
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,6 @@
--wrapparameters before-first
--disable trailingClosures, typeSugar
--header "Copyright (c) 2021 Jeff Lebrun \n\n \
Permission is hereby granted, free of charge, to any person obtaining a copy \n \
of this software and associated documentation files (the "Software"), to deal \n \
in the Software without restriction, including without limitation the rights \n \
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell \n \
copies of the Software, and to permit persons to whom the Software is \n \
furnished to do so, subject to the following conditions: \n\n \
\
The above copyright notice and this permission notice shall be included in all \n \
copies or substantial portions of the Software. \n\n \
\
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR \n \
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, \n \
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE \n \
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER \n \
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, \n \
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE \n \
SOFTWARE.
Licensed under the MIT License. \n\n \
The full text license can be found in the file named LICENSE.
"
86 changes: 64 additions & 22 deletions Examples/Foundationless/Sources/Foundationless/main.swift
Original file line number Diff line number Diff line change
@@ -1,22 +1,8 @@
// Copyright (c) 2021 Jeff Lebrun
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the Software), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// Licensed under the MIT License.
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// The full text license can be found in the file named LICENSE.

#if os(macOS)
import Darwin.C
Expand All @@ -28,13 +14,53 @@

import ArArchiveKit

let fd = open("test.a", O_RDONLY)
func parseHelpFlag(_ s: String) -> Bool {
switch s {
case "-h": return true
case "-help": return true
case "--help": return true
case "-?": return true
default:
return false
}
}

let usage = """
USAGE: \(CommandLine.arguments[0]) [--help, -h, -?] [-p] [-b] <file>
Reads the archive at `file` prints information about each file in the archive. Note that `-b` must come AFTER `-p`.
-h, --help, -? Prints this message.
-p Print the contents of the files in the archive.
-b Print the binary representation of the files in the archive.
"""

var shouldPrintFile = false
var printInBinary = false

func parseArgs() {
if CommandLine.arguments.count < 2 || parseHelpFlag(CommandLine.arguments[1]) {
print(usage)
exit(1)
}

if CommandLine.arguments.count >= 3, CommandLine.arguments[2] == "-p" {
shouldPrintFile = true
}

if CommandLine.arguments.count >= 4, CommandLine.arguments[3] == "-b" {
printInBinary = true
}
}

parseArgs()

let fd = open(CommandLine.arguments[1], O_RDONLY)

let size = Int(lseek(fd, 0, SEEK_END))

lseek(fd, 0, SEEK_SET)

var uInt8Pointer = UnsafeMutablePointer<UInt8>.allocate(capacity: size)
let buf = UnsafeMutableRawBufferPointer.allocate(byteCount: size, alignment: MemoryLayout<UInt8>.alignment)

read(fd, buf.baseAddress, buf.count)
Expand All @@ -46,8 +72,24 @@ let bytes = Array(bufferPointer)
let reader = try ArArchiveReader(archive: bytes)

for (header, file) in reader {
print(header.name + ":")
print()
print(String(file))
print()
print("---------------------------")

print("Name: " + header.name)
print("User ID: " + String(header.userID))
print("Group ID: " + String(header.groupID))
print("Mode (In Octal): " + String(header.mode, radix: 8))
print("File Size: " + String(header.size))
print("File Modification Time: " + String(header.modificationTime))

print("Contents:\n")

if shouldPrintFile {
if printInBinary {
file.forEach({ print($0) })
} else {
print(String(file))
}
}
}

print("---------------------------")
Original file line number Diff line number Diff line change
@@ -1,22 +1,8 @@
// Copyright (c) 2021 Jeff Lebrun
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the Software), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// Licensed under the MIT License.
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// The full text license can be found in the file named LICENSE.

import class Foundation.Bundle
import XCTest
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,8 @@
// Copyright (c) 2021 Jeff Lebrun
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the Software), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// Licensed under the MIT License.
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// The full text license can be found in the file named LICENSE.

import XCTest

Expand Down
18 changes: 2 additions & 16 deletions Examples/Foundationless/Tests/LinuxMain.swift
Original file line number Diff line number Diff line change
@@ -1,22 +1,8 @@
// Copyright (c) 2021 Jeff Lebrun
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the Software), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// Licensed under the MIT License.
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// The full text license can be found in the file named LICENSE.

import XCTest

Expand Down
11 changes: 9 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

- [ArArchiveKit](#ararchivekit)
- [Table of Contents](#table-of-contents)
- [ar Variations](#ar-variations)
- [Installation](#installation)
- [Swift Package Manager](#swift-package-manager)
- [Usage](#usage)
Expand All @@ -27,14 +28,20 @@
- [Windows](#windows)
- [Contributing](#contributing)

<!-- Added by: lebje, at: Mon Mar 22 12:11:21 EDT 2021 -->
<!-- Added by: lebje, at: Fri Apr 9 18:48:17 EDT 2021 -->

<!--te-->

Created by [gh-md-toc](https://github.com/ekalinin/github-markdown-toc)

Documentation is available [here](https://lebje.github.io/ArArchiveKit).

## `ar` Variations

ArArchiveKit supports the BSD variation of `ar` as described in [FreeBSD manpages](https://www.freebsd.org/cgi/man.cgi?query=ar&sektion=5).

Support for the GNU variant may come soon.

## Installation

### Swift Package Manager
Expand Down Expand Up @@ -162,7 +169,7 @@ let data = reader[header: header]

## Examples

- `Exaples/Foundationless`: This example shows how to use ArArchiveKit to read an archive using only `Darwin.C`/`Glibc`/`ucrt`.
- `Exaples/Foundationless`: This example shows how to use ArArchiveKit to read an any archive using only `Darwin.C` (macOS), `Glibc` (Linux) or `ucrt` (Windows (not tested)).

## Other Platforms

Expand Down
50 changes: 27 additions & 23 deletions Sources/ArArchiveKit/ArArchiveReader.swift
Original file line number Diff line number Diff line change
@@ -1,22 +1,8 @@
// Copyright (c) 2021 Jeff Lebrun
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the Software), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// Licensed under the MIT License.
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// The full text license can be found in the file named LICENSE.

/// `ArArchiveReader` reads `ar` files.
public struct ArArchiveReader {
Expand All @@ -37,15 +23,20 @@ public struct ArArchiveReader {
public var headers: [Header] = []

/// The initializer reads all the `ar` headers in preparation for random access to the header's file contents later.
///
/// - Parameters:
/// - archive: The bytes of the archive you want to read.
/// - variant: The format of the archive you want to read.
/// - Throws: `ArArchiveError`.
public init(archive: [UInt8]) throws {
if archive.isEmpty {
throw ArArchiveError.emptyArchive
} else if archive.count < 8 {
// The global header is missing.
throw ArArchiveError.invalidArchive
throw ArArchiveError.missingMagicBytes
} else if Array(archive[0...7]) != globalHeader.asciiArray {
// The global header is invalid.
throw ArArchiveError.invalidArchive
throw ArArchiveError.invalidMagicBytes
}

// Drop the global header from the byte array.
Expand All @@ -58,8 +49,11 @@ public struct ArArchiveReader {
var h = try self.parseHeader(bytes: Array(self.data[index...(index + headerSize - 1)]))

index += headerSize + 1
h.contentLocation = index - 1
index += h.size
h.contentLocation = (index - 1) + (h.nameSize != nil ? h.nameSize! : 0)

h.name = h.nameSize != nil ? String(Array(self.data[h.contentLocation - h.nameSize!..<h.contentLocation])) : h.name

index += h.size + (h.nameSize != nil ? h.nameSize! : 0)

self.headers.append(h)
}
Expand All @@ -83,13 +77,14 @@ public struct ArArchiveReader {

private func parseHeader(bytes: [UInt8]) throws -> Header {
var start = 0
let name = self.readString(from: Array(bytes[start...15]))
var name = self.readString(from: Array(bytes[start...15]))

start = 16

let modificationTime = self.readInt(from: Array(bytes[start...(start + 11)]))

start += 12

let userID = self.readInt(from: Array(bytes[start...(start + 5)]))

start += 6
Expand All @@ -113,11 +108,20 @@ public struct ArArchiveReader {
else { throw ArArchiveError.invalidHeader }

var h = Header(name: name, userID: u, groupID: g, mode: m, modificationTime: mT)
h.size = s

if name.hasPrefix("#1/") {
name.removeSubrange(name.startIndex..<name.index(name.startIndex, offsetBy: 3))

guard let nameSize = Int(name) else { throw ArArchiveError.invalidHeader }

h.size = s - nameSize
h.nameSize = nameSize
} else { h.size = s }

return h
}

/// From [blakesmith/r/reader.go: line 62](https://github.com/blakesmith/ar/blob/809d4375e1fb5bb262c159fc3ec2e7a86a8bfd28/reader.go#L62) .
/// From [blakesmith/ar/reader.go: line 62](https://github.com/blakesmith/ar/blob/809d4375e1fb5bb262c159fc3ec2e7a86a8bfd28/reader.go#L62) .
private func readString(from bytes: [UInt8]) -> String {
var i = bytes.count - 1

Expand Down
Loading

0 comments on commit 5c85f97

Please sign in to comment.