Enable all warnings
[tennix.git] / src / archive.cc
blob921d1df2ee6bb2e53cb37a02d54f09735d0226eb
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)
57 , building(1)
59 strcpy(header.header, TENNIX_ARCHIVE_HEADER);
60 header.items = 0;
63 TennixArchive::TennixArchive(const char* filename, const char* fallback)
64 : fp(NULL)
65 , header()
66 , items(NULL)
67 , blobs(NULL)
68 , offset(0)
69 , current_item(0)
70 , building(0)
72 fp = fopen(filename, "rb");
73 if (fp == NULL && fallback != NULL) {
74 fp = fopen(fallback, "rb");
77 if (fp == NULL) {
78 fprintf(stderr, "Cannot open archive: %s\n", filename);
79 exit(1);
82 offset = sizeof(TennixArchiveHeader)*fread(&(header), sizeof(TennixArchiveHeader), 1, fp);
83 tnx_assert(offset == sizeof(TennixArchiveHeader));
84 tnx_assert(strncmp(header.header, TENNIX_ARCHIVE_HEADER, TENNIX_ARCHIVE_HEADER_LEN) == 0);
85 tnx_assert(header.versionmajor == TENNIX_ARCHIVE_VERSIONMAJOR);
86 tnx_assert(header.versionminor == TENNIX_ARCHIVE_VERSIONMINOR);
88 items = (TennixArchiveItem*)calloc(header.items, sizeof(TennixArchiveItem));
89 tnx_assert(items != NULL);
90 offset += sizeof(TennixArchiveItem)*fread(items, sizeof(TennixArchiveItem), header.items, fp);
91 tnx_assert(offset == sizeof(TennixArchiveHeader) + header.items*sizeof(TennixArchiveItem));
93 xormem((char*)(items), header.items*sizeof(TennixArchiveItem), header.key);
95 for (int i=0; i<header.items; i++) {
96 /* convert offset + length from network byte order */
97 items[i].offset = ntohl(items[i].offset);
98 items[i].length = ntohl(items[i].length);
102 std::ostream&
103 operator<<(std::ostream& out, TennixArchiveHeader& header)
105 out << "Header: " << header.header << std::endl;
106 out << "Version: " <<
107 (int)header.versionmajor << '.' <<
108 (int)header.versionminor << std::endl;
109 out << "Master key: " << header.key << std::endl;
110 out << "Items: " << header.items;
112 return out;
115 std::ostream&
116 operator<<(std::ostream& out, TennixArchiveItem& item)
118 out << "File: " << item.filename << std::endl;
119 out << "Size: " << item.length << std::endl;
120 out << "Offset: " << item.offset << std::endl;
121 out << "Key: " << (int)item.key;
123 return out;
127 TennixArchive::setItemFilename(const char* filename)
129 int i;
131 for (i=0; i<header.items; i++) {
132 if (strncmp(items[i].filename, filename, TENNIX_ARCHIVE_ITEM_MAXNAME) == 0) {
133 current_item = i;
134 return 1;
138 return 0;
141 char*
142 TennixArchive::getItemBytes()
144 size_t size = getItemSize();
145 char* data = (char*)malloc(size+1);
146 /* the last char is a null character, so this works for strings, too */
147 data[size]='\0';
148 fseek(fp, items[current_item].offset, SEEK_SET);
149 tnx_assert(fread(data, size, 1, fp) == 1);
150 xormem(data, size, items[current_item].key);
151 return data;
154 void
155 TennixArchive::appendItem(char* filename, char* data, uint32_t length)
157 TennixArchiveItem* item;
159 header.items++;
160 items = (TennixArchiveItem*)realloc(items, sizeof(TennixArchiveItem)*header.items);
161 blobs = (char**)realloc(blobs, sizeof(char*)*header.items);
163 item = &(items[header.items-1]);
164 blobs[header.items-1] = data;
165 for (int i=0; i<TENNIX_ARCHIVE_ITEM_MAXNAME; i++) {
166 item->filename[i] = data[(i*2)%length];
168 strcpy(item->filename, filename);
169 item->length = length;
172 void
173 TennixArchive::buildFile(char* filename)
175 size_t offset = 0;
176 size_t *memsize = NULL;
178 memsize = (size_t*)calloc(header.items, sizeof(size_t));
180 fp = fopen(filename, "wb");
181 tnx_assert(fp != NULL);
183 offset += sizeof(TennixArchiveHeader) + header.items*sizeof(TennixArchiveItem);
185 header.versionmajor = TENNIX_ARCHIVE_VERSIONMAJOR;
186 header.versionminor = TENNIX_ARCHIVE_VERSIONMINOR;
188 header.key = (0xaa + 0x77*header.items*3) % 0xff;
190 for (int i=0; i<header.items; i++) {
191 items[i].offset = htonl(offset); /* network byte order */
192 items[i].key = 0xaa ^ ((i<<2)%0x100);
193 xormem(blobs[i], items[i].length, items[i].key);
194 memsize[i] = items[i].length;
195 offset += items[i].length;
196 items[i].length = htonl(items[i].length); /* network byte order */
197 xormem((char*)(items + i), sizeof(TennixArchiveItem), header.key);
200 tnx_assert(fwrite(&(header), sizeof(TennixArchiveHeader), 1, fp) == 1);
201 tnx_assert(fwrite(items, sizeof(TennixArchiveItem), header.items, fp) == header.items);
202 for (int i=0; i<header.items; i++) {
203 tnx_assert(fwrite(blobs[i], memsize[i], 1, fp) == 1);
204 free(blobs[i]);
207 free(memsize);
208 free(blobs);
211 std::ostream&
212 operator<<(std::ostream& out, TennixArchive& archive)
214 out << "Tennix Archive" << std::endl;
215 out << archive.header << std::endl;
217 for (int i=0; i<archive.header.items; i++) {
218 out << "=======================" << std::endl;
219 out << archive.items[i] << std::endl;
221 out << "=== END OF ARCHIVE ====" << std::endl;
223 return out;