Home | History | Annotate | Download | only in utils
      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