////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
// All rights reserved.
// Confidential and Proprietary - Qualcomm Technologies, Inc.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// THIS IS AUTO-GENERATED CODE.  PLEASE DO NOT EDIT (File bug reports against tools).
///
/// Auto-generated by: Parameter Parser V7.4.1 (8cca6579792b9fcef3bc725ff070c5ec453c7c85)
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @file  parameterfilesymboltable.cpp
/// @brief Auto-generated Chromatix parameter file
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#include "parameterfilesymboltable.h"
#include "parametersetmanager.h"

ParameterFileSymbolTable::ParameterFileSymbolTable(
    ParameterSetManager* const setManager,
    BYTE                       alignment,
    const VersionUnion&        version)
{
    m_count         = 0;
    m_dtCount       = 0;
    m_dupCount      = 0;
    m_dtDupCount    = 0;
    m_fileRef       = 0;
    m_entryLookup   = nullptr;
    m_dtEntryLookup = nullptr;
    m_dupEntries    = nullptr;
    m_dtDupEntries  = nullptr;
    m_entries       = nullptr;
    m_dtEntries     = nullptr;
    SetManager      = setManager;
    Version.Value   = version.Value;
    MultiModeTableVersion.Version.Major = ParameterSetManager::MULTI_MODE_TABLE_MAJOR;
    MultiModeTableVersion.Version.Minor = ParameterSetManager::MULTI_MODE_TABLE_MINOR;
    MultiModeTableVersion.Version.Patch = ParameterSetManager::MULTI_MODE_TABLE_PATCH;
    StructSymbolsVersion.Version.Major  = ParameterSetManager::STRUCT_SYMBOLS_MAJOR;
    StructSymbolsVersion.Version.Minor  = ParameterSetManager::STRUCT_SYMBOLS_MINOR;
    StructSymbolsVersion.Version.Patch  = ParameterSetManager::STRUCT_SYMBOLS_PATCH;
    DataTableVersion.Version.Major      = ParameterSetManager::DATA_TABLE_MAJOR;
    DataTableVersion.Version.Minor      = ParameterSetManager::DATA_TABLE_MINOR;
    DataTableVersion.Version.Patch      = ParameterSetManager::DATA_TABLE_PATCH;
    AlignedEndVersion.Version.Major     = ParameterSetManager::ALIGNED_END_MAJOR;
    AlignedEndVersion.Version.Minor     = ParameterSetManager::ALIGNED_END_MINOR;
    AlignedEndVersion.Version.Patch     = ParameterSetManager::ALIGNED_END_PATCH;
    LinkVersion.Version.Major           = ParameterSetManager::LINK_MAJOR;
    LinkVersion.Version.Minor           = ParameterSetManager::LINK_MINOR;
    LinkVersion.Version.Patch           = ParameterSetManager::LINK_PATCH;
    ModeFlagsVersion.Version.Major      = ParameterSetManager::MODE_FLAGS_MAJOR;
    ModeFlagsVersion.Version.Minor      = ParameterSetManager::MODE_FLAGS_MINOR;
    ModeFlagsVersion.Version.Patch      = ParameterSetManager::MODE_FLAGS_PATCH;
    FileName             = nullptr;
    File                 = nullptr;
    FileLength           = 0;
    SymbolTableOffset    = 0;
    SymbolTableSize      = 0;
    DataTableOffset      = 0;
    DataTableSize        = 0;
    DataOffset           = 0;
    DataSize             = 0;
    Data                 = nullptr;
    ModeTable            = 0;
    Alignment            = alignment;
    ModuleDefinitions    = nullptr;
    StructureDefinitions = nullptr;
}

ParameterFileSymbolTable::~ParameterFileSymbolTable()
{
    if (m_dtEntries != nullptr && m_dtEntries != m_entries)
    {
        PARAMETER_DELETE[] m_dtEntries;
    }

    if (m_entries != nullptr)
    {
        PARAMETER_DELETE[] m_entries;
    }

    if (m_dupEntries != nullptr)
    {
        for (UINT32 i = 0; i < m_dupCount; i++)
        {
            while (m_dupEntries[i].Count() > 0)
            {
                const UINT32 index = m_dupEntries[i].Count() - 1;
                PARAMETER_DELETE m_dupEntries[i][index];
                m_dupEntries[i].RemoveAt(index);
            }
        }
        PARAMETER_DELETE[] m_dupEntries;
    }

    if (m_dtDupEntries != nullptr)
    {
        for (UINT32 i = 0; i < m_dtDupCount; i++)
        {
            while (m_dtDupEntries[i].Count() > 0)
            {
                UINT32 const index = m_dtDupEntries[i].Count() - 1;
                PARAMETER_DELETE m_dtDupEntries[i][index];
                m_dtDupEntries[i].RemoveAt(index);
            }
        }
        PARAMETER_DELETE[] m_dtDupEntries;
    }

    if (m_dtEntryLookup != nullptr && m_dtEntryLookup != m_entryLookup)
    {
        PARAMETER_DELETE[] m_dtEntryLookup;
    }

    if (m_entryLookup != nullptr)
    {
        PARAMETER_DELETE[] m_entryLookup;
    }

    for (UINT32 i = 0; i < m_modules.Count(); i++)
    {
        PARAMETER_DELETE m_modules[i];
    }

    if (m_dupInfoMap.size() > 0)
    {
        PARAMETER_LOG_ERROR(SetManager, "%d DupInfo object were not released\n", m_dupInfoMap.size());
    }

    ClearDefinitions(true);

    PARAMETER_DELETE File;
}

