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>
41 TennixArchive::TennixArchive()
50 strcpy(header
.header
, TENNIX_ARCHIVE_HEADER
);
54 TennixArchive::TennixArchive(const char* filename
, const char* fallback
)
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
);
90 operator<<(std::ostream
& out
, TennixArchiveHeader
& header
)
92 out
<< "Header: " << header
.header
<< std::endl
;
94 (int)header
.versionmajor
<< '.' <<
95 (int)header
.versionminor
<< std::endl
;
96 out
<< "Master key: " << header
.key
<< std::endl
;
97 out
<< "Items: " << header
.items
;
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
;
114 TennixArchive::setItemFilename(const char* filename
)
118 for (i
=0; i
<header
.items
; i
++) {
119 if (strncmp(items
[i
].filename
, filename
, TENNIX_ARCHIVE_ITEM_MAXNAME
) == 0) {
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 */
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
);
142 TennixArchive::xormem(char* mem
, uint32_t length
, char key
)
144 char *i
= mem
, *end
= mem
+length
;
146 for(; i
!= end
; i
++) {
152 TennixArchive::appendItem(char* filename
, char* data
, uint32_t length
)
154 TennixArchiveItem
* item
;
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
;
170 TennixArchive::buildFile(char* filename
)
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);
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
;