void LogGuts(VktraceLogLevel level, const char* fmt, va_list args) {
#if defined(WIN32)
    int requiredLength = _vscprintf(fmt, args) + 1;
#elif defined(PLATFORM_LINUX) || defined(PLATFORM_OSX)
    int requiredLength;
    va_list argcopy;
    va_copy(argcopy, args);
    requiredLength = vsnprintf(NULL, 0, fmt, argcopy) + 1;
    va_end(argcopy);
#endif
    static VKTRACE_THREAD_LOCAL BOOL logging = FALSE;

    // Don't recursively log problems found during logging
    if (logging) {
        return;
    }
    logging = TRUE;

    char* message = (char*)vktrace_malloc(requiredLength);
#if defined(WIN32)
    _vsnprintf_s(message, requiredLength, requiredLength - 1, fmt, args);
#elif defined(PLATFORM_LINUX) || defined(PLATFORM_OSX)
    vsnprintf(message, requiredLength, fmt, args);
#endif

    if (s_reportFunc != NULL) {
        s_reportFunc(level, message);
    } else {
#ifdef ANDROID
#include <android/log.h>
        __android_log_print(ANDROID_LOG_INFO, "vktrace", "%s: %s\n", vktrace_LogLevelToString(level), message);
#else
        printf("%s: %s\n", vktrace_LogLevelToString(level), message);
#endif
    }

    vktrace_free(message);
    logging = FALSE;
}
//-----------------------------------------------------------------------------
bool vktraceviewer_QTraceFileLoader::populate_trace_file_info(vktraceviewer_trace_file_info* pTraceFileInfo)
{
    assert(pTraceFileInfo != NULL);
    assert(pTraceFileInfo->pFile != NULL);

    // read trace file header
    if (1 != fread(&(pTraceFileInfo->header), sizeof(vktrace_trace_file_header), 1, pTraceFileInfo->pFile))
    {
        emit OutputMessage(VKTRACE_LOG_ERROR, "Unable to read header from file.");
        return false;
    }

    // Find out how many trace packets there are.

    // Seek to first packet
    long first_offset = pTraceFileInfo->header.first_packet_offset;
    int seekResult = fseek(pTraceFileInfo->pFile, first_offset, SEEK_SET);
    if (seekResult != 0)
    {
        emit OutputMessage(VKTRACE_LOG_WARNING, "Failed to seek to the first packet offset in the trace file.");
    }

    uint64_t fileOffset = pTraceFileInfo->header.first_packet_offset;
    uint64_t packetSize = 0;
    while(1 == fread(&packetSize, sizeof(uint64_t), 1, pTraceFileInfo->pFile))
    {
        // success!
        pTraceFileInfo->packetCount++;
        fileOffset += packetSize;

        fseek(pTraceFileInfo->pFile, fileOffset, SEEK_SET);
    }

    if (pTraceFileInfo->packetCount == 0)
    {
        if (ferror(pTraceFileInfo->pFile) != 0)
        {
            perror("File Read error:");
            emit OutputMessage(VKTRACE_LOG_ERROR, "There was an error reading the trace file.");
            return false;
        }
        else if (feof(pTraceFileInfo->pFile) != 0)
        {
            emit OutputMessage(VKTRACE_LOG_WARNING, "Reached the end of the file.");
        }
        emit OutputMessage(VKTRACE_LOG_WARNING, "There are no trace packets in this trace file.");
        pTraceFileInfo->pPacketOffsets = NULL;
    }
    else
    {
        pTraceFileInfo->pPacketOffsets = VKTRACE_NEW_ARRAY(vktraceviewer_trace_file_packet_offsets, pTraceFileInfo->packetCount);

        // rewind to first packet and this time, populate the packet offsets
        if (fseek(pTraceFileInfo->pFile, first_offset, SEEK_SET) != 0)
        {
            emit OutputMessage(VKTRACE_LOG_ERROR, "Unable to rewind trace file to gather packet offsets.");
            return false;
        }

        unsigned int packetIndex = 0;
        fileOffset = first_offset;
        while(1 == fread(&packetSize, sizeof(uint64_t), 1, pTraceFileInfo->pFile))
        {
            // the fread confirms that this packet exists
            // NOTE: We do not actually read the entire packet into memory right now.
            pTraceFileInfo->pPacketOffsets[packetIndex].fileOffset = fileOffset;

            // rewind slightly
            fseek(pTraceFileInfo->pFile, -1*(long)sizeof(uint64_t), SEEK_CUR);

            // allocate space for the packet and read it in
            pTraceFileInfo->pPacketOffsets[packetIndex].pHeader = (vktrace_trace_packet_header*)vktrace_malloc(packetSize);
            if (1 != fread(pTraceFileInfo->pPacketOffsets[packetIndex].pHeader, packetSize, 1, pTraceFileInfo->pFile))
            {
                emit OutputMessage(VKTRACE_LOG_ERROR, "Unable to read in a trace packet.");
                return false;
            }

            // adjust pointer to body of the packet
            pTraceFileInfo->pPacketOffsets[packetIndex].pHeader->pBody = (uintptr_t)pTraceFileInfo->pPacketOffsets[packetIndex].pHeader + sizeof(vktrace_trace_packet_header);

            // now seek to what should be the next packet
            fileOffset += packetSize;
            packetIndex++;
        }

        if (fseek(pTraceFileInfo->pFile, first_offset, SEEK_SET) != 0)
        {
            emit OutputMessage(VKTRACE_LOG_ERROR, "Unable to rewind trace file to restore position.");
            return false;
        }
    }

    return true;
}