void ParameterFileSymbolTable::ClearDefinitions(
   bool all)
{
    if (all)
    {
        // Remove all elements
        if (ModuleDefinitions != nullptr)
        {
            std::unordered_map<UINT64, ParameterDefinitionModule*>::iterator modIter = ModuleDefinitions->begin();
            while (modIter != ModuleDefinitions->end())
            {
                PARAMETER_DELETE modIter->second;
                modIter++;
            }
            ModuleDefinitions->clear();
        }

        if (StructureDefinitions != nullptr)
        {
            std::unordered_map<UINT32, ParameterDefinitionStructure*>::iterator structIter = StructureDefinitions->begin();
            while (structIter != StructureDefinitions->end())
            {
                PARAMETER_DELETE structIter->second;
                structIter++;
            }
            StructureDefinitions->clear();
        }
    }
    else
    {
        // Remove only verified elements

        // List of structures that need to be kept
        std::unordered_map<UINT32, ParameterDefinitionStructure*> keeping;

        if (StructureDefinitions != nullptr)
        {
            // Remove verified elements from all structures
            std::unordered_map<UINT32, ParameterDefinitionStructure*>::iterator structIter = StructureDefinitions->begin();
            while (structIter != StructureDefinitions->end())
            {
                ParameterDefinitionStructure* structure = structIter->second;
                if (structure->Children != nullptr)
                {
                    std::unordered_map<UINT64, ParameterDefinitionElement*>::iterator childIter = structure->Children->begin();
                    bool keep = false;
                    while (childIter != structure->Children->end())
                    {
                        PList<UINT32> structuresChecked;
                        ParameterDefinitionElement* element = childIter->second;
                        if (element->IsStructVerified(structuresChecked))
                        {
                            PARAMETER_DELETE childIter->second->Info;
                            childIter->second->Info = nullptr;
                        }
                        else
                        {
                            if (element->Info != nullptr && element->Info->Structure != nullptr)
                            {
                                keeping[element->Info->Structure->StructureID] = element->Info->Structure;
                            }
                            keep = true;
                        }
                        childIter++;
                    }

                    if (keep)
                    {
                        keeping[structure->StructureID] = structure;
                    }
                }

                structIter++;
            }

            // Remove all structures that are not kept
            structIter = StructureDefinitions->begin();
            while (structIter != StructureDefinitions->end())
            {
                ParameterDefinitionStructure* structure = structIter->second;
                std::unordered_map<UINT32, ParameterDefinitionStructure*>::iterator unverIter = keeping.find(structure->StructureID);
                if (unverIter == keeping.end())
                {
                    // This is a verified structure, delete it and all remaining elements, and remove it
                    std::unordered_map<UINT64, ParameterDefinitionElement*>::iterator childIter = structure->Children->begin();
                    while (childIter != structure->Children->end())
                    {
                        PARAMETER_DELETE childIter->second;
                        childIter = structure->Children->erase(childIter);
                    }

                    structure->Children->clear();
                    PARAMETER_DELETE structIter->second;
                    structIter = StructureDefinitions->erase(structIter);
                }
                else
                {
                    structIter++;
                }
            }

            // Remove all modules that are verified
            std::unordered_map<UINT64, ParameterDefinitionModule*>::iterator modIter = ModuleDefinitions->begin();
            while (modIter != ModuleDefinitions->end())
            {
                std::unordered_map<UINT32, ParameterDefinitionStructure*>::iterator verIter = keeping.find(modIter->second->StructureID);
                if (verIter == keeping.end())
                {
                    // This module points to a verified structure, remove the module
                    PARAMETER_DELETE modIter->second;
                    modIter = ModuleDefinitions->erase(modIter);
                }
                else
                {
                    modIter++;
                }
            }

            keeping.clear();
        }
    }

    if (ModuleDefinitions != nullptr && ModuleDefinitions->empty())
    {
        PARAMETER_DELETE ModuleDefinitions;
        ModuleDefinitions = nullptr;
    }

    if (StructureDefinitions != nullptr && StructureDefinitions->empty())
    {
        PARAMETER_DELETE StructureDefinitions;
        StructureDefinitions = nullptr;
    }
}

