summaryrefslogtreecommitdiffstats
path: root/src/img4.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/img4.c')
-rw-r--r--src/img4.c140
1 files changed, 140 insertions, 0 deletions
diff --git a/src/img4.c b/src/img4.c
new file mode 100644
index 0000000..e18b419
--- /dev/null
+++ b/src/img4.c
@@ -0,0 +1,140 @@
+/*
+ * img4.c
+ * Functions for handling the new IMG4 format
+ *
+ * Copyright (c) 2013 Nikias Bassen. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "img4.h"
+
+#define ASN1_CONSTRUCTED 0x20
+#define ASN1_SEQUENCE 0x10
+#define ASN1_CONTEXT_SPECIFIC 0x80
+#define ASN1_IA5_STRING 0x16
+
+#define IMG4_MAGIC "IMG4"
+#define IMG4_MAGIC_SIZE 4
+
+static unsigned char* asn1_create_element_header(unsigned char type, unsigned int size, unsigned char** data, unsigned int *data_size)
+{
+ unsigned char buf[5];
+ unsigned int off = 0;
+
+ if (!type || size == 0 || !data || !data_size) {
+ return NULL;
+ }
+
+ buf[off++] = type;
+
+ // first, calculate the size
+ if (size >= 0x1000000) {
+ // 1+4 bytes length
+ buf[off++] = 0x84;
+ buf[off++] = (size >> 24) & 0xFF;
+ buf[off++] = (size >> 16) & 0xFF;
+ buf[off++] = (size >> 8) & 0xFF;
+ buf[off++] = size & 0xFF;
+ } else if (size >= 0x10000) {
+ // 1+3 bytes length
+ buf[off++] = 0x83;
+ buf[off++] = (size >> 16) & 0xFF;
+ buf[off++] = (size >> 8) & 0xFF;
+ buf[off++] = size & 0xFF;
+ } else if (size >= 0x100) {
+ // 1+2 bytes length
+ buf[off++] = 0x82;
+ buf[off++] = (size >> 8) & 0xFF;
+ buf[off++] = (size & 0xFF);
+ } else if (size >= 0x80) {
+ // 1+1 byte length
+ buf[off++] = 0x81;
+ buf[off++] = (size & 0xFF);
+ } else {
+ // 1 byte length
+ buf[off++] = size & 0xFF;
+ }
+
+ *data = malloc(off);
+ memcpy(*data, buf, off);
+ *data_size = off;
+
+ return *data;
+}
+
+int img4_stitch_component(const char* component_name, const unsigned char* component_data, unsigned int component_size, const unsigned char* blob, unsigned int blob_size, unsigned char** img4_data, unsigned int *img4_size)
+{
+ unsigned char* magic_header = NULL;
+ unsigned int magic_header_size = 0;
+ unsigned char* blob_header = NULL;
+ unsigned int blob_header_size = 0;
+ unsigned char* img4header = NULL;
+ unsigned int img4header_size = 0;
+ unsigned int content_size;
+ unsigned char* outbuf;
+ unsigned char* p;
+
+ if (!component_name || !component_data || component_size == 0 || !blob || blob_size == 0 || !img4_data || !img4_size) {
+ return -1;
+ }
+
+ /* first we need check if we have to change the tag for the given component */
+ // FIXME: write proper ASN1 handling code for this
+ if (strcmp(component_name, "RestoreKernelCache") == 0) {
+ memcpy((char*)component_data+0xD, "rkrn", 4);
+ } else if (strcmp(component_name, "RestoreDeviceTree") == 0) {
+ memcpy((char*)component_data+0xD, "rdtr", 4);
+ }
+
+ // create element header for the "IMG4" magic
+ asn1_create_element_header(ASN1_IA5_STRING, IMG4_MAGIC_SIZE, &magic_header, &magic_header_size);
+ // create element header for the blob (ApImg4Ticket)
+ asn1_create_element_header(ASN1_CONTEXT_SPECIFIC|ASN1_CONSTRUCTED, blob_size, &blob_header, &blob_header_size);
+
+ // calculate the size for the final IMG4 file (asn1 sequence)
+ content_size = magic_header_size + IMG4_MAGIC_SIZE + component_size + blob_header_size + blob_size;
+
+ // create element header for the final IMG4 asn1 blob
+ asn1_create_element_header(ASN1_SEQUENCE|ASN1_CONSTRUCTED, content_size, &img4header, &img4header_size);
+
+ outbuf = (unsigned char*)malloc(img4header_size + content_size);
+ if (!outbuf) {
+ return -1;
+ }
+ p = outbuf;
+
+ // now put everything together
+ memcpy(p, img4header, img4header_size);
+ p += img4header_size;
+ memcpy(p, magic_header, magic_header_size);
+ p += magic_header_size;
+ memcpy(p, IMG4_MAGIC, IMG4_MAGIC_SIZE);
+ p += IMG4_MAGIC_SIZE;
+ memcpy(p, component_data, component_size);
+ p += component_size;
+ memcpy(p, blob_header, blob_header_size);
+ p += blob_header_size;
+ memcpy(p, blob, blob_size);
+ p += blob_size;
+
+ *img4_data = outbuf;
+ *img4_size = (p - outbuf);
+
+ return 0;
+}