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,
34 #include <sys/types.h>
37 #include <arpa/inet.h>
42 xormem(char* mem
, uint32_t length
, char key
)
44 char *i
= mem
, *end
= mem
+length
;
45 for(; i
!= end
; i
++) {
50 TennixArchive::TennixArchive()
58 strcpy(header
.header
, TENNIX_ARCHIVE_HEADER
);
62 TennixArchive::TennixArchive(const char* filename
, const char* fallback
)
70 fp
= fopen(filename
, "rb");
71 if (fp
== NULL
&& fallback
!= NULL
) {
72 fp
= fopen(fallback
, "rb");
76 fprintf(stderr
, "Cannot open archive: %s\n", filename
);
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
);
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
;
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
;
125 TennixArchive::setItemFilename(const char* filename
)
129 for (i
=0; i
<header
.items
; i
++) {
130 if (strncmp(items
[i
].filename
, filename
, TENNIX_ARCHIVE_ITEM_MAXNAME
) == 0) {
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 */
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
);
153 TennixArchive::appendItem(char* filename
, char* data
, uint32_t length
)
155 TennixArchiveItem
* item
;
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
;
171 TennixArchive::buildFile(char* filename
)
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);
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
;