1// Copyright 2014 The Android Open Source Project 2// 3// This software is licensed under the terms of the GNU General Public 4// License version 2, as published by the Free Software Foundation, and 5// may be copied, distributed, and modified under those terms. 6// 7// This program is distributed in the hope that it will be useful, 8// but WITHOUT ANY WARRANTY; without even the implied warranty of 9// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10// GNU General Public License for more details. 11 12#include "android/utils/file_data.h" 13 14#include "android/utils/panic.h" 15 16#include <errno.h> 17#include <stdio.h> 18#include <stdlib.h> 19#include <string.h> 20 21// Use a magic value in the |flags| field to indicate that a FileData 22// value was properly initialized. Helps catch errors at runtime. 23#define FILE_DATA_MAGIC ((size_t)0x87002013U) 24 25 26bool fileData_isValid(const FileData* data) { 27 if (!data) 28 return false; 29 if (data->flags == FILE_DATA_MAGIC) 30 return true; 31 if (data->flags == 0 && data->data == NULL && data->size == 0) 32 return true; 33 return false; 34} 35 36static inline void fileData_setValid(FileData* data) { 37 data->flags = FILE_DATA_MAGIC; 38} 39 40 41static inline void fileData_setInvalid(FileData* data) { 42 data->flags = (size_t)0xDEADBEEFU; 43} 44 45 46static void fileData_initWith(FileData* data, 47 const void* buff, 48 size_t size) { 49 data->data = size ? (uint8_t*)buff : NULL; 50 data->size = size; 51 fileData_setValid(data); 52} 53 54 55void fileData_initEmpty(FileData* data) { 56 fileData_initWith(data, NULL, 0); 57} 58 59 60int fileData_initFromFile(FileData* data, const char* filePath) { 61 FILE* f = fopen(filePath, "rb"); 62 if (!f) 63 return -errno; 64 65 int ret = 0; 66 do { 67 if (fseek(f, 0, SEEK_END) < 0) { 68 ret = -errno; 69 break; 70 } 71 72 long fileSize = ftell(f); 73 if (fileSize < 0) { 74 ret = -errno; 75 break; 76 } 77 78 if (fileSize == 0) { 79 fileData_initEmpty(data); 80 break; 81 } 82 83 if (fseek(f, 0, SEEK_SET) < 0) { 84 ret = -errno; 85 break; 86 } 87 88 char* buffer = malloc((size_t)fileSize); 89 if (!buffer) { 90 ret = -errno; 91 break; 92 } 93 94 size_t readLen = fread(buffer, 1, (size_t)fileSize, f); 95 if (readLen != (size_t)fileSize) { 96 if (feof(f)) { 97 ret = -EIO; 98 } else { 99 ret = -ferror(f); 100 } 101 break; 102 } 103 104 fileData_initWith(data, buffer, readLen); 105 106 } while (0); 107 108 fclose(f); 109 return ret; 110} 111 112 113int fileData_initFrom(FileData* data, const FileData* other) { 114 if (!other || !fileData_isValid(other)) { 115 APANIC("Trying to copy an uninitialized FileData instance\n"); 116 } 117 if (other->size == 0) { 118 fileData_initEmpty(data); 119 return 0; 120 } 121 void* copy = malloc(other->size); 122 if (!copy) { 123 return -errno; 124 } 125 126 memcpy(copy, other->data, other->size); 127 fileData_initWith(data, copy, other->size); 128 return 0; 129} 130 131 132int fileData_initFromMemory(FileData* data, 133 const void* input, 134 size_t inputLen) { 135 FileData other; 136 fileData_initWith(&other, input, inputLen); 137 memset(data, 0, sizeof(*data)); // make valgrind happy. 138 return fileData_initFrom(data, &other); 139} 140 141 142void fileData_swap(FileData* data, FileData* other) { 143 if (!fileData_isValid(data) || !fileData_isValid(data)) 144 APANIC("Trying to swap un-initialized FileData instance\n"); 145 146 uint8_t* buffer = data->data; 147 data->data = other->data; 148 other->data = buffer; 149 150 size_t size = data->size; 151 data->size = other->size; 152 other->size = size; 153} 154 155 156void fileData_done(FileData* data) { 157 if (!fileData_isValid(data)) { 158 APANIC("Trying to finalize an un-initialized FileData instance\n"); 159 } 160 161 free(data->data); 162 fileData_initWith(data, NULL, 0); 163 fileData_setInvalid(data); 164} 165