/* * RabbitSign - Tools for signing TI graphing calculator software * Copyright (C) 2009 Benjamin Moody * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 3 of the * License, or (at your option) any later version. * * This program 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 * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifdef HAVE_CONFIG_H # include #endif #include #include "rabbitsign.h" #include "internal.h" /* * Get length of a header field. */ void rs_get_field_size (const unsigned char* data, /* Data */ unsigned long* fieldstart, /* Offset to start of field contents */ unsigned long* fieldsize) /* Length of field contents */ { switch (data[1] & 0x0f) { case 0x0D: if (fieldstart) *fieldstart = 3; if (fieldsize) *fieldsize = data[2]; break; case 0x0E: if (fieldstart) *fieldstart = 4; if (fieldsize) *fieldsize = ((data[2] << 8) | data[3]); break; case 0x0F: if (fieldstart) *fieldstart = 6; if (fieldsize) { *fieldsize = (((unsigned long) data[2] << 24) | ((unsigned long) data[3] << 16) | ((unsigned long) data[4] << 8) | (unsigned long) data[5]); } break; default: if (fieldstart) *fieldstart = 2; if (fieldsize) *fieldsize = (data[1] & 0x0f); break; } } /* Set length of a header field. */ int rs_set_field_size (unsigned char* data, unsigned long fieldsize) { switch (data[1] & 0x0f) { case 0x0D: if (fieldsize > 0xff) return -1; data[2] = fieldsize; return 0; case 0x0E: if (fieldsize > 0xfffful) return -1; data[2] = (fieldsize >> 8) & 0xff; data[3] = fieldsize & 0xff; return 0; case 0x0F: if (fieldsize > 0xfffffffful) return -1; data[2] = (fieldsize >> 24) & 0xff; data[3] = (fieldsize >> 16) & 0xff; data[4] = (fieldsize >> 8) & 0xff; data[5] = fieldsize & 0xff; return 0; default: if (fieldsize > 0x0C) return -1; data[1] = (data[1] & 0xf0) | fieldsize; return 0; } } /* * Find a given header field in the data. */ int rs_find_app_field(unsigned int type, /* Type of field to search for (e.g., 0x8040 to search for the name) */ const unsigned char* data, /* Data to search */ unsigned long length, /* Maximum length of data to search */ unsigned long* fieldhead, /* Offset to field type bytes, if found */ unsigned long* fieldstart, /* Offset to start of field contents, if found */ unsigned long* fieldsize) /* Length of field contents, if found */ { unsigned char b1, b2; unsigned long pos = 0; unsigned long fstart, fsize; b1 = ((type >> 8) & 0xff); b2 = (type & 0xf0); while (pos < length) { if (data[pos] == b1 && (data[pos + 1] & 0xf0) == b2) { rs_get_field_size(data + pos, &fstart, fieldsize); if (fieldhead) *fieldhead = pos; if (fieldstart) *fieldstart = pos + fstart; return 0; } rs_get_field_size(data + pos, &fstart, &fsize); pos += fstart + fsize; } return -1; } /* * Get value of a numeric header field. * * Return 0 if field is not found, or if its contents are longer than * 4 bytes. */ unsigned long rs_get_numeric_field (unsigned int type, const unsigned char* data, unsigned long length) { unsigned long fstart, fsize, value; if (rs_find_app_field(type, data, length, NULL, &fstart, &fsize)) return 0; if (fsize > 4) return 0; value = 0; while (fsize > 0) { value <<= 8; value |= data[fstart]; fstart++; fsize--; } return value; }