From 933cf4f0a47306ee4b0c1ac728173a576cc2ebe1 Mon Sep 17 00:00:00 2001 From: Tomasz Kramkowski Date: Wed, 28 Mar 2018 00:09:21 +0100 Subject: bie: initial commit and version 0.1 --- .gitignore | 13 ++++++ LICENSE | 20 +++++++++ Makefile | 43 ++++++++++++++++++++ README | 56 ++++++++++++++++++++++++++ bie.1.in | 70 ++++++++++++++++++++++++++++++++ bie.c | 134 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 336 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 README create mode 100644 bie.1.in create mode 100644 bie.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..54eb42b --- /dev/null +++ b/.gitignore @@ -0,0 +1,13 @@ +*.o +bie + +*.d + +tags +TAGS + +config.mk + +eprintf.h +eprintf.c +bie.1 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..1a71eb5 --- /dev/null +++ b/LICENSE @@ -0,0 +1,20 @@ +Copyright 2018 Tomasz Kramkowski + +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: + +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. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..982352c --- /dev/null +++ b/Makefile @@ -0,0 +1,43 @@ +# Copyright (C) 2018 Tomasz Kramkowski +# SPDX-License-Identifier: MIT +-include config.mk + +PROG := bie +MANPAGE := $(PROG).1 +VERSION != git describe --tags 2>/dev/null || echo "v0.1" + +EPRINTF_PATH ?= ../eprintf +PKG_CONFIG ?= pkg-config +LN ?= ln -sf + +CPPFLAGS += -DVERSION=\"$(VERSION)\" +CFLAGS += -std=c11 -MMD -MP + +OBJ := bie.o eprintf.o +DEP := $(OBJ:.o=.d) + +prefix ?= /usr/local +exec_prefix ?= $(prefix) +bindir = $(exec_prefix)/bin +datarootdir = $(prefix)/share +mandir = $(datarootdir)/man +man1dir = $(mandir)/man1 + +all: $(PROG) $(MANPAGE) +$(PROG): $(OBJ) +bie.o: eprintf.h +$(MANPAGE): $(MANPAGE).in + m4 -DVERSION=$(VERSION) $^ >$@ + +install: $(PROG) $(MANPAGE) + install -Dm755 -s $(PROG) -t $(DESTDIR)$(bindir) + install -Dm644 $(MANPAGE) -t $(DESTDIR)$(man1dir) + +clean: + $(RM) $(OBJ) $(DEP) $(PROG) $(MANPAGE) + +include $(EPRINTF_PATH)/module.mk + +-include $(DEP) + +.PHONY: all install clean diff --git a/README b/README new file mode 100644 index 0000000..9135648 --- /dev/null +++ b/README @@ -0,0 +1,56 @@ + _ _ + | | (_) + | |__ _ ___ + | '_ \| |/ _ \ + | |_) | | __/ + |_.__/|_|\___| + +--------------------------------------------------------------------- + +bie is a tool for generating a simple indexed flat archive. + +Example: +======== + +$ echo "foo" >a +$ dd if=/dev/urandom of=b bs=30 count=1 +$ zlib-flate -compress c +$ bie archive.bie archive.idx a b c +$ hexdump -C archive.bie +00000000 66 6f 6f 0a 00 00 00 00 00 00 00 00 00 00 00 00 |foo.............| +00000010 1b c9 01 82 4f df 1a ec 01 2a dc 0e 3e f1 e7 52 |....O....*..>..R| +00000020 ed e3 99 3e 70 b0 eb 6f f8 20 49 ba b9 8d 00 00 |...>p..o. I.....| +00000030 78 9c 95 54 6d 6f d3 30 10 fe 9c fc 8a a3 a8 6b |x..Tmo.0.......k| +00000040 d2 76 5d 37 10 42 7d 19 2f a5 43 15 65 a0 ad 93 |.v]7.B}./.C.e...| +00000050 40 6c 1a 21 71 5a ab 89 1d c5 4e c7 c6 fa df b9 |@l.!qZ....N.....| +... SNIP ... +$ cat archive.idx +BIE_ENTRY(a, 0, 4) +BIE_ENTRY(b, 16, 30) +BIE_ENTRY(c, 48, 750) + +Use: +==== + +Create an archive and index from a list of files you wish to access +from your program. + +Use the CPP or another macro processor to expand BIE_ENTRY to some +code which stores this information in your program. + +Read the archive into memory (or link it in) and use the offset and +size data from the index to read from the archive. + +Dependencies: +============= + +eprintf - https://the-tk.com/cgit/eprintf/ +Place in a directory adjacent to the location of the bie sources or +override EPRINTF_PATH in config.mk + +Compilation and Installation: +============================= + +$ echo prefix=/usr >config.mk +$ make +# make install diff --git a/bie.1.in b/bie.1.in new file mode 100644 index 0000000..3dc9eef --- /dev/null +++ b/bie.1.in @@ -0,0 +1,70 @@ +.\" Copyright (C) 2018 Tomasz Kramkowski +.\" SPDX-License-Identifier: MIT +.TH "BIE" "1" "2018-03-27" "bie VERSION" "bie Manual" + +.SH "NAME" +bie \- a tool for generating an indexed flat archive + +.SH "SYNOPSIS" +.B bie +.RB [ -hv ] +.RB [ -- ] +.I output index input... + +.SH "DESCRIPTION" +.I output +is the destination of the flat archive. +.I index +is the destination of the index file. +.I input +is the list of files to archive. +.P +The output is a concatenation of the contents of all the input files +with each file aligned to as 16 byte boundary. The format of the index +file is a list of macro calls to BIE_ENTRY with the parameters being +the name, the offset and the size of each input file. +.P +An appropriate definition of BIE_ENTRY should be provided to make use +of this information. +.P +The name of each input file will be slugified to remove any characters +which are not valid inside a C identifier (leading digits are +removed). The slugification process leaves alphanumeric characters +alone, replaces punctuation and spaces with underscores and removes +any other characters. Any resulting leading underscores are dropped. +.P +.B bie +does not attempt to fix name collisions. + +.SH "OPTIONS" +.B -h +.RS +Show help. +.RE + +.B -v +.RS +Show version and license information. +.RE + +.SH "EXAMPLES" +bie assets.bie assets.idx a b c +.RS +This will instruct +.B bie +to read the contents of the files named a, b and c and to generate an +assets.bie which is a concatenation of the aligned file contents of a, +b and c and to generate an assets.idx which might look like this: + +.nf +BIE_ENTRY(a, 0, 10) +BIE_ENTRY(b, 16, 30) +BIE_ENTRY(c, 48, 100) +.fi +.RE + +.SH "SEE ALSO" +.BR ld (1), +.BR zlib-flate (1) +.SH AUTHOR +Tomasz Kramkowski diff --git a/bie.c b/bie.c new file mode 100644 index 0000000..66c97c9 --- /dev/null +++ b/bie.c @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2018 Tomasz Kramkowski + * SPDX-License-Identifier: MIT + */ +#include +#include +#include +#include + +#include "eprintf.h" + +#ifndef VERSION +#define VERSION "v0.1" +#endif + +enum { + ALIGN = 16, +}; + +static const char *usage = "[-hv] [--] output map input..."; + +static void help(void) +{ + fprintf(stderr, + "Options:\n" + " -h Show this help.\n" + " -v Show version and license information.\n" + "\n" + "Please check the bie(1) man page for more information.\n"); +} + +static void version(void) +{ + fprintf(stderr, + "bie %s\n" + "Copyright (C) 2018 Tomasz Kramkowski \n" + "Licensed under the MIT license \n" + "There is NO WARRANTY, to the extent permitted by law.\n", + VERSION); +} + +static void slug(FILE *f, const char *text) +{ + bool leading = true; + int c; + + while (c = *text++, c != '\0') { + if (isalpha(c)) { + leading = false; + fputc(c, f); + continue; + } + if (leading) continue; + if (isdigit(c)) + fputc(c, f); + else if (ispunct(c) || isspace(c)) + fputc('_', f); + } +} + +static void mapentry(FILE *map, const char *name, size_t pos, size_t size) +{ + fprintf(map, "BIE_ENTRY("); + slug(map, name); + fprintf(map, ", %zu, %zu)\n", pos, size); +} + +static size_t dumpfile(FILE *dest, FILE *src) +{ + size_t size = 0; + int c; + + while (c = fgetc(src), c != EOF) { + size++; + fputc(c, dest); + } + + return size; +} + +int main(int argc, char **argv) +{ + const char *argv0 = argv[0] != NULL ? argv[0] : "bie"; + FILE *dest, *map; + size_t pos = 0; + + setprogname(argv0); + + for (argv++, argc--; argv[0] != NULL && argv[0][0] == '-' && + argv[0][1] != '-' && argv[0][2] == '\0'; argv++, argc--) { + switch (argv[0][1]) { + case 'h': + fprintf(stderr, "Usage: %s %s\n", argv0, usage); + help(); + return EXIT_SUCCESS; + case 'v': + version(); + return EXIT_SUCCESS; + } + } + + if (argc < 3) + eprintf("Invalid argument count\nUsage: %s %s", argv0, usage); + + dest = fopen(argv[0], "wb"); + if (dest == NULL) + eprintf("Could not open `%s':", argv[0]); + + map = fopen(argv[1], "w"); + if (map == NULL) + eprintf("Could not open `%s':", argv[1]); + + for (int i = 2; i < argc; i++) { + size_t size; + FILE *src; + + src = fopen(argv[i], "rb"); + if (src == NULL) + eprintf("Could not open `%s':", argv[i]); + size = dumpfile(dest, src); + fclose(src); + mapentry(map, argv[i], pos, size); + pos += size; + if (pos % ALIGN) { + size_t pad = ALIGN - pos % ALIGN; + for (size_t i = 0; i < pad; i++) + fputc(0, dest); + pos += pad; + } + } + + fclose(map); + fclose(dest); +} -- cgit v1.2.3-54-g00ecf