15ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner// Copyright 2014 The Android Open Source Project 25ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner// 35ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner// This software is licensed under the terms of the GNU General Public 45ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner// License version 2, as published by the Free Software Foundation, and 55ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner// may be copied, distributed, and modified under those terms. 65ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner// 75ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner// This program is distributed in the hope that it will be useful, 85ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner// but WITHOUT ANY WARRANTY; without even the implied warranty of 95ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 105ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner// GNU General Public License for more details. 115ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner 125ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner#include "android/utils/file_data.h" 135ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner 145ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner#include "android/utils/panic.h" 155ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner 165ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner#include <errno.h> 175ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner#include <stdio.h> 185ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner#include <stdlib.h> 195ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner#include <string.h> 205ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner 215ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner// Use a magic value in the |flags| field to indicate that a FileData 225ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner// value was properly initialized. Helps catch errors at runtime. 235ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner#define FILE_DATA_MAGIC ((size_t)0x87002013U) 245ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner 255ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner 265ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turnerbool fileData_isValid(const FileData* data) { 275ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner if (!data) 285ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner return false; 295ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner if (data->flags == FILE_DATA_MAGIC) 305ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner return true; 315ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner if (data->flags == 0 && data->data == NULL && data->size == 0) 325ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner return true; 335ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner return false; 345ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner} 355ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner 365ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turnerstatic inline void fileData_setValid(FileData* data) { 375ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner data->flags = FILE_DATA_MAGIC; 385ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner} 395ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner 405ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner 415ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turnerstatic inline void fileData_setInvalid(FileData* data) { 425ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner data->flags = (size_t)0xDEADBEEFU; 435ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner} 445ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner 455ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner 465ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turnerstatic void fileData_initWith(FileData* data, 475ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner const void* buff, 485ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner size_t size) { 495ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner data->data = size ? (uint8_t*)buff : NULL; 505ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner data->size = size; 515ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner fileData_setValid(data); 525ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner} 535ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner 545ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner 555ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turnervoid fileData_initEmpty(FileData* data) { 565ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner fileData_initWith(data, NULL, 0); 575ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner} 585ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner 595ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner 605ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turnerint fileData_initFromFile(FileData* data, const char* filePath) { 615ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner FILE* f = fopen(filePath, "rb"); 625ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner if (!f) 635ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner return -errno; 64c005246ed03de874fdc432073ba8e5e8ebfed922David 'Digit' Turner 655ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner int ret = 0; 665ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner do { 675ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner if (fseek(f, 0, SEEK_END) < 0) { 685ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner ret = -errno; 695ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner break; 705ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner } 71c005246ed03de874fdc432073ba8e5e8ebfed922David 'Digit' Turner 725ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner long fileSize = ftell(f); 735ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner if (fileSize < 0) { 745ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner ret = -errno; 755ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner break; 765ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner } 77c005246ed03de874fdc432073ba8e5e8ebfed922David 'Digit' Turner 785ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner if (fileSize == 0) { 795ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner fileData_initEmpty(data); 805ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner break; 815ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner } 825ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner 835ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner if (fseek(f, 0, SEEK_SET) < 0) { 845ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner ret = -errno; 855ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner break; 865ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner } 87c005246ed03de874fdc432073ba8e5e8ebfed922David 'Digit' Turner 885ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner char* buffer = malloc((size_t)fileSize); 895ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner if (!buffer) { 905ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner ret = -errno; 915ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner break; 925ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner } 93c005246ed03de874fdc432073ba8e5e8ebfed922David 'Digit' Turner 945ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner size_t readLen = fread(buffer, 1, (size_t)fileSize, f); 955ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner if (readLen != (size_t)fileSize) { 965ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner if (feof(f)) { 975ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner ret = -EIO; 985ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner } else { 995ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner ret = -ferror(f); 1005ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner } 1015ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner break; 1025ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner } 103c005246ed03de874fdc432073ba8e5e8ebfed922David 'Digit' Turner 1045ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner fileData_initWith(data, buffer, readLen); 1055ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner 1065ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner } while (0); 107c005246ed03de874fdc432073ba8e5e8ebfed922David 'Digit' Turner 1085ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner fclose(f); 1095ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner return ret; 1105ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner} 1115ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner 1125ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner 1135ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turnerint fileData_initFrom(FileData* data, const FileData* other) { 1145ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner if (!other || !fileData_isValid(other)) { 1155ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner APANIC("Trying to copy an uninitialized FileData instance\n"); 1165ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner } 1175ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner if (other->size == 0) { 1185ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner fileData_initEmpty(data); 1195ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner return 0; 1205ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner } 1215ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner void* copy = malloc(other->size); 1225ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner if (!copy) { 1235ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner return -errno; 1245ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner } 125c005246ed03de874fdc432073ba8e5e8ebfed922David 'Digit' Turner 1265ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner memcpy(copy, other->data, other->size); 1275ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner fileData_initWith(data, copy, other->size); 1285ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner return 0; 1295ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner} 130c005246ed03de874fdc432073ba8e5e8ebfed922David 'Digit' Turner 1315ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner 1325ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turnerint fileData_initFromMemory(FileData* data, 1335ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner const void* input, 1345ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner size_t inputLen) { 1355ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner FileData other; 1365ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner fileData_initWith(&other, input, inputLen); 137d3f2c27ff9f611e5047a35cb20ed53f548214fedDavid 'Digit' Turner memset(data, 0, sizeof(*data)); // make valgrind happy. 1385ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner return fileData_initFrom(data, &other); 1395ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner} 1405ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner 1415ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner 1425ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turnervoid fileData_swap(FileData* data, FileData* other) { 1435ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner if (!fileData_isValid(data) || !fileData_isValid(data)) 1445ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner APANIC("Trying to swap un-initialized FileData instance\n"); 1455ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner 1465ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner uint8_t* buffer = data->data; 1475ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner data->data = other->data; 1485ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner other->data = buffer; 149c005246ed03de874fdc432073ba8e5e8ebfed922David 'Digit' Turner 1505ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner size_t size = data->size; 1515ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner data->size = other->size; 1525ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner other->size = size; 1535ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner} 1545ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner 1555ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner 1565ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turnervoid fileData_done(FileData* data) { 1575ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner if (!fileData_isValid(data)) { 1585ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner APANIC("Trying to finalize an un-initialized FileData instance\n"); 1595ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner } 160c005246ed03de874fdc432073ba8e5e8ebfed922David 'Digit' Turner 1615ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner free(data->data); 1625ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner fileData_initWith(data, NULL, 0); 1635ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner fileData_setInvalid(data); 1645ea914899e5dbef4e8a7454b40a3c6648173f086David 'Digit' Turner} 165