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);