4 * Tennix Archive File Format
5 * Copyright (C) 2009-2010 Thomas Perl <thp@thpinfo.com>
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,
33 #include <sys/types.h>
36 #include <arpa/inet.h>
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");
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
);
73 operator<<(std::ostream
& out
, TennixArchiveHeader
& header
)
75 out
<< "Header: " << header
.header
<< std::endl
;
77 (int)header
.versionmajor
<< '.' <<
78 (int)header
.versionminor
<< std::endl
;
79 out
<< "Master key: " << header
.key
<< std::endl
;
80 out
<< "Items: " << header
.items
;
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
;
97 TennixArchive::setItemFilename(const char* filename
)
101 for (i
=0; i
<header
.items
; i
++) {
102 if (strncmp(items
[i
].filename
, filename
, TENNIX_ARCHIVE_ITEM_MAXNAME
) == 0) {
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 */
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
);
125 TennixArchive::xormem(char* mem
, uint32_t length
, char key
)
127 char *i
= mem
, *end
= mem
+length
;
129 for(; i
!= end
; i
++) {
135 TennixArchive::appendItem(char* filename
, char* data
, uint32_t length
)
137 TennixArchiveItem
* item
;
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
;
153 TennixArchive::buildFile(char* filename
)
156 size_t *memsize
= NULL
;
158 memsize
= (size_t*)calloc(header
.items
, sizeof(size_t));
160 fp
= fopen(filename
, "wb");
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
, ", ");
186 fprintf(stderr
, "Writing: %s", filename
);
188 assert(fwrite(&(header
), sizeof(TennixArchiveHeader
), 1, fp
) == 1);
190 assert(fwrite(items
, sizeof(TennixArchiveItem
), header
.items
, fp
) == header
.items
);
192 for (int i
=0; i
<header
.items
; i
++) {
193 assert(fwrite(blobs
[i
], memsize
[i
], 1, fp
) == 1);
197 fprintf(stderr
, "OK\n");
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
;