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