#include <stdint.h>
#include <string.h>

#include "fs_private.h"

int FS_ReadFile(const char *qpath, void **buffer)
{
    char *contents;
    int32_t handle;
    int32_t isConfig;
    int32_t length;
    int32_t bytesRead;

    FS_CheckFileSystemStarted();

    if (qpath == NULL || *qpath == '\0') {
        Com_Error(0, "\x15" "FS_ReadFile with empty name\n");
    }

    contents = NULL;
    if (strstr(qpath, ".cfg") != NULL) {
        isConfig = 1;
        if (com_journal != NULL && com_journal->integer == 2) {
            Com_DPrintf("Loading %s from journal file.\n", qpath);
            bytesRead =
                FS_Read(&length, (int32_t)sizeof(length),
                        com_journalDataFile);
            if (bytesRead != (int32_t)sizeof(length)) {
                if (buffer != NULL) {
                    *buffer = NULL;
                }
                return -1;
            }
            if (length == 0) {
                if (buffer == NULL) {
                    return 1;
                }
                *buffer = NULL;
                return -1;
            }
            if (buffer == NULL) {
                return length;
            }

            /* ORIGINAL_BINARY_BUG: journal playback rejects zero but accepts
             * a negative dword length; see
             * original-bugs/coduomp-readfile-negative-length.md. */
            contents = Hunk_AllocateTempMemory(
                (size_t)(uint32_t)(length + 1));
            *buffer = contents;
            bytesRead = FS_Read(contents, length, com_journalDataFile);
            if (bytesRead != length) {
                Com_Error(0, "EXE_ERR_JOURNAL_FILE_READ");
            }
            fs_loadCount++;
            contents[length] = '\0';
            return length;
        }
    } else {
        isConfig = 0;
    }

    length = FS_FOpenFileRead(qpath, &handle, 0);
    if (handle == 0) {
        if (buffer != NULL) {
            *buffer = NULL;
        }
        if (isConfig != 0 && com_journal != NULL &&
            com_journal->integer == 1) {
            Com_DPrintf("Writing zero for %s to journal file.\n", qpath);
            length = 0;
            FS_Write(&length, (int32_t)sizeof(length),
                     com_journalDataFile);
            FS_ForceFlush(com_journalDataFile);
        }
        return -1;
    }

    if (buffer == NULL) {
        if (isConfig != 0 && com_journal != NULL &&
            com_journal->integer == 1) {
            Com_DPrintf("Writing len for %s to journal file.\n", qpath);
            FS_Write(&length, (int32_t)sizeof(length),
                     com_journalDataFile);
            FS_ForceFlush(com_journalDataFile);
        }
        FS_FCloseFile(handle);
        return length;
    }

    fs_loadCount++;
    /* ORIGINAL_BINARY_BUG: ordinary file lengths can likewise be negative
     * before allocation, read and terminator indexing; see
     * original-bugs/coduomp-readfile-negative-length.md. */
    contents =
        Hunk_AllocateTempMemory((size_t)(uint32_t)(length + 1));
    *buffer = contents;
    FS_Read(contents, length, handle);
    contents[length] = '\0';
    FS_FCloseFile(handle);

    if (isConfig != 0 && com_journal != NULL && com_journal->integer == 1) {
        Com_DPrintf("Writing %s to journal file.\n", qpath);
        FS_Write(&length, (int32_t)sizeof(length),
                 com_journalDataFile);
        FS_Write(contents, length, com_journalDataFile);
        FS_ForceFlush(com_journalDataFile);
    }

    return length;
}
