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
fileData_isValid(const FileData * data)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
fileData_setValid(FileData * data)36 static inline void fileData_setValid(FileData* data) {
37 data->flags = FILE_DATA_MAGIC;
38 }
39
40
fileData_setInvalid(FileData * data)41 static inline void fileData_setInvalid(FileData* data) {
42 data->flags = (size_t)0xDEADBEEFU;
43 }
44
45
fileData_initWith(FileData * data,const void * buff,size_t size)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
fileData_initEmpty(FileData * data)55 void fileData_initEmpty(FileData* data) {
56 fileData_initWith(data, NULL, 0);
57 }
58
59
fileData_initFromFile(FileData * data,const char * filePath)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
fileData_initFrom(FileData * data,const FileData * other)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
fileData_initFromMemory(FileData * data,const void * input,size_t inputLen)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
fileData_swap(FileData * data,FileData * other)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
fileData_done(FileData * data)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