Remove unused flag 'building'
[tennix.git] / src / archive.cc
blobac4b82c4c2d9b74a98b13b6db5cb5e36741270a7
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 "tennix.h"
26 #include <iostream>
28 #include <libgen.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <unistd.h>
33 #include <errno.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
37 #include <arpa/inet.h>
39 #include "archive.h"
41 static void
42 xormem(char* mem, uint32_t length, char key)
44 char *i = mem, *end = mem+length;
45 for(; i != end; i++) {
46 *i ^= key;
50 TennixArchive::TennixArchive()
51 : fp(NULL)
52 , header()
53 , items(NULL)
54 , blobs(NULL)
55 , offset(0)
56 , current_item(0)
58 strcpy(header.header, TENNIX_ARCHIVE_HEADER);
59 header.items = 0;
62 TennixArchive::TennixArchive(const char* filename, const char* fallback)
63 : fp(NULL)
64 , header()
65 , items(NULL)
66 , blobs(NULL)
67 , offset(0)
68 , current_item(0)
70 fp = fopen(filename, "rb");
71 if (fp == NULL && fallback != NULL) {
72 fp = fopen(fallback, "rb");
75 if (fp == NULL) {
76 fprintf(stderr, "Cannot open archive: %s\n", filename);
77 exit(1);
80 offset = sizeof(TennixArchiveHeader)*fread(&(header), sizeof(TennixArchiveHeader), 1, fp);
81 tnx_assert(offset == sizeof(TennixArchiveHeader));
82 tnx_assert(strncmp(header.header, TENNIX_ARCHIVE_HEADER, TENNIX_ARCHIVE_HEADER_LEN) == 0);
83 tnx_assert(header.versionmajor == TENNIX_ARCHIVE_VERSIONMAJOR);
84 tnx_assert(header.versionminor == TENNIX_ARCHIVE_VERSIONMINOR);
86 items = (TennixArchiveItem*)calloc(header.items, sizeof(TennixArchiveItem));
87 tnx_assert(items != NULL);
88 offset += sizeof(TennixArchiveItem)*fread(items, sizeof(TennixArchiveItem), header.items, fp);
89 tnx_assert(offset == sizeof(TennixArchiveHeader) + header.items*sizeof(TennixArchiveItem));
91 xormem((char*)(items), header.items*sizeof(TennixArchiveItem), header.key);
93 for (int i=0; i<header.items; i++) {
94 /* convert offset + length from network byte order */
95 items[i].offset = ntohl(items[i].offset);
96 items[i].length = ntohl(items[i].length);
100 std::ostream&
101 operator<<(std::ostream& out, TennixArchiveHeader& header)
103 out << "Header: " << header.header << std::endl;
104 out << "Version: " <<
105 (int)header.versionmajor << '.' <<
106 (int)header.versionminor << std::endl;
107 out << "Master key: " << header.key << std::endl;
108 out << "Items: " << header.items;
110 return out;
113 std::ostream&
114 operator<<(std::ostream& out, TennixArchiveItem& item)
116 out << "File: " << item.filename << std::endl;
117 out << "Size: " << item.length << std::endl;
118 out << "Offset: " << item.offset << std::endl;
119 out << "Key: " << (int)item.key;
121 return out;
125 TennixArchive::setItemFilename(const char* filename)
127 int i;
129 for (i=0; i<header.items; i++) {
130 if (strncmp(items[i].filename, filename, TENNIX_ARCHIVE_ITEM_MAXNAME) == 0) {
131 current_item = i;
132 return 1;
136 return 0;
139 char*
140 TennixArchive::getItemBytes()
142 size_t size = getItemSize();
143 char* data = (char*)malloc(size+1);
144 /* the last char is a null character, so this works for strings, too */
145 data[size]='\0';
146 fseek(fp, items[current_item].offset, SEEK_SET);
147 tnx_assert(fread(data, size, 1, fp) == 1);
148 xormem(data, size, items[current_item].key);
149 return data;
152 void
153 TennixArchive::appendItem(char* filename, char* data, uint32_t length)
155 TennixArchiveItem* item;
157 header.items++;
158 items = (TennixArchiveItem*)realloc(items, sizeof(TennixArchiveItem)*header.items);
159 blobs = (char**)realloc(blobs, sizeof(char*)*header.items);
161 item = &(items[header.items-1]);
162 blobs[header.items-1] = data;
163 for (int i=0; i<TENNIX_ARCHIVE_ITEM_MAXNAME; i++) {
164 item->filename[i] = data[(i*2)%length];
166 strcpy(item->filename, filename);
167 item->length = length;
170 void
171 TennixArchive::buildFile(char* filename)
173 size_t offset = 0;
174 size_t *memsize = NULL;
176 memsize = (size_t*)calloc(header.items, sizeof(size_t));
178 fp = fopen(filename, "wb");
179 tnx_assert(fp != NULL);
181 offset += sizeof(TennixArchiveHeader) + header.items*sizeof(TennixArchiveItem);
183 header.versionmajor = TENNIX_ARCHIVE_VERSIONMAJOR;
184 header.versionminor = TENNIX_ARCHIVE_VERSIONMINOR;
186 header.key = (0xaa + 0x77*header.items*3) % 0xff;
188 for (int i=0; i<header.items; i++) {
189 items[i].offset = htonl(offset); /* network byte order */
190 items[i].key = 0xaa ^ ((i<<2)%0x100);
191 xormem(blobs[i], items[i].length, items[i].key);
192 memsize[i] = items[i].length;
193 offset += items[i].length;
194 items[i].length = htonl(items[i].length); /* network byte order */
195 xormem((char*)(items + i), sizeof(TennixArchiveItem), header.key);
198 tnx_assert(fwrite(&(header), sizeof(TennixArchiveHeader), 1, fp) == 1);
199 tnx_assert(fwrite(items, sizeof(TennixArchiveItem), header.items, fp) == header.items);
200 for (int i=0; i<header.items; i++) {
201 tnx_assert(fwrite(blobs[i], memsize[i], 1, fp) == 1);
202 free(blobs[i]);
205 free(memsize);
206 free(blobs);
209 std::ostream&
210 operator<<(std::ostream& out, TennixArchive& archive)
212 out << "Tennix Archive" << std::endl;
213 out << archive.header << std::endl;
215 for (int i=0; i<archive.header.items; i++) {
216 out << "=======================" << std::endl;
217 out << archive.items[i] << std::endl;
219 out << "=== END OF ARCHIVE ====" << std::endl;
221 return out;