bool ParameterFileSymbolTable::ReadTable(
    BYTE* const                    buffer,
    UINT32 const                   length,
    UINT32&                        pos,
    UINT32                         count,
    ParameterFileSymbolTableEntry* entries,
    EntryData* const               entryLookup,
    UINT32&                        dupCount,
    PList<DupObjInfo*>*&           dupEntries,
    UINT32 const                   dataOffset,
    IModeTable* const              modeTable,
    const bool                     isModule)
{
    UINT32  offset     = Version < StructSymbolsVersion ? 1 : 0;
    UINT32* duplicates = PARAMETER_NEW UINT32[count + offset];
    bool    valid      = true;

    if (duplicates != nullptr)
    {
        PARAMETER_MEMSET(duplicates, 0, sizeof(UINT32) * (count + offset));
        PARAMETER_INITIALIZE(entries[0]); // entry 0 is unused, so clear it

        for (UINT32 i = offset; valid && i < count + offset; i++)
        {
            UINT32 id    = i;
            UINT32 idPos = pos;
            if (Version < StructSymbolsVersion)
            {
                valid = ParameterUtils::Read(&id, buffer, length, idPos, Alignment, SetManager);
            }
            if (valid && (i == 0 || id > 0) && id < count + offset)
            {
                entryLookup[id].Position = pos;
                entries[id].Init(this);
                valid = entries[id].Load(buffer, nullptr, nullptr, length, pos, dataOffset, modeTable, isModule, id);
                if (valid && duplicates != nullptr)
                {
                    const UINT32 dup = entries[id].DuplicateID;
                    duplicates[dup]++;         // Count the duplicates
                    entryLookup[id].Dup = dup; // Make duplicate entries point to self/duplicate
                }
            }
            else if (!valid)
            {
                PARAMETER_LOG_ERROR(SetManager, "Failed to read entry ID from Symbol table\n");
            }
            else
            {
                PARAMETER_LOG_ERROR(SetManager, "Symbol table entry ID %d out of range 1 - %d\n", id, count);
            }
        }

        // Do not use entry 0 in m_dupEntries as that value is used to represent no duplicates
        dupCount = 1;
        // Build the total number of m_dupEntries needed, change duplicates to point to the m_dupEntries index,
        // or zero if not a duplicate
        for (UINT32 i = 1; valid && duplicates != nullptr && i < count + offset; i++)
        {
            if (duplicates[i] > 1)
            {
                duplicates[i] = dupCount++;
            }
            else
            {
                duplicates[i] = 0;
            }
        }

        // After re-building the duplicates array, update entryLookup to point to the m_dupEntries index, 
        // or zero if no duplicate
        for (UINT32 i = 1; valid && duplicates != nullptr && i < count + offset; i++)
        {
            if (entryLookup[i].Dup > 0)
            {
                entryLookup[i].Dup = duplicates[entryLookup[i].Dup];
            }
        }

        PARAMETER_DELETE[] duplicates;
        duplicates = nullptr;

        // If there are duplicates, build m_dupEntries
        if (dupCount > 1)
        {
            dupEntries = PARAMETER_NEW PList<DupObjInfo*>[dupCount];
        }

        for (UINT32 i = 1; valid && i < count + offset; i++)
        {
            if (entries[i].IsModule())
            {
                m_modules.Add(entries[i].Module);
                entries[i].Module = nullptr;
            }
        }
    }
    else
    {
        PARAMETER_LOG_ERROR(SetManager, "Failed to allocate space for duplicates variable\n");
    }

    return valid;
}

