diff options
Diffstat (limited to 'format.c')
-rw-r--r-- | format.c | 188 |
1 files changed, 188 insertions, 0 deletions
diff --git a/format.c b/format.c new file mode 100644 index 0000000..cbd7265 --- /dev/null +++ b/format.c @@ -0,0 +1,188 @@ +#include "format.h" +#include "gzip.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <inttypes.h> + +struct segment empty_segment = { + .start = -1, + .end = -1, + .description = "No segment selected", +}; + +struct segment get_segment(void *mem, size_t len, ssize_t addr) { + + if (addr < 0 || addr >= len) { + return empty_segment; + } + + + static char *buf = NULL; + if (buf != NULL) { + free(buf); + buf = NULL; + } + struct member *header = (struct member*) mem; + + if (addr == 0) { + return (struct segment) { + .start = 0, + .end = 1, + .description = "ID1 = 31" + }; + } + if (addr == 1) { + return (struct segment) { + .start = 1, + .end = 2, + .description = "ID2 = 139", + }; + } + if (addr == 2) { + return (struct segment) { + .start = 2, + .end = 3, + .description = "CM (Compression Method)\n" + "CM = 8 is defalte", + }; + } + if (addr == 3) { + buf = malloc(1000); + buf[0] = '\0'; + for (int i = 0; i < 5; i++) { + if (header->flg & (1 << i)) { + strcat(buf, "- "); + strcat(buf, flag_str(1<<i)); + strcat(buf, "\n"); + } + } + return (struct segment) { + .start = 3, + .end = 4, + .description = buf, + }; + } + if (addr >= 4 && addr < 8) { + buf = malloc(1000); + sprintf(buf, "Mtime=%i", header->mtime); + return (struct segment) { + .start = 4, + .end = 8, + .description = buf, + }; + } + if (addr == 8) { + return (struct segment) { + .start = 8, + .end = 9, + .description = "XFL", + }; + } + if (addr == 9) { + buf = malloc(1000); + sprintf(buf, "OS: %s\n", os_str(header->os)); + return (struct segment) { + .start = 9, + .end = 10, + .description = buf, + }; + } + + void *ptr = ((struct member*) mem) + 1; + + if (header->flg & FEXTRA) { + uint16_t xlen = *((uint16_t*) ptr); + if (mem + addr == ptr || mem + addr == ptr + 1) { + return (struct segment) { + .start = ptr - mem, + .end = ptr - mem + 1, + .description = "XLEN", + }; + } + ptr = ((uint16_t*) ptr) + 1; + // if (mem + addr >= ptr && mem + addr < xlen) { + if (ptr - mem + addr < 2) { + return (struct segment) { + .start = ptr - mem, + .end = ptr - mem + xlen, + .description = "XLEN bytes of extra data", + }; + } + ptr = ((uint8_t*) ptr) + 1 + xlen; + } + + if (header->flg & FNAME) { + void *c = memchr(ptr, '\0', (ptr - mem) + len); + size_t start = ptr - mem; + size_t end = c - mem; + ptr = ((uint8_t*) c) + 1; + if (addr < c - mem + 1) { + return (struct segment) { + .start = start, + .end = end + 1, + .description = "Original filename", + }; + } + } + + if (header->flg & FCOMMENT) { + void *c = memchr(ptr, '\0', (ptr - mem) + len); + ptr = ((uint8_t*) c) + 1; + if (addr < c - mem + 1) { + size_t start = ptr - mem; + size_t end = c - mem; + return (struct segment) { + .start = start, + .end = end + 1, + .description = "File comment", + }; + } + } + + if (header->flg & FHCRC) { + if (addr < ptr - mem + 2) { + buf = malloc(1000); + fprintf(buf, "CRC16=" PRIu16, *((uint16_t*) ptr)); + return (struct segment) { + .start = ptr - mem, + .end = ptr - mem + 2, + .description = buf, + }; + } + ptr = (uint16_t*) ptr + 1; + } + + if (len - addr < 4) { + buf = malloc(1000); + fprintf(buf, "ISIZE" PRIu32, *(((uint32_t*) ((uint8_t*) (mem + len))) - 1)); + return (struct segment) { + .start = len - 4, + .end = len, + .description = buf, + }; + } + + if (len - addr - 4 < 4) { + buf = malloc(1000); + fprintf(buf, "CRC32" PRIu32, *(((uint32_t*) ((uint8_t*) (mem + len))) - 2)); + return (struct segment) { + .start = len - 8, + .end = len - 4, + .description = buf, + }; + } + + if (ptr - mem <= addr && addr < ptr - mem + len - 8) { + return (struct segment) { + .start = ptr - mem, + .end = len - 8, + .description = "ZLIB compressed payload", + }; + } + + + return empty_segment; + +} |