fb435c9e7d68d0b2fcc50782e6468263dbad94b8
[tennix.git] / archive.cc
blobfb435c9e7d68d0b2fcc50782e6468263dbad94b8
2 /**
4 * Tennix Archive File Format
5 * Copyright (C) 2009-2010 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 <libgen.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <assert.h>
29 #include <string.h>
30 #include <unistd.h>
31 #include <errno.h>
32 #include <sys/types.h>
33 #include <sys/stat.h>
35 #include <arpa/inet.h>
37 #include "archive.hh"
39 TennixArchive::TennixArchive(const char* filename)
41 fp = fopen(filename, "rb");
42 assert(fp != NULL);
44 offset = sizeof(TennixArchiveHeader)*fread(&(header), sizeof(TennixArchiveHeader), 1, fp);
45 assert(offset == sizeof(TennixArchiveHeader));
46 assert(strncmp(header.header, TENNIX_ARCHIVE_HEADER, TENNIX_ARCHIVE_HEADER_LEN) == 0);
47 assert(header.versionmajor == TENNIX_ARCHIVE_VERSIONMAJOR);
48 assert(header.versionminor == TENNIX_ARCHIVE_VERSIONMINOR);
50 items = (TennixArchiveItem*)calloc(header.items, sizeof(TennixArchiveItem));
51 assert(items != NULL);
52 offset += sizeof(TennixArchiveItem)*fread(items, sizeof(TennixArchiveItem), header.items, fp);
53 assert(offset == sizeof(TennixArchiveHeader) + header.items*sizeof(TennixArchiveItem));
55 xormem((char*)(items), header.items*sizeof(TennixArchiveItem), header.key);
57 for (int i=0; i<header.items; i++) {
58 /* convert offset + length from network byte order */
59 items[i].offset = ntohl(items[i].offset);
60 items[i].length = ntohl(items[i].length);
63 current_item = 0;
65 building = 0;
69 void
70 TennixArchive::dump()
72 int x;
73 fprintf(stderr, "Tennix Archive\n");
74 fprintf(stderr, "Header: %s\n", header.header);
75 fprintf(stderr, "Version: %d.%d\n", header.versionmajor, header.versionminor);
76 fprintf(stderr, "Master key: %d\n", header.key);
77 fprintf(stderr, "Items: %d\n", header.items);
78 for (x = 0; x < header.items; x++) {
79 fprintf(stderr, "===========\n");
80 fprintf(stderr, "File: %s (#%d)\n", items[x].filename, x);
81 fprintf(stderr, "Size: %d\n", items[x].length);
82 fprintf(stderr, "Offset: %d\n", items[x].offset);
83 fprintf(stderr, "Key: %d\n", items[x].key);
87 int
88 TennixArchive::setItemFilename(const char* filename)
90 int i;
92 for (i=0; i<header.items; i++) {
93 if (strncmp(items[i].filename, filename, TENNIX_ARCHIVE_ITEM_MAXNAME) == 0) {
94 current_item = i;
95 return 1;
99 return 0;
102 char*
103 TennixArchive::getItemBytes()
105 size_t size = getItemSize();
106 char* data = (char*)malloc(size+1);
107 /* the last char is a null character, so this works for strings, too */
108 data[size]='\0';
109 fseek(fp, items[current_item].offset, SEEK_SET);
110 assert(fread(data, size, 1, fp) == 1);
111 xormem(data, size, items[current_item].key);
112 return data;
115 void
116 TennixArchive::xormem(char* mem, uint32_t length, char key)
118 char *i = mem, *end = mem+length;
120 for(; i != end; i++) {
121 *i ^= key;
125 void
126 TennixArchive::appendItem(char* filename, char* data, uint32_t length)
128 TennixArchiveItem* item;
130 header.items++;
131 items = (TennixArchiveItem*)realloc(items, sizeof(TennixArchiveItem)*header.items);
132 blobs = (char**)realloc(blobs, sizeof(char*)*header.items);
134 item = &(items[header.items-1]);
135 blobs[header.items-1] = data;
136 for (int i=0; i<TENNIX_ARCHIVE_ITEM_MAXNAME; i++) {
137 item->filename[i] = data[(i*2)%length];
139 strcpy(item->filename, filename);
140 item->length = length;
143 void
144 TennixArchive::buildFile(char* filename)
146 size_t offset = 0;
147 size_t *memsize = NULL;
149 memsize = (size_t*)calloc(header.items, sizeof(size_t));
151 fp = fopen(filename, "wb");
152 assert(fp != NULL);
154 offset += sizeof(TennixArchiveHeader) + header.items*sizeof(TennixArchiveItem);
156 header.versionmajor = TENNIX_ARCHIVE_VERSIONMAJOR;
157 header.versionminor = TENNIX_ARCHIVE_VERSIONMINOR;
159 header.key = (0xaa + 0x77*header.items*3) % 0xff;
161 fprintf(stderr, "Packing: ");
162 for (int i=0; i<header.items; i++) {
163 fprintf(stderr, "%s", items[i].filename);
164 items[i].offset = htonl(offset); /* network byte order */
165 items[i].key = 0xaa ^ ((i<<2)%0x100);
166 xormem(blobs[i], items[i].length, items[i].key);
167 memsize[i] = items[i].length;
168 offset += items[i].length;
169 items[i].length = htonl(items[i].length); /* network byte order */
170 xormem((char*)(items + i), sizeof(TennixArchiveItem), header.key);
171 if (i != header.items-1) {
172 fprintf(stderr, ", ");
175 fputc('\n', stderr);
177 fprintf(stderr, "Writing: %s", filename);
178 fputc('.', stderr);
179 assert(fwrite(&(header), sizeof(TennixArchiveHeader), 1, fp) == 1);
180 fputc('.', stderr);
181 assert(fwrite(items, sizeof(TennixArchiveItem), header.items, fp) == header.items);
182 fputc('.', stderr);
183 for (int i=0; i<header.items; i++) {
184 assert(fwrite(blobs[i], memsize[i], 1, fp) == 1);
185 free(blobs[i]);
187 fputc('.', stderr);
188 fprintf(stderr, "OK\n");
190 free(memsize);
191 free(blobs);