bool ParameterFileSymbolTable::ReadDefinitions(
    BYTE* const  buffer,
    UINT32 const length,
    UINT32&      pos,
    UINT32       size,
    bool const   fbcEnabled)
{
    bool result = pos + size <= length;

    if (result)
    {
        ModuleDefinitions    = PARAMETER_NEW std::unordered_map<UINT64, ParameterDefinitionModule*>;
        StructureDefinitions = PARAMETER_NEW std::unordered_map<UINT32, ParameterDefinitionStructure*>;

        if (ModuleDefinitions != nullptr && StructureDefinitions != nullptr)
        {
            UINT32 start = pos;
            do
            {
                BYTE   type     = 0;
                UINT32 strCount = 0;

                result = ParameterUtils::Read(&type, buffer, length, pos, Alignment, SetManager);
                switch (type)
                {
                case (BYTE)ParameterDefinitionType::ParameterDefinitionType_ScenarioMode:
                {
                    // skip mode
                    pos += sizeof(BYTE);
                    // Read name size
                    result = result && ParameterUtils::Read(&strCount, buffer, length, pos, Alignment, SetManager);
                    // skip mode name and the IsValueEnum byte
                    pos += strCount + sizeof(BYTE);
                    break;
                }
                case (BYTE)ParameterDefinitionType::ParameterDefinitionType_ScenarioSubMode:
                {
                    // skip mode and sub mode
                    pos += sizeof(BYTE) + sizeof(UINT16);
                    // Read sub mode name size
                    result = result && ParameterUtils::Read(&strCount, buffer, length, pos, Alignment, SetManager);
                    // skip sub mode name and the IsValueEnum byte
                    pos += strCount + sizeof(BYTE);
                    break;
                }
                case (BYTE)ParameterDefinitionType::ParameterDefinitionType_Pipeline:
                {
                    // skip pipeline value
                    pos += sizeof(UINT16);
                    // Read pipeline name size
                    result = result && ParameterUtils::Read(&strCount, buffer, length, pos, Alignment, SetManager);
                    // skip pipeline name
                    pos += strCount;
                    // Read value string size
                    result = result && ParameterUtils::Read(&strCount, buffer, length, pos, Alignment, SetManager);
                    // skip value string
                    pos += strCount;
                    break;
                }
                case (BYTE)ParameterDefinitionType::ParameterDefinitionType_Module:
                {
                    if (fbcEnabled)
                    {
                        ParameterDefinitionModule* mod = PARAMETER_NEW ParameterDefinitionModule(buffer, length, pos, Alignment, SetManager);

                        if (mod != nullptr)
                        {
                            std::unordered_map<UINT64, ParameterDefinitionModule*>::iterator iter = ModuleDefinitions->find(mod->NameHash);
                            if (iter == ModuleDefinitions->end())
                            {
                                (*ModuleDefinitions)[mod->NameHash] = mod;
                            }
                            else
                            {
                                PARAMETER_LOG_ERROR(SetManager, "Error: Duplicate structure Hash (%llu) found in definition table: %s / %s\n",
                                    mod->NameHash, iter->second->Name, mod->Name);
                                PARAMETER_DELETE mod;
                            }
                        }
                        else
                        {
                            PARAMETER_LOG_ERROR(SetManager, "Error: Failed to allocate ParameterDefinitionModule object\n");
                        }
                    }
                    else
                    {
                        UINT32 count       = 0;
                        UINT32 structureID = 0;
                        UINT64 nameHash    = 0;
                        result = result && ParameterUtils::Read(&structureID, buffer, length, pos, Alignment, SetManager);
                        result = result && ParameterUtils::Read(&nameHash, buffer, length, pos, Alignment, SetManager);
                        result = result && ParameterUtils::Read(&count, buffer, length, pos, Alignment, SetManager);
                        pos   += count; // Skip Name
                        result = result && ParameterUtils::Read(&count, buffer, length, pos, Alignment, SetManager);
                        pos   += count; // Skip Schema
                    }
                    break;
                }
                case (BYTE)ParameterDefinitionType::ParameterDefinitionType_Structure:
                {
                    if (fbcEnabled)
                    {
                        ParameterDefinitionStructure* structure = PARAMETER_NEW ParameterDefinitionStructure(buffer, length, pos, Alignment, SetManager);
                        if (structure != nullptr)
                        {
                            std::unordered_map<UINT32, ParameterDefinitionStructure*>::iterator iter = StructureDefinitions->find(structure->StructureID);
                            if (iter == StructureDefinitions->end())
                            {
                                (*StructureDefinitions)[structure->StructureID] = structure;
                            }
                            else
                            {
                                PARAMETER_LOG_ERROR(SetManager, "Error: Duplicate structure ID (%u) found in definition table: %s / %s\n",
                                    structure->StructureID, iter->second->TypeName, structure->TypeName);
                                PARAMETER_DELETE structure;
                            }
                        }
                        else
                        {
                            PARAMETER_LOG_ERROR(SetManager, "Error: Failed to allocate ParameterDefinitionStructure object\n");
                        }
                    }
                    else
                    {
                        UINT32 count = 0;
                        UINT32 id    = 0;
                        UINT64 hash  = 0;

                        result = result && ParameterUtils::Read(&id, buffer, length, pos, Alignment, SetManager);
                        result = result && ParameterUtils::Read(&count, buffer, length, pos, Alignment, SetManager);
                        pos   += count; // Skip TypeName
                        result = result && ParameterUtils::Read(&hash, buffer, length, pos, Alignment, SetManager);
                        result = result && ParameterUtils::Read(&count, buffer, length, pos, Alignment, SetManager);

                        for (UINT32 i = 0; i < count; i++)
                        {
                            UINT32 strCnt  = 0;
                            BYTE   defType = 0;
                            UINT16 flags   = 0;
                            UINT32 min     = 0;
                            UINT32 max     = 0;

                            result = result && ParameterUtils::Read(&defType, buffer, length, pos, Alignment, SetManager);
                            result = result && ParameterUtils::Read(&id, buffer, length, pos, Alignment, SetManager);
                            result = result && ParameterUtils::Read(&strCnt, buffer, length, pos, Alignment, SetManager);
                            pos   += strCnt; // Skip Name
                            result = result && ParameterUtils::Read(&flags, buffer, length, pos, Alignment, SetManager);
                            result = result && ParameterUtils::Read(&min, buffer, length, pos, Alignment, SetManager); // MinCount
                            result = result && ParameterUtils::Read(&max, buffer, length, pos, Alignment, SetManager); // MaxCount
                            result = result && ParameterUtils::Read(&strCnt, buffer, length, pos, Alignment, SetManager);
                            pos   += strCnt; // Skip Default
                        }
                    }
                    break;
                }
                case (BYTE)ParameterDefinitionType::ParameterDefinitionType_EnumDefinition:
                {
                    UINT32 count = 0;
                    // We don't need enum information, skip it

                    // Skip ID
                    pos += sizeof(UINT32);

                    // Read name length, and skip it
                    result = result && ParameterUtils::Read(&strCount, buffer, length, pos, Alignment, SetManager);
                    pos += strCount;

                    // Skip Hash
                    pos += sizeof(UINT64);

                    // Read children count, and skip children
                    result = result && ParameterUtils::Read(&count, buffer, length, pos, Alignment, SetManager);

                    for (UINT32 i = 0; i < count; i++)
                    {
                        // Skip Value and Is Value Enum
                        pos += sizeof(UINT32) + sizeof(BYTE);

                        // Read name length, and skip it
                        result = result && ParameterUtils::Read(&strCount, buffer, length, pos, Alignment, SetManager);
                        pos += strCount;

                        // Read value string length, and skip it
                        result = result && ParameterUtils::Read(&strCount, buffer, length, pos, Alignment, SetManager);
                        pos += strCount;
                    }
                    break;
                }
                default:
                    PARAMETER_LOG_ERROR(SetManager, "Error: Unexpected type found in definition table (%u)\n", type);
                    result = false;  // Variable Type, not valid as a Main Type value
                    break;
                }

            } while (result && pos < start + size);

            std::unordered_map<UINT32, ParameterDefinitionStructure*>::iterator iter = StructureDefinitions->begin();
            if (fbcEnabled)
            {
                while (iter != StructureDefinitions->end())
                {
                    iter->second->PopulateOffsetSizeStructure(StructureDefinitions, SetManager);
                    iter++;
                }
            }
        }
        else
        {
            PARAMETER_LOG_ERROR(SetManager, "Failed to allocate ModuleDefinitions or StructureDefinitions\n");
        }
    }

    return result;
}

