Loading progress bar, add missing header files, Maemo
[tennix.git] / archive.c
blob61991fe6d3d4623975a849e2572cd06313434acd
2 /**
4 * Tennix Archive File Format
5 * Copyright (C) 2009 Thomas Perl <thp@thpinfo.com>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
20 * MA 02110-1301, USA.
22 **/
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <assert.h>
28 #include <string.h>
29 #include <unistd.h>
30 #include <errno.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
34 #include <arpa/inet.h>
36 #include "archive.h"
38 #ifdef TENNIXAR_STANDALONE
39 int main(int argc, char* argv[])
41 TennixArchive *tnxar;
42 char *data;
43 FILE *fp;
44 char *filename;
45 char *bn = (char*)basename(argv[0]);
46 int len, i;
47 struct stat st;
49 if(strcmp(bn, "archive") == 0) {
50 if (argc < 2) {
51 fprintf(stderr, "Usage: %s archive.tnx file1 [....]\n", bn);
52 exit(EXIT_FAILURE);
53 } else if (argc == 2) {
54 fprintf(stderr, "Refusing to create an empty archive.\n");
55 exit(EXIT_FAILURE);
58 if (stat(argv[1], &st) != -1) {
59 fprintf(stderr, "File %s already exists. Aborting.\n", argv[1]);
60 exit(EXIT_FAILURE);
62 tnxar = tnxar_create();
64 fprintf(stderr, "Creating %s with %d files\n", argv[1], argc-2);
65 for (i=2; i<argc; i++) {
66 fp = fopen(argv[i], "rb");
67 fseek(fp, 0, SEEK_END);
68 len = ftell(fp);
69 fseek(fp, 0, SEEK_SET);
70 data = (char*)malloc(len);
71 fread(data, len, 1, fp);
72 fclose(fp);
73 tnxar_append(tnxar, (char*)basename(argv[i]), data, len);
75 tnxar_build(tnxar, argv[1]);
76 } else if(strcmp(bn, "dump") == 0) {
77 if (argc < 2) {
78 fprintf(stderr, "Usage: %s archive.tnx\n", bn);
79 exit(EXIT_FAILURE);
81 tnxar = tnxar_open(argv[1]);
82 tnxar_dump(tnxar);
83 tnxar_close(tnxar);
84 } else if(strcmp(bn, "extract") == 0) {
85 if (argc < 2 || argc > 3) {
86 fprintf(stderr, "Usage: %s archive.tnx [file]\n", bn);
87 exit(EXIT_FAILURE);
89 tnxar = tnxar_open(argv[1]);
90 if (argc == 2) {
91 while (!tnxar_eof(tnxar)) {
92 filename = tnxar_get_current_filename(tnxar);
93 fprintf(stderr, "Extracting: %s", filename);
94 data = tnxar_read_current(tnxar);
95 len = tnxar_size_current(tnxar);
96 fprintf(stderr, " (%d bytes)", len);
97 fp = fopen(filename, "wb");
98 fputc('.', stderr);
99 fwrite(data, len, 1, fp);
100 fputc('.', stderr);
101 fclose(fp);
102 fprintf(stderr, ".OK\n");
103 free(data);
104 tnxar_next(tnxar);
106 } else if (argc == 3) {
107 filename = argv[2];
108 if (tnxar_set_current_filename(tnxar, filename) != 0) {
109 fprintf(stderr, "Extracting: %s", filename);
110 data = tnxar_read_current(tnxar);
111 len = tnxar_size_current(tnxar);
112 fprintf(stderr, " (%d bytes)", len);
113 fp = fopen(filename, "wb");
114 fputc('.', stderr);
115 fwrite(data, len, 1, fp);
116 fputc('.', stderr);
117 fclose(fp);
118 fprintf(stderr, ".OK\n");
119 free(data);
120 } else {
121 fprintf(stderr, "File not found in %s: %s\n", argv[1], filename);
122 tnxar_close(tnxar);
123 exit(EXIT_FAILURE);
126 tnxar_close(tnxar);
129 return EXIT_SUCCESS;
131 #endif
133 TennixArchive* tnxar_open(char* filename)
135 int i;
137 TennixArchive *tnxar = (TennixArchive*)malloc(sizeof(TennixArchive));
138 assert(tnxar != NULL);
140 tnxar->fp = fopen(filename, "rb");
141 assert(tnxar->fp != NULL);
143 tnxar->offset = sizeof(TennixArchiveHeader)*fread(&(tnxar->header), sizeof(TennixArchiveHeader), 1, tnxar->fp);
144 assert(tnxar->offset == sizeof(TennixArchiveHeader));
145 assert(strcmp(tnxar->header.header, TENNIX_ARCHIVE_HEADER) == 0);
146 assert(tnxar->header.versionmajor == TENNIX_ARCHIVE_VERSIONMAJOR);
147 assert(tnxar->header.versionminor == TENNIX_ARCHIVE_VERSIONMINOR);
149 tnxar->items = (TennixArchiveItem*)calloc(tnxar->header.items, sizeof(TennixArchiveItem));
150 assert(tnxar->items != NULL);
151 tnxar->offset += sizeof(TennixArchiveItem)*fread(tnxar->items, sizeof(TennixArchiveItem), tnxar->header.items, tnxar->fp);
152 assert(tnxar->offset == sizeof(TennixArchiveHeader) + tnxar->header.items*sizeof(TennixArchiveItem));
154 tnxar_xormem((char*)(tnxar->items), tnxar->header.items*sizeof(TennixArchiveItem), tnxar->header.key);
156 for (i=0; i<tnxar->header.items; i++) {
157 /* convert offset + length from network byte order */
158 tnxar->items[i].offset = ntohl(tnxar->items[i].offset);
159 tnxar->items[i].length = ntohl(tnxar->items[i].length);
162 tnxar->current_item = 0;
164 return tnxar;
168 #ifdef TENNIXAR_STANDALONE
169 void tnxar_dump(TennixArchive* tnxar)
171 fprintf(stderr, "Tennix Archive\n");
172 fprintf(stderr, "Header: %s\n", tnxar->header.header);
173 fprintf(stderr, "Version: %d.%d\n", tnxar->header.versionmajor, tnxar->header.versionminor);
174 fprintf(stderr, "Master key: %d\n", tnxar->header.key);
175 fprintf(stderr, "Items: %d\n", tnxar->header.items);
176 for (tnxar->current_item = 0; tnxar->current_item < tnxar->header.items; tnxar->current_item++) {
177 fprintf(stderr, "===========\n");
178 fprintf(stderr, "File: %s (#%d)\n", tnxar->items[tnxar->current_item].filename, tnxar->current_item);
179 fprintf(stderr, "Size: %d\n", tnxar->items[tnxar->current_item].length);
180 fprintf(stderr, "Offset: %d\n", tnxar->items[tnxar->current_item].offset);
181 fprintf(stderr, "Key: %d\n", tnxar->items[tnxar->current_item].key);
184 #endif
186 int tnxar_set_current_filename(TennixArchive* tnxar, char* filename)
188 int i;
190 for (i=0; i<tnxar->header.items; i++) {
191 if (strcmp(tnxar->items[i].filename, filename) == 0) {
192 tnxar->current_item = i;
193 return 1;
197 return 0;
200 char* tnxar_get_current_filename(TennixArchive* tnxar)
202 return tnxar->items[tnxar->current_item].filename;
205 char* tnxar_read_current(TennixArchive* tnxar)
207 int size = tnxar_size_current(tnxar);
208 char* data = (char*)malloc(size);
209 fseek(tnxar->fp, tnxar->items[tnxar->current_item].offset, SEEK_SET);
210 assert(fread(data, size, 1, tnxar->fp) == 1);
211 tnxar_xormem(data, size, tnxar->items[tnxar->current_item].key);
212 return data;
215 size_t tnxar_size_current(TennixArchive* tnxar)
217 return tnxar->items[tnxar->current_item].length;
220 int tnxar_eof(TennixArchive* tnxar)
222 return tnxar->current_item >= tnxar->header.items;
225 void tnxar_next(TennixArchive* tnxar)
227 tnxar->current_item++;
230 void tnxar_close(TennixArchive *tnxar)
232 assert(tnxar != NULL);
234 fclose(tnxar->fp);
235 tnxar->fp = NULL;
237 free(tnxar->items);
238 tnxar->items = NULL;
240 free(tnxar);
243 void tnxar_xormem(char* mem, uint32_t length, char key)
245 char *i = mem, *end = mem+length;
247 for(; i != end; i++) {
248 *i ^= key;
252 #ifdef TENNIXAR_STANDALONE
253 TennixArchive* tnxar_create()
255 TennixArchive *tnxar = (TennixArchive*)calloc(sizeof(TennixArchive), 1);
256 assert(tnxar != NULL);
258 strcpy(tnxar->header.header, TENNIX_ARCHIVE_HEADER);
259 tnxar->header.items = 0;
262 void tnxar_append(TennixArchive* tnxar, char* filename, char* mem, uint32_t length)
264 int i;
265 TennixArchiveItem *item;
267 assert(tnxar != NULL);
269 tnxar->header.items++;
270 tnxar->items = (TennixArchiveItem*)realloc(tnxar->items, sizeof(TennixArchiveItem)*tnxar->header.items);
271 tnxar->blobs = (char**)realloc(tnxar->blobs, sizeof(char*)*tnxar->header.items);
273 item = &(tnxar->items[tnxar->header.items-1]);
274 tnxar->blobs[tnxar->header.items-1] = mem;
275 for (i=0; i<TENNIX_ARCHIVE_ITEM_MAXNAME; i++) {
276 item->filename[i] = mem[(i*2)%length];
278 strcpy(item->filename, filename);
279 item->length = length;
282 void tnxar_build(TennixArchive *tnxar, char* filename)
284 int i;
285 size_t offset = 0;
286 size_t *memsize = NULL;
287 assert(tnxar != NULL);
289 memsize = (size_t*)calloc(tnxar->header.items, sizeof(size_t));
291 tnxar->fp = fopen(filename, "wb");
293 offset += sizeof(TennixArchiveHeader) + tnxar->header.items*sizeof(TennixArchiveItem);
295 tnxar->header.versionmajor = TENNIX_ARCHIVE_VERSIONMAJOR;
296 tnxar->header.versionminor = TENNIX_ARCHIVE_VERSIONMINOR;
298 tnxar->header.key = (0xaa + 0x77*tnxar->header.items*3) % 0xff;
300 for (i=0; i<tnxar->header.items; i++) {
301 fprintf(stderr, "Packing: %s", tnxar->items[i].filename);
302 tnxar->items[i].offset = htonl(offset); /* network byte order */
303 tnxar->items[i].key = 0xaa ^ ((i<<2)%0x100);
304 fputc('.', stderr);
305 tnxar_xormem(tnxar->blobs[i], tnxar->items[i].length, tnxar->items[i].key);
306 fputc('.', stderr);
307 memsize[i] = tnxar->items[i].length;
308 offset += tnxar->items[i].length;
309 fputc('.', stderr);
310 tnxar->items[i].length = htonl(tnxar->items[i].length); /* network byte order */
311 tnxar_xormem((char*)(tnxar->items + i), sizeof(TennixArchiveItem), tnxar->header.key);
312 fputc('.', stderr);
313 fprintf(stderr, "OK\n");
316 fprintf(stderr, "Writing: %s", filename);
317 fputc('.', stderr);
318 fwrite(&(tnxar->header), sizeof(TennixArchiveHeader), 1, tnxar->fp);
319 fputc('.', stderr);
320 fwrite(tnxar->items, sizeof(TennixArchiveItem), tnxar->header.items, tnxar->fp);
321 fputc('.', stderr);
322 for (i=0; i<tnxar->header.items; i++) {
323 fputc('.', stderr);
324 fwrite(tnxar->blobs[i], memsize[i], 1, tnxar->fp);
325 free(tnxar->blobs[i]);
327 fprintf(stderr, "OK\n");
329 free(memsize);
330 free(tnxar->blobs);
331 fclose(tnxar->fp);
333 #endif