batman
This commit is contained in:
commit
0ea7d8b7ee
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
zig-out/
|
||||||
|
zig-cache
|
70
build.zig
Normal file
70
build.zig
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
// Although this function looks imperative, note that its job is to
|
||||||
|
// declaratively construct a build graph that will be executed by an external
|
||||||
|
// runner.
|
||||||
|
pub fn build(b: *std.Build) void {
|
||||||
|
// Standard target options allows the person running `zig build` to choose
|
||||||
|
// what target to build for. Here we do not override the defaults, which
|
||||||
|
// means any target is allowed, and the default is native. Other options
|
||||||
|
// for restricting supported target set are available.
|
||||||
|
const target = b.standardTargetOptions(.{});
|
||||||
|
|
||||||
|
// Standard optimization options allow the person running `zig build` to select
|
||||||
|
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not
|
||||||
|
// set a preferred release mode, allowing the user to decide how to optimize.
|
||||||
|
const optimize = b.standardOptimizeOption(.{});
|
||||||
|
|
||||||
|
const exe = b.addExecutable(.{
|
||||||
|
.name = "ebook-reader",
|
||||||
|
// In this case the main source file is merely a path, however, in more
|
||||||
|
// complicated build scripts, this could be a generated file.
|
||||||
|
.root_source_file = .{ .path = "src/main.zig" },
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
});
|
||||||
|
|
||||||
|
// This declares intent for the executable to be installed into the
|
||||||
|
// standard location when the user invokes the "install" step (the default
|
||||||
|
// step when running `zig build`).
|
||||||
|
b.installArtifact(exe);
|
||||||
|
|
||||||
|
// This *creates* a Run step in the build graph, to be executed when another
|
||||||
|
// step is evaluated that depends on it. The next line below will establish
|
||||||
|
// such a dependency.
|
||||||
|
const run_cmd = b.addRunArtifact(exe);
|
||||||
|
|
||||||
|
// By making the run step depend on the install step, it will be run from the
|
||||||
|
// installation directory rather than directly from within the cache directory.
|
||||||
|
// This is not necessary, however, if the application depends on other installed
|
||||||
|
// files, this ensures they will be present and in the expected location.
|
||||||
|
run_cmd.step.dependOn(b.getInstallStep());
|
||||||
|
|
||||||
|
// This allows the user to pass arguments to the application in the build
|
||||||
|
// command itself, like this: `zig build run -- arg1 arg2 etc`
|
||||||
|
if (b.args) |args| {
|
||||||
|
run_cmd.addArgs(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This creates a build step. It will be visible in the `zig build --help` menu,
|
||||||
|
// and can be selected like this: `zig build run`
|
||||||
|
// This will evaluate the `run` step rather than the default, which is "install".
|
||||||
|
const run_step = b.step("run", "Run the app");
|
||||||
|
run_step.dependOn(&run_cmd.step);
|
||||||
|
|
||||||
|
// Creates a step for unit testing. This only builds the test executable
|
||||||
|
// but does not run it.
|
||||||
|
const unit_tests = b.addTest(.{
|
||||||
|
.root_source_file = .{ .path = "src/main.zig" },
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
});
|
||||||
|
|
||||||
|
const run_unit_tests = b.addRunArtifact(unit_tests);
|
||||||
|
|
||||||
|
// Similar to creating the run step earlier, this exposes a `test` step to
|
||||||
|
// the `zig build --help` menu, providing a way for the user to request
|
||||||
|
// running the unit tests.
|
||||||
|
const test_step = b.step("test", "Run unit tests");
|
||||||
|
test_step.dependOn(&run_unit_tests.step);
|
||||||
|
}
|
78
flake.lock
Normal file
78
flake.lock
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"flake-compat": {
|
||||||
|
"flake": false,
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1673956053,
|
||||||
|
"narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=",
|
||||||
|
"owner": "edolstra",
|
||||||
|
"repo": "flake-compat",
|
||||||
|
"rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "edolstra",
|
||||||
|
"repo": "flake-compat",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flake-utils": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1659877975,
|
||||||
|
"narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"rev": "c0e246b9b83f637f4681389ecabcb2681b4f3af0",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1661151577,
|
||||||
|
"narHash": "sha256-++S0TuJtuz9IpqP8rKktWyHZKpgdyrzDFUXVY07MTRI=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "54060e816971276da05970a983487a25810c38a7",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"ref": "nixpkgs-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"zig": "zig"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"zig": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-compat": "flake-compat",
|
||||||
|
"flake-utils": "flake-utils",
|
||||||
|
"nixpkgs": "nixpkgs"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1684670828,
|
||||||
|
"narHash": "sha256-e3HSmT9ufQ0WZYh6hOPx87dg/4jjLoJLl6zAEzev07E=",
|
||||||
|
"owner": "mitchellh",
|
||||||
|
"repo": "zig-overlay",
|
||||||
|
"rev": "22a39bd5ce8f8b0fdec3049ca5bfb54c748380bd",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "mitchellh",
|
||||||
|
"repo": "zig-overlay",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
9
flake.nix
Normal file
9
flake.nix
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
description = "A very basic flake";
|
||||||
|
|
||||||
|
inputs.zig.url = "github:mitchellh/zig-overlay";
|
||||||
|
|
||||||
|
outputs = { self, zig, ... }: {
|
||||||
|
packages.x86_64-linux.zig = zig.packages.x86_64-linux.master;
|
||||||
|
};
|
||||||
|
}
|
128
src/main.zig
Normal file
128
src/main.zig
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const stdout = std.io.getStdOut().writer();
|
||||||
|
const stderr = std.io.getStdErr().writer();
|
||||||
|
|
||||||
|
fn print(comptime str: []const u8, params: anytype) void {
|
||||||
|
stdout.print(str ++ "\n", params) catch {};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pErr(comptime str: []const u8, params: anytype) void {
|
||||||
|
stderr.print(str ++ "\n", params) catch {};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn exit(comptime str: []const u8, params: anytype, exitCode: u8) void {
|
||||||
|
pErr(str, params);
|
||||||
|
std.os.exit(exitCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage() void {
|
||||||
|
pErr("reader <path>", .{});
|
||||||
|
exit("", .{}, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const LOCAL_FILE_HEADER_SIGNATURE = 0x04034b50;
|
||||||
|
const ZipFileHeader = struct {
|
||||||
|
version: u16,
|
||||||
|
general: u16,
|
||||||
|
compression_method: u16,
|
||||||
|
last_mod_time: u16,
|
||||||
|
last_mod_date: u16,
|
||||||
|
crc_32: u32,
|
||||||
|
compressed_size: u32,
|
||||||
|
uncompressed_size: u32,
|
||||||
|
file_name_length: u16,
|
||||||
|
extra_field_length: u16,
|
||||||
|
|
||||||
|
file_name: []u8,
|
||||||
|
extra_field: []u8,
|
||||||
|
|
||||||
|
allocator: std.mem.Allocator,
|
||||||
|
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
|
fn init(allocator: std.mem.Allocator, reader: std.fs.File.Reader) !Self {
|
||||||
|
if (try reader.readInt(u32, .Big) == LOCAL_FILE_HEADER_SIGNATURE) {
|
||||||
|
return error.InvalidError;
|
||||||
|
}
|
||||||
|
|
||||||
|
var self = Self{
|
||||||
|
.allocator = allocator,
|
||||||
|
.version = try reader.readInt(u16, .Big),
|
||||||
|
.general = try reader.readInt(u16, .Big),
|
||||||
|
.compression_method = try reader.readInt(u16, .Big),
|
||||||
|
.last_mod_time = try reader.readInt(u16, .Big),
|
||||||
|
.last_mod_date = try reader.readInt(u16, .Big),
|
||||||
|
.crc_32 = try reader.readInt(u32, .Big),
|
||||||
|
.compressed_size = try reader.readInt(u32, .Big),
|
||||||
|
.uncompressed_size = try reader.readInt(u32, .Big),
|
||||||
|
.file_name_length = try reader.readInt(u16, .Big),
|
||||||
|
.extra_field_length = try reader.readInt(u16, .Big),
|
||||||
|
.file_name = undefined,
|
||||||
|
.extra_field = undefined,
|
||||||
|
};
|
||||||
|
|
||||||
|
self.file_name = try allocator.alloc(u8, self.file_name_length);
|
||||||
|
self.extra_field = try allocator.alloc(u8, self.extra_field_length);
|
||||||
|
|
||||||
|
_ = try reader.read(self.file_name);
|
||||||
|
_ = try reader.read(self.extra_field);
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deinit(self: *Self) void {
|
||||||
|
self.allocator.free(self.file_name);
|
||||||
|
self.allocator.free(self.extra_field);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn main() !void {
|
||||||
|
var args = std.process.args();
|
||||||
|
|
||||||
|
var filePath: ?[]const u8 = null;
|
||||||
|
|
||||||
|
// Skip the current path
|
||||||
|
_ = args.next();
|
||||||
|
while (args.next()) |arg| {
|
||||||
|
if (filePath == null) {
|
||||||
|
filePath = arg;
|
||||||
|
} else {
|
||||||
|
pErr("Invalid argument: {s}", .{arg});
|
||||||
|
usage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filePath == null) {
|
||||||
|
pErr("File path not provided. Please provide a path", .{});
|
||||||
|
usage();
|
||||||
|
}
|
||||||
|
|
||||||
|
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||||
|
defer _ = gpa.deinit();
|
||||||
|
|
||||||
|
var allocator = gpa.allocator();
|
||||||
|
|
||||||
|
var book_path = try std.fs.realpathAlloc(allocator, filePath.?);
|
||||||
|
defer allocator.free(book_path);
|
||||||
|
|
||||||
|
var file = std.fs.openFileAbsolute(book_path, .{}) catch |err| {
|
||||||
|
exit("Please provide a file path! Error: {?}", .{err}, 1);
|
||||||
|
return err;
|
||||||
|
};
|
||||||
|
defer file.close();
|
||||||
|
|
||||||
|
var stat = try file.stat();
|
||||||
|
|
||||||
|
if (stat.kind != .File) {
|
||||||
|
exit("Please provide a valid file", .{}, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
var reader = file.reader();
|
||||||
|
|
||||||
|
var first_file = try ZipFileHeader.init(allocator, reader);
|
||||||
|
defer first_file.deinit();
|
||||||
|
|
||||||
|
print("G: {}", .{first_file.file_name_length});
|
||||||
|
print("T: {s}", .{first_file.file_name});
|
||||||
|
print("O: {s}", .{first_file.extra_field});
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user