bool ParameterFileSymbolTable::Load(
    BYTE* const                buffer,
    UINT32 const               bufLength,
    const CHAR* const          fileName,
    ParameterBinaryFile* const file,
    UINT32 const               fileLength,
    const SectionInfo&         symbolTable,
    const SectionInfo&         dataTable,
    const SectionInfo&         data,
    const SectionInfo&         definitions,
    IModeTable* const          modeTable,
    bool const                 fbcEnabled)
{
    UINT32 entrySize = GetSymbolEntrySize();
    m_count = symbolTable.Size / entrySize;

    UINT32 expected = m_count * entrySize;
    bool   valid    = symbolTable.Size == expected;

    if (!valid)
    {
        PARAMETER_LOG_ERROR(SetManager, "Invalid symbol table size: %d, expected: %d\n", symbolTable.Size, expected);
    }

    if (valid && dataTable.Size > 0 && dataTable.Offset > 0)
    {
        entrySize = GetDataTableEntrySize();
        if (entrySize > 0)
        {
            m_dtCount = dataTable.Size / entrySize;

            expected = m_dtCount * entrySize;
            valid    = dataTable.Size == expected;

            if (!valid)
            {
                PARAMETER_LOG_ERROR(SetManager, "Invalid data table size: %d, expected: %d\n", dataTable.Size, expected);
            }
        }
        else
        {
            PARAMETER_LOG_ERROR(SetManager, "Data table entry size is zero\n");
        }
    }

    // Validate symbol table size
    if (valid)
    {
        m_entries     = PARAMETER_NEW ParameterFileSymbolTableEntry[m_count + 1];
        m_entryLookup = PARAMETER_NEW EntryData[m_count + 1];

        if (dataTable.Size > 0 && dataTable.Offset > 0)
        {
            m_dtEntries     = PARAMETER_NEW ParameterFileSymbolTableEntry[m_dtCount + 1];
            m_dtEntryLookup = PARAMETER_NEW EntryData[m_dtCount + 1];
        }
        else
        {
            m_dtEntries     = m_entries;
            m_dtEntryLookup = m_entryLookup;
            m_dtCount       = m_count;
        }

        // m_entryLookup will ultimately point to the entry index in the m_dupEntries, or 0 if there is no duplicate.
        // Start by building m_dupEntries to point to itself or the duplicate entry.
        // Then check if there are enough duplicates to warrant an entry in m_dupEntries (uses the duplicates variable).
        // Then rebuild the m_entryLookup to point to the entry index in m_dupEntries or zero if not valid

        valid = m_entries != nullptr && m_entryLookup != nullptr && m_dtEntries != nullptr && m_dtEntryLookup != nullptr;

        if (!valid)
        {
            PARAMETER_LOG_ERROR(SetManager, "Failed to allocate entry/lookup tables\n");
        }

        FileName   = fileName;
        File       = file;
        m_fileRef  = file != nullptr ? 1 : 0;
        FileLength = fileLength;
        ModeTable  = modeTable;

        if (valid && definitions.Size > 0)
        {
            UINT8* readBuffer = buffer;
            UINT32 readLength = bufLength;
            UINT32 readPos    = definitions.Offset;
            if (file != nullptr)
            {
                readLength = definitions.Size;
                readBuffer = file->Read(definitions.Offset, definitions.Size);
                readPos    = 0;
                valid      = readBuffer != nullptr;
                if (!valid)
                {
                    PARAMETER_LOG_ERROR(SetManager, "Failed to read definition table buffer (offset: %d, size: %d) from binary file\n",
                        definitions.Offset, definitions.Size);
                }
            }

            if (valid && definitions.Size > 0)
            {
                valid = ReadDefinitions(readBuffer, readLength, readPos, definitions.Size, fbcEnabled);
                if (!valid)
                {
                    PARAMETER_LOG_ERROR(SetManager, "Failed to read definition table from binary file\n");
                }
            }

            if (file != nullptr)
            {
                PARAMETER_DELETE[] readBuffer;
                readBuffer = nullptr;
            }
        }

        if (valid)
        {
            UINT8* readBuffer = buffer;
            UINT32 readLength = bufLength;
            UINT32 readPos    = symbolTable.Offset;
            if (file != nullptr)
            {
                readLength = symbolTable.Size;
                readBuffer = file->Read(symbolTable.Offset, symbolTable.Size);
                readPos    = 0;
                valid      = readBuffer != nullptr;
                if (!valid)
                {
                    PARAMETER_LOG_ERROR(SetManager, "Failed to read symbol table buffer (offset: %d, size: %d) from binary file\n", symbolTable.Offset, symbolTable.Size);
                }
            }

            if (valid)
            {
                valid = ReadTable(readBuffer, readLength, readPos, m_count, m_entries, m_entryLookup, m_dupCount,
                    m_dupEntries, data.Offset, modeTable, true);
                if (!valid)
                {
                    PARAMETER_LOG_ERROR(SetManager, "Failed to read symbol table from binary file\n");
                }
            }

            if (file != nullptr)
            {
                PARAMETER_DELETE[] readBuffer;
                readBuffer = nullptr;
            }

            if (valid && dataTable.Size > 0 && dataTable.Offset > 0)
            {
                readPos = dataTable.Offset;

                if (file != nullptr)
                {
                    readLength = dataTable.Size;
                    readBuffer = file->Read(dataTable.Offset, dataTable.Size);
                    readPos    = 0;
                    valid      = readBuffer != nullptr;
                    if (!valid)
                    {
                        PARAMETER_LOG_ERROR(SetManager, "Failed to read data table buffer (offset: %d, size: %d) from binary file\n", symbolTable.Offset, symbolTable.Size);
                    }
                }

                if (valid)
                {
                    valid = ReadTable(readBuffer, readLength, readPos, m_dtCount, m_dtEntries, m_dtEntryLookup, m_dtDupCount,
                        m_dtDupEntries, data.Offset, modeTable, false);
                    if (!valid)
                    {
                        PARAMETER_LOG_ERROR(SetManager, "Failed to read data table from binary file\n");
                    }
                }

                if (file != nullptr)
                {
                    PARAMETER_DELETE[] readBuffer;
                    readBuffer = nullptr;
                }
            }
        }
    }

    if (valid)
    {
        SymbolTableOffset = symbolTable.Offset;
        SymbolTableSize   = symbolTable.Size;
        DataTableOffset   = dataTable.Offset;
        DataTableSize     = dataTable.Size;
        DataOffset        = data.Offset;
        DataSize          = data.Size;
        if (file == nullptr)
        {
            Data = &buffer[data.Offset];
        }
    }

    return valid;
}

