4 * Copyright (C) 2016 Rafał Miłecki <zajec5@gmail.com>
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the Free
8 * Software Foundation; either version 2 of the License, or (at your option)
23 #if !defined(__BYTE_ORDER)
24 #error "Unknown byte order"
27 #if __BYTE_ORDER == __BIG_ENDIAN
28 #define cpu_to_be32(x) (x)
29 #define be32_to_cpu(x) (x)
30 #define cpu_to_be16(x) (x)
31 #define be16_to_cpu(x) (x)
32 #elif __BYTE_ORDER == __LITTLE_ENDIAN
33 #define cpu_to_be32(x) bswap_32(x)
34 #define be32_to_cpu(x) bswap_32(x)
35 #define cpu_to_be16(x) bswap_16(x)
36 #define be16_to_cpu(x) bswap_16(x)
38 #error "Unsupported endianness"
41 #define SEAMA_MAGIC 0x5ea3a417
43 struct seama_seal_header
{
48 } __attribute__ ((packed
));
50 struct seama_entity_header
{
56 } __attribute__ ((packed
));
62 static inline size_t oseama_min(size_t x
, size_t y
) {
66 /**************************************************
68 **************************************************/
70 static void oseama_info_parse_options(int argc
, char **argv
) {
73 while ((c
= getopt(argc
, argv
, "e:")) != -1) {
76 entity_idx
= atoi(optarg
);
82 static int oseama_info_entities(FILE *seama
) {
83 struct seama_entity_header hdr
;
84 size_t bytes
, metasize
, imagesize
;
90 while ((bytes
= fread(&hdr
, 1, sizeof(hdr
), seama
)) == sizeof(hdr
)) {
91 if (be32_to_cpu(hdr
.magic
) != SEAMA_MAGIC
) {
92 fprintf(stderr
, "Invalid Seama magic: 0x%08x\n", be32_to_cpu(hdr
.magic
));
96 metasize
= be16_to_cpu(hdr
.metasize
);
97 imagesize
= be32_to_cpu(hdr
.imagesize
);
99 if (entity_idx
>= 0 && i
!= entity_idx
) {
100 fseek(seama
, metasize
+ imagesize
, SEEK_CUR
);
105 if (metasize
>= sizeof(buf
)) {
106 fprintf(stderr
, "Too small buffer (%zu B) to read all meta info (%zd B)\n", sizeof(buf
), metasize
);
113 printf("Entity offset:\t%ld\n", ftell(seama
) - sizeof(hdr
));
114 printf("Entity size:\t%zd\n", sizeof(hdr
) + metasize
+ imagesize
);
115 printf("Meta size:\t%zd\n", metasize
);
116 printf("Image size:\t%zd\n", imagesize
);
118 bytes
= fread(buf
, 1, metasize
, seama
);
119 if (bytes
!= metasize
) {
120 fprintf(stderr
, "Couldn't read %zd B of meta\n", metasize
);
125 end
= (char *)&buf
[metasize
- 1];
127 for (tmp
= (char *)buf
; tmp
< end
&& strlen(tmp
); tmp
+= strlen(tmp
) + 1) {
128 printf("Meta entry:\t%s\n", tmp
);
131 fseek(seama
, imagesize
, SEEK_CUR
);
139 static int oseama_info(int argc
, char **argv
) {
141 struct seama_seal_header hdr
;
149 fprintf(stderr
, "No Seama file passed\n");
153 seama_path
= argv
[2];
156 oseama_info_parse_options(argc
, argv
);
158 seama
= fopen(seama_path
, "r");
160 fprintf(stderr
, "Couldn't open %s\n", seama_path
);
165 bytes
= fread(&hdr
, 1, sizeof(hdr
), seama
);
166 if (bytes
!= sizeof(hdr
)) {
167 fprintf(stderr
, "Couldn't read %s header\n", seama_path
);
171 metasize
= be16_to_cpu(hdr
.metasize
);
172 imagesize
= be32_to_cpu(hdr
.imagesize
);
174 if (be32_to_cpu(hdr
.magic
) != SEAMA_MAGIC
) {
175 fprintf(stderr
, "Invalid Seama magic: 0x%08x\n", be32_to_cpu(hdr
.magic
));
180 if (metasize
>= sizeof(buf
)) {
181 fprintf(stderr
, "Too small buffer (%zu B) to read all meta info (%d B)\n", sizeof(buf
), metasize
);
187 fprintf(stderr
, "Invalid Seama image size: 0x%08x (should be 0)\n", imagesize
);
192 bytes
= fread(buf
, 1, metasize
, seama
);
193 if (bytes
!= metasize
) {
194 fprintf(stderr
, "Couldn't read %d B of meta\n", metasize
);
199 if (entity_idx
< 0) {
202 printf("Meta size:\t%d\n", metasize
);
203 printf("Image size:\t%d\n", imagesize
);
205 end
= (char *)&buf
[metasize
- 1];
207 for (tmp
= (char *)buf
; tmp
< end
&& strlen(tmp
); tmp
+= strlen(tmp
) + 1) {
208 printf("Meta entry:\t%s\n", tmp
);
212 oseama_info_entities(seama
);
220 /**************************************************
222 **************************************************/
224 static ssize_t
oseama_entity_append_file(FILE *seama
, const char *in_path
) {
230 in
= fopen(in_path
, "r");
232 fprintf(stderr
, "Couldn't open %s\n", in_path
);
236 while ((bytes
= fread(buf
, 1, sizeof(buf
), in
)) > 0) {
237 if (fwrite(buf
, 1, bytes
, seama
) != bytes
) {
238 fprintf(stderr
, "Couldn't write %zu B to %s\n", bytes
, seama_path
);
250 static ssize_t
oseama_entity_append_zeros(FILE *seama
, size_t length
) {
253 buf
= malloc(length
);
256 memset(buf
, 0, length
);
258 if (fwrite(buf
, 1, length
, seama
) != length
) {
259 fprintf(stderr
, "Couldn't write %zu B to %s\n", length
, seama_path
);
266 static ssize_t
oseama_entity_align(FILE *seama
, size_t curr_offset
, size_t alignment
) {
267 if (curr_offset
& (alignment
- 1)) {
268 size_t length
= alignment
- (curr_offset
% alignment
);
270 return oseama_entity_append_zeros(seama
, length
);
276 static int oseama_entity_write_hdr(FILE *seama
, size_t metasize
, size_t imagesize
) {
277 struct seama_entity_header hdr
= {};
279 size_t length
= imagesize
;
283 fseek(seama
, sizeof(hdr
) + metasize
, SEEK_SET
);
285 while ((bytes
= fread(buf
, 1, oseama_min(sizeof(buf
), length
), seama
)) > 0) {
286 MD5_Update(&ctx
, buf
, bytes
);
289 MD5_Final(hdr
.md5
, &ctx
);
291 hdr
.magic
= cpu_to_be32(SEAMA_MAGIC
);
292 hdr
.metasize
= cpu_to_be16(metasize
);
293 hdr
.imagesize
= cpu_to_be32(imagesize
);
295 fseek(seama
, 0, SEEK_SET
);
296 bytes
= fwrite(&hdr
, 1, sizeof(hdr
), seama
);
297 if (bytes
!= sizeof(hdr
)) {
298 fprintf(stderr
, "Couldn't write Seama entity header to %s\n", seama_path
);
305 static int oseama_entity(int argc
, char **argv
) {
308 size_t curr_offset
= sizeof(struct seama_entity_header
);
309 size_t metasize
= 0, imagesize
= 0;
314 fprintf(stderr
, "No Seama file passed\n");
318 seama_path
= argv
[2];
320 seama
= fopen(seama_path
, "w+");
322 fprintf(stderr
, "Couldn't open %s\n", seama_path
);
326 fseek(seama
, curr_offset
, SEEK_SET
);
329 while ((c
= getopt(argc
, argv
, "m:f:b:")) != -1) {
332 sbytes
= fwrite(optarg
, 1, strlen(optarg
) + 1, seama
);
334 fprintf(stderr
, "Failed to write meta %s\n", optarg
);
336 curr_offset
+= sbytes
;
340 sbytes
= oseama_entity_align(seama
, curr_offset
, 4);
342 fprintf(stderr
, "Failed to append zeros\n");
344 curr_offset
+= sbytes
;
356 while ((c
= getopt(argc
, argv
, "m:f:b:")) != -1) {
361 sbytes
= oseama_entity_append_file(seama
, optarg
);
363 fprintf(stderr
, "Failed to append file %s\n", optarg
);
365 curr_offset
+= sbytes
;
370 sbytes
= strtol(optarg
, NULL
, 0) - curr_offset
;
372 fprintf(stderr
, "Current Seama entity length is 0x%zx, can't pad it with zeros to 0x%lx\n", curr_offset
, strtol(optarg
, NULL
, 0));
374 sbytes
= oseama_entity_append_zeros(seama
, sbytes
);
376 fprintf(stderr
, "Failed to append zeros\n");
378 curr_offset
+= sbytes
;
388 oseama_entity_write_hdr(seama
, metasize
, imagesize
);
395 /**************************************************
397 **************************************************/
399 static void oseama_extract_parse_options(int argc
, char **argv
) {
402 while ((c
= getopt(argc
, argv
, "e:o:")) != -1) {
405 entity_idx
= atoi(optarg
);
414 static int oseama_extract_entity(FILE *seama
, FILE *out
) {
415 struct seama_entity_header hdr
;
416 size_t bytes
, metasize
, imagesize
, length
;
421 while ((bytes
= fread(&hdr
, 1, sizeof(hdr
), seama
)) == sizeof(hdr
)) {
422 if (be32_to_cpu(hdr
.magic
) != SEAMA_MAGIC
) {
423 fprintf(stderr
, "Invalid Seama magic: 0x%08x\n", be32_to_cpu(hdr
.magic
));
427 metasize
= be16_to_cpu(hdr
.metasize
);
428 imagesize
= be32_to_cpu(hdr
.imagesize
);
430 if (i
!= entity_idx
) {
431 fseek(seama
, metasize
+ imagesize
, SEEK_CUR
);
436 fseek(seama
, -sizeof(hdr
), SEEK_CUR
);
438 length
= sizeof(hdr
) + metasize
+ imagesize
;
439 while ((bytes
= fread(buf
, 1, oseama_min(sizeof(buf
), length
), seama
)) > 0) {
440 if (fwrite(buf
, 1, bytes
, out
) != bytes
) {
441 fprintf(stderr
, "Couldn't write %zu B to %s\n", bytes
, out_path
);
449 fprintf(stderr
, "Couldn't extract whole entity %d from %s (%zu B left)\n", entity_idx
, seama_path
, length
);
460 static int oseama_extract(int argc
, char **argv
) {
463 struct seama_seal_header hdr
;
469 fprintf(stderr
, "No Seama file passed\n");
473 seama_path
= argv
[2];
476 oseama_extract_parse_options(argc
, argv
);
477 if (entity_idx
< 0) {
478 fprintf(stderr
, "No entity specified\n");
481 } else if (!out_path
) {
482 fprintf(stderr
, "No output file specified\n");
487 seama
= fopen(seama_path
, "r");
489 fprintf(stderr
, "Couldn't open %s\n", seama_path
);
494 out
= fopen(out_path
, "w");
496 fprintf(stderr
, "Couldn't open %s\n", out_path
);
498 goto err_close_seama
;
501 bytes
= fread(&hdr
, 1, sizeof(hdr
), seama
);
502 if (bytes
!= sizeof(hdr
)) {
503 fprintf(stderr
, "Couldn't read %s header\n", seama_path
);
507 metasize
= be16_to_cpu(hdr
.metasize
);
509 fseek(seama
, metasize
, SEEK_CUR
);
511 oseama_extract_entity(seama
, out
);
521 /**************************************************
523 **************************************************/
525 static void usage() {
528 printf("Info about Seama seal (container):\n");
529 printf("\toseama info <file> [options]\n");
530 printf("\t-e\t\t\t\tprint info about specified entity only\n");
532 printf("Create Seama entity:\n");
533 printf("\toseama entity <file> [options]\n");
534 printf("\t-m meta\t\t\t\tmeta into to put in header\n");
535 printf("\t-f file\t\t\t\tappend content from file\n");
536 printf("\t-b offset\t\t\tappend zeros till reaching absolute offset\n");
538 printf("Extract from Seama seal (container):\n");
539 printf("\toseama extract <file> [options]\n");
540 printf("\t-e\t\t\t\tindex of entity to extract\n");
541 printf("\t-o file\t\t\t\toutput file\n");
544 int main(int argc
, char **argv
) {
546 if (!strcmp(argv
[1], "info"))
547 return oseama_info(argc
, argv
);
548 else if (!strcmp(argv
[1], "entity"))
549 return oseama_entity(argc
, argv
);
550 else if (!strcmp(argv
[1], "extract"))
551 return oseama_extract(argc
, argv
);