summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/encoding.c36
-rw-r--r--src/encoding.h23
-rw-r--r--src/io.c19
-rw-r--r--src/io.h3
-rw-r--r--src/table.c49
-rw-r--r--src/table.h7
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);
diff --git a/src/io.c b/src/io.c
index be894dd..c9627d3 100644
--- a/src/io.c
+++ b/src/io.c
@@ -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;
+ }
}
diff --git a/src/io.h b/src/io.h
index 87f93b2..a543ae5 100644
--- a/src/io.h
+++ b/src/io.h
@@ -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);