bool ParameterFileSymbolTable::Find(
    ParameterFileSymbolTableEntry& entry,
    UINT32 id,
    bool const isModule)
{
    bool       result      = false;
    UINT32     count       = isModule ? m_count       : m_dtCount;
    const EntryData* const entryLookup = isModule ? m_entryLookup : m_dtEntryLookup;
    const ParameterFileSymbolTableEntry* const entries = isModule ? m_entries : m_dtEntries;

    if (SetManager != nullptr && id > 0 && id < count + 1)
    {
        if (entries != nullptr)
        {
            entry = entries[id];
            result = true;
        }
        else if (FileName != nullptr)
        {
            FileReference(1);

            if (File != nullptr)
            {
                UINT32 pos = entryLookup[id].Position;
                entry.Init(this);
                result = entry.Load(Data, FileName, File, FileLength, pos, DataOffset, ModeTable, isModule, id);
            }

            FileReference(-1);
        }
    }
    else
    {
        PARAMETER_LOG_ERROR(SetManager, "Find: Symbol table entry ID %d out of range 1 - %d\n", id, count);
    }

    return result;
}

bool ParameterFileSymbolTable::ReadPointerEntry(
    ParameterFileSymbolTableEntry&       pointerEntry,
    ParameterFileSymbolTableEntry* const entry)
{
    bool   result = false;
    UINT32 id     = 0;

    entry->Read(id, nullptr, entry->DataSize);
    if (id > 0)
    {
        result = Find(pointerEntry, id, false);
        if (!result)
        {
            PARAMETER_LOG_ERROR(SetManager, "ReadPointerEntry: Unable to find pointer entry ID %u in Symbol table%d\n", id);
        }
    }
    else
    {
        PARAMETER_LOG_ERROR(SetManager, "ReadPointerEntry: Unable to read pointer entry from Symbol table\n");
    }
    return result;
}

DupObjInfo* ParameterFileSymbolTable::FindDupObject(
    void* const obj)
{
    DupObjInfo* result = nullptr;

    if (m_dupInfoMap.find(obj) != m_dupInfoMap.end())
    {
        result = m_dupInfoMap[obj];
    }

    return result;
}

DupObjInfo* ParameterFileSymbolTable::GetDupObjectInternal(
    bool const        isModule,
    UINT32 const      id,
    INT32  const      location,
#ifdef PARAMETER_USE_MUTEX
    bool              lock)
#else
    bool)
