Tennix 1.1 "Classic Championship Tour 2011" released
[tennix.git] / archive.cc
blob55461731d9b00f425708ff0d4027c885c0b82bbd
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 **/
24 #include <iostream>
26 #include <libgen.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <assert.h>
30 #include <string.h>
31 #include <unistd.h>
32 #include <errno.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
36 #include <arpa/inet.h>
38 #include "archive.hh"
40 TennixArchive::TennixArchive(const char* filename, const char* fallback)
42 fp = fopen(filename, "rb");
43 if (fp == NULL && fallback != NULL) {
44 fp = fopen(fallback, "rb");
46 assert(fp != NULL);
48 offset = sizeof(TennixArchiveHeader)*fread(&(header), sizeof(TennixArchiveHeader), 1, fp);
49 assert(offset == sizeof(TennixArchiveHeader));
50 assert(strncmp(header.header, TENNIX_ARCHIVE_HEADER, TENNIX_ARCHIVE_HEADER_LEN) == 0);
51 assert(header.versionmajor == TENNIX_ARCHIVE_VERSIONMAJOR);
52 assert(header.versionminor == TENNIX_ARCHIVE_VERSIONMINOR);
54 items = (TennixArchiveItem*)calloc(header.items, sizeof(TennixArchiveItem));
55 assert(items != NULL);
56 offset += sizeof(TennixArchiveItem)*fread(items, sizeof(TennixArchiveItem), header.items, fp);
57 assert(offset == sizeof(TennixArchiveHeader) + header.items*sizeof(TennixArchiveItem));
59 xormem((char*)(items), header.items*sizeof(TennixArchiveItem), header.key);
61 for (int i=0; i<header.items; i++) {
62 /* convert offset + length from network byte order */
63 items[i].offset = ntohl(items[i].offset);
64 items[i].length = ntohl(items[i].length);
67 current_item = 0;
69 building = 0;
72 std::ostream&
73 operator<<(std::ostream& out, TennixArchiveHeader& header)
75 out << "Header: " << header.header << std::endl;
76 out << "Version: " <<
77 (int)header.versionmajor << '.' <<
78 (int)header.versionminor << std::endl;
79 out << "Master key: " << header.key << std::endl;
80 out << "Items: " << header.items;
82 return out;
85 std::ostream&
86 operator<<(std::ostream& out, TennixArchiveItem& item)
88 out << "File: " << item.filename << std::endl;
89 out << "Size: " << item.length << std::endl;
90 out << "Offset: " << item.offset << std::endl;
91 out << "Key: " << (int)item.key;
93 return out;
96 int
97 TennixArchive::setItemFilename(const char* filename)
99 int i;
101 for (i=0; i<header.items; i++) {
102 if (strncmp(items[i].filename, filename, TENNIX_ARCHIVE_ITEM_MAXNAME) == 0) {
103 current_item = i;
104 return 1;
108 return 0;
111 char*
112 TennixArchive::getItemBytes()
114 size_t size = getItemSize();
115 char* data = (char*)malloc(size+1);
116 /* the last char is a null character, so this works for strings, too */
117 data[size]='\0';
118 fseek(fp, items[current_item].offset, SEEK_SET);
119 assert(fread(data, size, 1, fp) == 1);
120 xormem(data, size, items[current_item].key);
121 return data;
124 void
125 TennixArchive::xormem(char* mem, uint32_t length, char key)
127 char *i = mem, *end = mem+length;
129 for(; i != end; i++) {
130 *i ^= key;
134 void
135 TennixArchive::appendItem(char* filename, char* data, uint32_t length)
137 TennixArchiveItem* item;
139 header.items++;
140 items = (TennixArchiveItem*)realloc(items, sizeof(TennixArchiveItem)*header.items);
141 blobs = (char**)realloc(blobs, sizeof(char*)*header.items);
143 item = &(items[header.items-1]);
144 blobs[header.items-1] = data;
145 for (int i=0; i<TENNIX_ARCHIVE_ITEM_MAXNAME; i++) {
146 item->filename[i] = data[(i*2)%length];
148 strcpy(item->filename, filename);
149 item->length = length;
152 void
153 TennixArchive::buildFile(char* filename)
155 size_t offset = 0;
156 size_t *memsize = NULL;
158 memsize = (size_t*)calloc(header.items, sizeof(size_t));
160 fp = fopen(filename, "wb");
161 assert(fp != NULL);
163 offset += sizeof(TennixArchiveHeader) + header.items*sizeof(TennixArchiveItem);
165 header.versionmajor = TENNIX_ARCHIVE_VERSIONMAJOR;
166 header.versionminor = TENNIX_ARCHIVE_VERSIONMINOR;
168 header.key = (0xaa + 0x77*header.items*3) % 0xff;
170 fprintf(stderr, "Packing: ");
171 for (int i=0; i<header.items; i++) {
172 fprintf(stderr, "%s", items[i].filename);
173 items[i].offset = htonl(offset); /* network byte order */
174 items[i].key = 0xaa ^ ((i<<2)%0x100);
175 xormem(blobs[i], items[i].length, items[i].key);
176 memsize[i] = items[i].length;
177 offset += items[i].length;
178 items[i].length = htonl(items[i].length); /* network byte order */
179 xormem((char*)(items + i), sizeof(TennixArchiveItem), header.key);
180 if (i != header.items-1) {
181 fprintf(stderr, ", ");
184 fputc('\n', stderr);
186 fprintf(stderr, "Writing: %s", filename);
187 fputc('.', stderr);
188 assert(fwrite(&(header), sizeof(TennixArchiveHeader), 1, fp) == 1);
189 fputc('.', stderr);
190 assert(fwrite(items, sizeof(TennixArchiveItem), header.items, fp) == header.items);
191 fputc('.', stderr);
192 for (int i=0; i<header.items; i++) {
193 assert(fwrite(blobs[i], memsize[i], 1, fp) == 1);
194 free(blobs[i]);
196 fputc('.', stderr);
197 fprintf(stderr, "OK\n");
199 free(memsize);
200 free(blobs);
203 std::ostream&
204 operator<<(std::ostream& out, TennixArchive& archive)
206 out << "Tennix Archive" << std::endl;
207 out << archive.header << std::endl;
209 for (int i=0; i<archive.header.items; i++) {
210 out << "=======================" << std::endl;
211 out << archive.items[i] << std::endl;
213 out << "=== END OF ARCHIVE ====" << std::endl;
215 return out;