diff options
| author | jakob <jakob@memeware.net> | 2017-02-19 20:49:43 -0500 |
|---|---|---|
| committer | jakob <jakob@memeware.net> | 2017-02-19 20:49:43 -0500 |
| commit | d65a3ae8790ae28a90f0ebcf0bc4dc078c67dc35 (patch) | |
| tree | 3eb2ad7f78f55cde5b809bc75904b36c5a747502 /src | |
| parent | 32fb7b11d83138cc288d62c1f1674d95cc94e8de (diff) | |
Implemented eliF parsing.
Diffstat (limited to 'src')
| -rw-r--r-- | src/encoding.c | 36 | ||||
| -rw-r--r-- | src/encoding.h | 23 | ||||
| -rw-r--r-- | src/io.c | 19 | ||||
| -rw-r--r-- | src/io.h | 3 | ||||
| -rw-r--r-- | src/table.c | 49 | ||||
| -rw-r--r-- | src/table.h | 7 |
6 files changed, 132 insertions, 5 deletions
diff --git a/src/encoding.c b/src/encoding.c new file mode 100644 index 0000000..6ad4ea1 --- /dev/null +++ b/src/encoding.c @@ -0,0 +1,36 @@ +/* encoding.c -- Code for working with encoded strings. + + Copyright (C) 2017 Jakob Tsar-Fox, All Rights Reserved. + + This file is part of Nekopack. + + Nekopack is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation, either version 3 of the License, or (at + your option) any later version. + + Nekopack is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Nekopack. If not, see <http://www.gnu.org/licenses/>. */ + +#include <iconv.h> + + +/* Wrapper for iconv, using the conversion specified by `conv`. */ +static void convert(char *in_buf, char *out_buf, size_t len, iconv_t conv) { + size_t in_size = len, out_size = len; + char *in_start = in_buf, *out_start = out_buf; + iconv(conv, &in_start, &in_size, &out_start, &out_size); +} + + +/* Decodes the UTF-16LE string specified by `in_buf` into `out_buf`. */ +void utf16le_decode(char *in_buf, char *out_buf, size_t len) { + iconv_t conv = iconv_open("UTF-8", "UTF-16LE"); + convert(in_buf, out_buf, len, conv); + iconv_close(conv); +} diff --git a/src/encoding.h b/src/encoding.h new file mode 100644 index 0000000..cfb49c8 --- /dev/null +++ b/src/encoding.h @@ -0,0 +1,23 @@ +/* encoding.h -- Code for working with encoded strings. + + Copyright (C) 2017 Jakob Tsar-Fox, All Rights Reserved. + + This file is part of Nekopack. + + Nekopack is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation, either version 3 of the License, or (at + your option) any later version. + + Nekopack is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Nekopack. If not, see <http://www.gnu.org/licenses/>. */ + +#pragma once + +/* Decodes the UTF-16LE string specified by `in_buf` into `out_buf`. */ +void utf16le_decode(char *in_buf, char *out_buf, size_t len); @@ -18,6 +18,7 @@ along with Nekopack. If not, see <http://www.gnu.org/licenses/>. */ #include <stdint.h> +#include <stdio.h> #include <stdlib.h> #include <string.h> @@ -86,9 +87,21 @@ size_t stream_tell(struct stream *s) { } -/* Sets the stream's position indicator to the given `pos`. */ -void stream_seek(struct stream *s, size_t pos) { - s->_cur = s->_start + pos; +/* Sets the stream's position indicator to the given `pos`. If `whence` + is set to SEEK_SET, SEEK_CUR, or SEEK_END, the offset is relative to + the start of the file, the current position indicator, or + end-of-file, respectively. */ +void stream_seek(struct stream *s, size_t pos, int whence) { + switch (whence) { + case SEEK_SET: + s->_cur = s->_start + pos; + break; + case SEEK_CUR: + s->_cur += pos; + break; + case SEEK_END: + s->_cur = s->_start + s->len - pos; + } } @@ -20,6 +20,7 @@ #pragma once #include <stdint.h> +#include <stdio.h> #include <stddef.h> /* Internal enumerable type for representing the location of a memory @@ -62,7 +63,7 @@ void stream_xor(struct stream *s, uint8_t initial, uint8_t primary); size_t stream_tell(struct stream *s); /* Sets the stream's position indicator to the given `pos`. */ -void stream_seek(struct stream *s, size_t pos); +void stream_seek(struct stream *s, size_t pos, int whence); /* Sets the stream's position indicator to the beginning. */ void stream_rewind(struct stream *s); diff --git a/src/table.c b/src/table.c index 84ab77f..a541ab9 100644 --- a/src/table.c +++ b/src/table.c @@ -20,7 +20,9 @@ #include <stdbool.h> #include <stdint.h> #include <stdlib.h> +#include <string.h> +#include "encoding.h" #include "io.h" #include "table.h" @@ -47,7 +49,7 @@ struct table_entry *parse_table(struct stream *s) { case ELIF_MAGIC: case HNFN_MAGIC: case NEKO_MAGIC: - break; + read_elif(s, root); case FILE_MAGIC: break; default: @@ -57,6 +59,51 @@ struct table_entry *parse_table(struct stream *s) { } +/* Reads the contents of an eliF chunk. If there is an entry with a + matching key in the linked list specified by `root`, that structure + will be modified. Otherwise, a new entry will be created and appended + to the linked list. */ +void read_elif(struct stream *s, struct table_entry *root) { + char *name, *buf; + uint16_t name_size; + uint32_t key; + struct table_entry *cur; + + stream_read(&key, s, sizeof(uint32_t)); + stream_read(&name_size, s, sizeof(uint16_t)); + + /* The value provided by the archive represents the number of + UTF-16LE characters, not the number of bytes in the string. */ + name_size = name_size * 2 + 2; + + for (cur = root; cur != NULL && cur->key != key; cur = cur->next); + if (cur == NULL) { + cur = calloc(sizeof(struct table_entry), 1); + if (cur == NULL) return; + entry_append(root, cur); + } + + if (name_size < 0x100) { + buf = malloc(name_size); + name = malloc(name_size); + if (buf == NULL || name == NULL) return; + + stream_read(buf, s, name_size); + utf16le_decode(buf, name, name_size); + free(buf); + + name = realloc(name, strlen(name) + 1); + if (name == NULL) return; + } else { + /* strdup isn't defined in ISO/IEC 9899:1999 C. */ + name = malloc(14); + if (name == NULL) return; + strncpy(name, "COPYRIGHT.txt", 14); + } + cur->filename = name; +} + + /* Inserts `e` to the end of the linked list specified by `root`. */ void entry_append(struct table_entry *root, struct table_entry *e) { struct table_entry *cur; diff --git a/src/table.h b/src/table.h index 488e67f..c7c85bb 100644 --- a/src/table.h +++ b/src/table.h @@ -37,6 +37,7 @@ struct segment { struct table_entry { bool encrypted; /* Whether or not it's encrypted. */ bool compressed; /* Whether or not it's compressed. */ + char *filename; /* String containing file's name. */ uint32_t key; /* File-specific key for encryption. */ uint64_t ctime; /* Timestamp of creation time. */ uint64_t segment_count; /* Number of segments. */ @@ -49,6 +50,12 @@ struct table_entry { in the archive's table section. */ struct table_entry *parse_table(struct stream *s); +/* Reads the contents of an eliF chunk. If there is an entry with a + matching key in the linked list specified by `root`, that structure + will be modified. Otherwise, a new entry will be created and appended + to the linked list. */ +void read_elif(struct stream *s, struct table_entry *root); + /* Inserts `e` to the end of the linked list specified by `root`. */ void entry_append(struct table_entry *root, struct table_entry *e); |