#endif
{
    DupObjInfo*               result      = nullptr;
    const UINT32              dupCount    = isModule ? m_dupCount    : m_dtDupCount;
    const UINT32              lookupCnt   = isModule ? m_count       : m_dtCount;
    PList<DupObjInfo*>* const dupEntries  = isModule ? m_dupEntries  : m_dtDupEntries;
    const EntryData* const    entryLookup = isModule ? m_entryLookup : m_dtEntryLookup;

    if (dupEntries != nullptr && entryLookup != nullptr && id <= lookupCnt && entryLookup[id].Dup > 0 &&
        entryLookup[id].Dup < dupCount)
    {
#ifdef PARAMETER_USE_MUTEX
        if (lock)
        {
#ifdef PARAMETER_USE_UNIQUE
            m_dupInfoMutex.lock(); // Unique LOCK
#else
            m_dupInfoMutex.lock_shared(); // Shared LOCK
#endif
        }
#endif
        const PList<DupObjInfo*>& dupObject = dupEntries[entryLookup[id].Dup];
        for (UINT32 i = 0; result == nullptr && i < dupObject.Count(); i++)
        {
            DupObjInfo* const obj = dupObject[i];
            if (obj != nullptr && obj->Location == location)
            {
                result = obj;
                if (obj->Object != nullptr)
                {
                    result->RefCount++;
                }
            }
        }
#ifdef PARAMETER_USE_MUTEX
        if (lock)
        {
#ifdef PARAMETER_USE_UNIQUE
            m_dupInfoMutex.unlock(); // Unique LOCK
#else
            m_dupInfoMutex.unlock_shared(); // Shared LOCK
#endif
        }
#endif
    }
    else if (entryLookup != nullptr && id <= lookupCnt)
    {
        // entryLookup[id].Dup == 0 is not an error, ignore
        if (entryLookup[id].Dup > 0)
        {
            PARAMETER_LOG_ERROR(SetManager, "GetDupObject called with invalid values, This: %p, IsModule: %d, ID: %u, DupCount: %u, LookupCnt: %u, DupEntries: %p, EntryLookup: %p, EntryLookup[id].Dup: %u, Loc: %d\n",
                this, isModule, id, dupCount, lookupCnt, dupEntries, entryLookup, entryLookup[id].Dup, location);
        }
    }
    else
    {
        PARAMETER_LOG_ERROR(SetManager, "GetDupObject called with invalid values, This: %p, IsModule: %d, ID: %u, DupCount: %u, LookupCnt: %u, DupEntries: %p, EntryLookup: %p, Loc: %d\n",
            this, isModule, id, dupCount, lookupCnt, dupEntries, entryLookup, location);
    }
    return result;
}

DupObjInfo* ParameterFileSymbolTable::SetDupObject(
    bool const   isModule,
    UINT32 const id,
    void* const  obj,
    INT32 const  location)
{
    DupObjInfo*               result      = nullptr;
    const UINT32              dupCount    = isModule ? m_dupCount    : m_dtDupCount;
    const UINT32              lookupCnt   = isModule ? m_count       : m_dtCount;
    PList<DupObjInfo*>* const dupEntries  = isModule ? m_dupEntries  : m_dtDupEntries;
    const EntryData* const    entryLookup = isModule ? m_entryLookup : m_dtEntryLookup;

    if (obj != nullptr && dupEntries != nullptr && entryLookup != nullptr && id <= lookupCnt &&
        entryLookup[id].Dup > 0 && entryLookup[id].Dup < dupCount)
    {
#ifdef PARAMETER_USE_MUTEX
#ifdef PARAMETER_USE_UNIQUE
        ParameterMutexLocker lock(m_dupInfoMutex); // Unique LOCK
#else
        const std::unique_lock<std::shared_mutex> lock(m_dupInfoMutex); // Unique LOCK
#endif
#endif
        result = GetDupObjectInternal(isModule, id, location, false);
        if (result == nullptr)
        {
            PList<DupObjInfo*>& dupObject = dupEntries[entryLookup[id].Dup];
            result = PARAMETER_NEW DupObjInfo(location);
            result->Object = obj;
            result->RefCount++;
            m_dupInfoMap[obj] = result;
            dupObject.Add(result);
        }
        else if (result->Object == nullptr)
        {
            // entryLookup[id].Dup == 0 is not an error, ignore
            if (result->RefCount > 0)
            {
                PARAMETER_LOG_ERROR(SetManager, "SetDuplicateObject called on existing object with nullptr Object and RefCount %u:"
                    " ID: %d, DupID: %d, Loc: %s:%d, ignored\n", result->RefCount.Get(), id, entryLookup[id].Dup);
            }
            result->Object = obj;
            result->RefCount++;
            m_dupInfoMap[obj] = result;
        }
        else
        {
            result = nullptr;
        }
    }
    else if (entryLookup != nullptr && id <= lookupCnt)
    {
        // entryLookup[id].Dup == 0 is not an error, ignore
        if (entryLookup[id].Dup > 0)
        {
            PARAMETER_LOG_ERROR(SetManager, "SetDupObject called with invalid values, This: %p, IsModule: %d, ID: %u, Obj: %p, DupCount: %u, LookupCnt: %u, DupEntries: %p, EntryLookup: %p, EntryLookup[id].Dup: %u, Loc: %s:%d\n",
                this, isModule, id, obj, dupCount, lookupCnt, dupEntries, entryLookup, entryLookup[id].Dup);
        }
    }
    else
    {
        PARAMETER_LOG_ERROR(SetManager, "SetDupObject called with invalid values, This: %p, IsModule: %d, ID: %u, Obj: %p, DupCount: %u, LookupCnt: %u, DupEntries: %p, EntryLookup: %p, Loc: %s:%d\n",
            this, isModule, id, obj, dupCount, lookupCnt, dupEntries, entryLookup);
    }

    return result;
}

bool ParameterFileSymbolTable::ReleaseDupObject(
    void* const obj)
{
    bool deleteObject = obj != nullptr;

    if (obj != nullptr)
    {
#ifdef PARAMETER_USE_MUTEX
#ifdef PARAMETER_USE_UNIQUE
        ParameterMutexLocker lock(m_dupInfoMutex); // Unique LOCK
#else
        const std::unique_lock<std::shared_mutex> lock(m_dupInfoMutex); // Unique LOCK
#endif
#endif
        DupObjInfo* const dupInfo = FindDupObject(obj);

        if (dupInfo != nullptr)
        {
            deleteObject = DupObjInfo::Release(dupInfo);
            if (deleteObject)
            {
                m_dupInfoMap.erase(obj);
            }
        }
    }

    return deleteObject;
}

