Version 1.2.0 with new build/configure system
[tennix.git] / src / archive.cc
blob962a950e1766eed757acc43bda4a90642196c884
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 TennixArchive::TennixArchive()
42 : fp(NULL)
43 , header()
44 , items(NULL)
45 , blobs(NULL)
46 , offset(0)
47 , current_item(0)
48 , building(1)
50 strcpy(header.header, TENNIX_ARCHIVE_HEADER);
51 header.items = 0;
54 TennixArchive::TennixArchive(const char* filename, const char* fallback)
55 : fp(NULL)
56 , header()
57 , items(NULL)
58 , blobs(NULL)
59 , offset(0)
60 , current_item(0)
61 , building(0)
63 fp = fopen(filename, "rb");
64 if (fp == NULL && fallback != NULL) {
65 fp = fopen(fallback, "rb");
67 tnx_assert(fp != NULL);
69 offset = sizeof(TennixArchiveHeader)*fread(&(header), sizeof(TennixArchiveHeader), 1, fp);
70 tnx_assert(offset == sizeof(TennixArchiveHeader));
71 tnx_assert(strncmp(header.header, TENNIX_ARCHIVE_HEADER, TENNIX_ARCHIVE_HEADER_LEN) == 0);
72 tnx_assert(header.versionmajor == TENNIX_ARCHIVE_VERSIONMAJOR);
73 tnx_assert(header.versionminor == TENNIX_ARCHIVE_VERSIONMINOR);
75 items = (TennixArchiveItem*)calloc(header.items, sizeof(TennixArchiveItem));
76 tnx_assert(items != NULL);
77 offset += sizeof(TennixArchiveItem)*fread(items, sizeof(TennixArchiveItem), header.items, fp);
78 tnx_assert(offset == sizeof(TennixArchiveHeader) + header.items*sizeof(TennixArchiveItem));
80 xormem((char*)(items), header.items*sizeof(TennixArchiveItem), header.key);
82 for (int i=0; i<header.items; i++) {
83 /* convert offset + length from network byte order */
84 items[i].offset = ntohl(items[i].offset);
85 items[i].length = ntohl(items[i].length);
89 std::ostream&
90 operator<<(std::ostream& out, TennixArchiveHeader& header)
92 out << "Header: " << header.header << std::endl;
93 out << "Version: " <<
94 (int)header.versionmajor << '.' <<
95 (int)header.versionminor << std::endl;
96 out << "Master key: " << header.key << std::endl;
97 out << "Items: " << header.items;
99 return out;
102 std::ostream&
103 operator<<(std::ostream& out, TennixArchiveItem& item)
105 out << "File: " << item.filename << std::endl;
106 out << "Size: " << item.length << std::endl;
107 out << "Offset: " << item.offset << std::endl;
108 out << "Key: " << (int)item.key;
110 return out;
114 TennixArchive::setItemFilename(const char* filename)
116 int i;
118 for (i=0; i<header.items; i++) {
119 if (strncmp(items[i].filename, filename, TENNIX_ARCHIVE_ITEM_MAXNAME) == 0) {
120 current_item = i;
121 return 1;
125 return 0;
128 char*
129 TennixArchive::getItemBytes()
131 size_t size = getItemSize();
132 char* data = (char*)malloc(size+1);
133 /* the last char is a null character, so this works for strings, too */
134 data[size]='\0';
135 fseek(fp, items[current_item].offset, SEEK_SET);
136 tnx_assert(fread(data, size, 1, fp) == 1);
137 xormem(data, size, items[current_item].key);
138 return data;
141 void
142 TennixArchive::xormem(char* mem, uint32_t length, char key)
144 char *i = mem, *end = mem+length;
146 for(; i != end; i++) {
147 *i ^= key;
151 void
152 TennixArchive::appendItem(char* filename, char* data, uint32_t length)
154 TennixArchiveItem* item;
156 header.items++;
157 items = (TennixArchiveItem*)realloc(items, sizeof(TennixArchiveItem)*header.items);
158 blobs = (char**)realloc(blobs, sizeof(char*)*header.items);
160 item = &(items[header.items-1]);
161 blobs[header.items-1] = data;
162 for (int i=0; i<TENNIX_ARCHIVE_ITEM_MAXNAME; i++) {
163 item->filename[i] = data[(i*2)%length];
165 strcpy(item->filename, filename);
166 item->length = length;
169 void
170 TennixArchive::buildFile(char* filename)
172 size_t offset = 0;
173 size_t *memsize = NULL;
175 memsize = (size_t*)calloc(header.items, sizeof(size_t));
177 fp = fopen(filename, "wb");
178 tnx_assert(fp != NULL);
180 offset += sizeof(TennixArchiveHeader) + header.items*sizeof(TennixArchiveItem);
182 header.versionmajor = TENNIX_ARCHIVE_VERSIONMAJOR;
183 header.versionminor = TENNIX_ARCHIVE_VERSIONMINOR;
185 header.key = (0xaa + 0x77*header.items*3) % 0xff;
187 for (int i=0; i<header.items; i++) {
188 items[i].offset = htonl(offset); /* network byte order */
189 items[i].key = 0xaa ^ ((i<<2)%0x100);
190 xormem(blobs[i], items[i].length, items[i].key);
191 memsize[i] = items[i].length;
192 offset += items[i].length;
193 items[i].length = htonl(items[i].length); /* network byte order */
194 xormem((char*)(items + i), sizeof(TennixArchiveItem), header.key);
197 tnx_assert(fwrite(&(header), sizeof(TennixArchiveHeader), 1, fp) == 1);
198 tnx_assert(fwrite(items, sizeof(TennixArchiveItem), header.items, fp) == header.items);
199 for (int i=0; i<header.items; i++) {
200 tnx_assert(fwrite(blobs[i], memsize[i], 1, fp) == 1);
201 free(blobs[i]);
204 free(memsize);
205 free(blobs);
208 std::ostream&
209 operator<<(std::ostream& out, TennixArchive& archive)
211 out << "Tennix Archive" << std::endl;
212 out << archive.header << std::endl;
214 for (int i=0; i<archive.header.items; i++) {
215 out << "=======================" << std::endl;
216 out << archive.items[i] << std::endl;
218 out << "=== END OF ARCHIVE ====" << std::endl;
220 return out;