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 26 bool 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 36 static inline void fileData_setValid(FileData* data) { 37 data->flags = FILE_DATA_MAGIC; 38 } 39 40 41 static inline void fileData_setInvalid(FileData* data) { 42 data->flags = (size_t)0xDEADBEEFU; 43 } 44 45 46 static 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 55 void fileData_initEmpty(FileData* data) { 56 fileData_initWith(data, NULL, 0); 57 } 58 59 60 int 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 113 int 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 132 int 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 142 void 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 156 void 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