UINT32 ParameterFileSymbolTable::GetSymbolEntrySize()
{
    UINT32 result = ParameterFileSymbolTableEntry::SYMBOL_ENTRY_SIZE;
    if (Version <= AlignedEndVersion)
    {
        result = ParameterFileSymbolTableEntry::SYMBOL_ENTRY_ALIGNED_SIZE;
        if (Alignment == 1)
        {
            if (Version < AlignedEndVersion)
            {
                result = ParameterFileSymbolTableEntry::SYMBOL_ENTRY_SIZE_LEGACY;
            }
            else
            {
                result = ParameterFileSymbolTableEntry::SYMBOL_ENTRY_UNALIGNED_SIZE;
            }
        }
    }
    else if (Version < StructSymbolsVersion)
    {
        result = ParameterFileSymbolTableEntry::SYMBOL_ENTRY_TYPE_SIZE;
    }

    return result;
}

UINT32 ParameterFileSymbolTable::GetDataTableEntrySize()
{
    UINT32 result = ParameterFileSymbolTableEntry::DATA_TABLE_ENTRY_SIZE;
    if (Version < DataTableVersion)
    {
        result = 0;
    }
    else if (Version < StructSymbolsVersion)
    {
        result = ParameterFileSymbolTableEntry::DATA_TABLE_ID_ENTRY_SIZE;
    }

    return result;
}

UINT32 ParameterFileSymbolTable::GetModeEntrySize()
{
    UINT32 result = ParameterFileSymbolTableEntry::MODE_ENTRY_SIZE;
    if (Alignment == 1)
    {
        if (Version < AlignedEndVersion)
        {
            result = ParameterFileSymbolTableEntry::MODE_ENTRY_SIZE_LEGACY;
        }
        else if (Version >= ModeFlagsVersion)
        {
            result = ParameterFileSymbolTableEntry::MODE_ENTRY_FLAGS_SIZE;
        }
        else
        {
            result = ParameterFileSymbolTableEntry::MODE_ENTRY_UNALIGNED_SIZE;
        }
    }
    else if (Version < LinkVersion)
    {
        result = ParameterFileSymbolTableEntry::MODE_ENTRY_SIZE_NOLINK;
    }

    return result;
}

ParameterDefinitionElement* ParameterFileSymbolTable::BuildModuleElement(UINT64 nameHash)
{
    ParameterDefinitionElement* result = nullptr;
    if (ModuleDefinitions != nullptr)
    {
        ParameterDefinitionStructure* structure = FindModuleStructure(nameHash);
        if (structure != nullptr)
        {
            result = PARAMETER_NEW ParameterDefinitionElement(structure);
            if (result != nullptr)
            {
                result->NameHash = nameHash;
            }
            else
            {
                PARAMETER_LOG_ERROR(SetManager, "%s: Failed to allocate ParameterDefinitionElement object\n", __FUNCTION__);
            }
        }
    }
    return result;
}

ParameterDefinitionStructure* ParameterFileSymbolTable::FindModuleStructure(UINT64 moduleNameHash)
{
    ParameterDefinitionStructure* result = nullptr;
    if (ModuleDefinitions != nullptr)
    {
        std::unordered_map<UINT64, ParameterDefinitionModule*>::iterator iter = ModuleDefinitions->find(moduleNameHash);

        ParameterDefinitionModule* module = iter != ModuleDefinitions->end() ? iter->second : nullptr;
        if (module != nullptr)
        {
            result = FindStructure(module->StructureID);
        }
    }

    return result;
}

ParameterDefinitionStructure* ParameterFileSymbolTable::FindStructure(UINT32 structID)
{
    ParameterDefinitionStructure* result = nullptr;
    if (StructureDefinitions != nullptr)
    {
        std::unordered_map<UINT32, ParameterDefinitionStructure*>::iterator structure = StructureDefinitions->find(structID);

        result = structure != StructureDefinitions->end() ? structure->second : nullptr;
    }

    return result;
}

void ParameterFileSymbolTable::FreeEntryData()
{
    if (m_dtEntries != m_entries)
    {
        PARAMETER_DELETE[] m_dtEntries;
    }

    PARAMETER_DELETE[] m_entries;
    m_entries   = nullptr;
    m_dtEntries = nullptr;
}

void ParameterFileSymbolTable::FreeLookupData()
{
    if (m_dtEntryLookup != m_entryLookup)
    {
        PARAMETER_DELETE[] m_dtEntryLookup;
    }

    PARAMETER_DELETE[] m_entryLookup;
    m_entryLookup   = nullptr;
    m_dtEntryLookup = nullptr;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// FileReference
///
/// @brief Adjusts the reference count, and opens or closes the file as needed
/// @param adjust - how much to adjust the reference count
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void ParameterFileSymbolTable::FileReference(INT32 adjust)
{
    if (File != nullptr)
    {
        (void)File->Reference(adjust);
    }
    else
    {
        PARAMETER_LOG_ERROR(SetManager, "FileReference called with null File object, Adjust: %d\n", adjust);
    }
}
