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

#include "../filesystem/fs_private.h"
#include "core_runtime_private.h"

#define COM_CDKEY_FILE "cdkey"
#define COM_CDKEY_DEFAULT "                "
#define COM_CDKEY_TEXT_BYTES 16
#define COM_CDKEY_HASH_BYTES 4
#define COM_CDKEY_FILE_BYTES 21

char com_cdkey[COM_CDKEY_TEXT_BYTES + 1] = "123456789";
char com_cdkeyHash[COM_CDKEY_HASH_BYTES + 1];

void Com_ResetCDKey(void)
{
    strcpy(com_cdkey, COM_CDKEY_DEFAULT);
}

void Com_ReadCDKey(void)
{
    void *fileBuffer;
    int32_t fileLength;
    uint8_t localBuffer[COM_CDKEY_FILE_BYTES];

    fileLength = FS_ReadFile(COM_CDKEY_FILE, NULL);
    /* ORIGINAL_BINARY_BUG: every normal nonempty second read allocates a temp
     * buffer, returns its nonzero length, is rejected here, and is never freed;
     * preserved per original-bugs/engine-cdkey-double-read-buffer-mismatch.md. */
    if (FS_ReadFile(COM_CDKEY_FILE, &fileBuffer) != 0) {
        Com_ResetCDKey();
        return;
    }

    /* ORIGINAL_BINARY_BUG: this copies the first read's length from the second
     * read's buffer before checking 21, so a file-state change can over-read the
     * new allocation and overwrite this stack buffer; see the report above. */
    /* The i386 memcpy size argument is the raw dword returned by FS_ReadFile.
     * Preserve that zero-extended width on hosts whose size_t is wider. */
    memcpy(localBuffer, fileBuffer, (size_t)(uint32_t)fileLength);
    if (fileLength != COM_CDKEY_FILE_BYTES) {
        Com_ResetCDKey();
        return;
    }

    memcpy(com_cdkey, localBuffer, COM_CDKEY_TEXT_BYTES);
    com_cdkey[COM_CDKEY_TEXT_BYTES] = '\0';
    memcpy(com_cdkeyHash, &localBuffer[COM_CDKEY_TEXT_BYTES],
           COM_CDKEY_HASH_BYTES);
    com_cdkeyHash[COM_CDKEY_HASH_BYTES] = '\0';

    if (CL_CDKeyValidate(com_cdkey, com_cdkeyHash) == qfalse) {
        Com_ResetCDKey();
    }
}
