/** * Copyright(c) 2011 Trusted Logic. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name Trusted Logic nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** Simple implementation of lib_object using doubly-linked lists. This implementation should outperform more sophisticated data structures like blanced binary trees when the tables have fewer than 10 to 20 elements. */ #include <string.h> #include "s_type.h" #include "lib_object.h" /* Generic node */ typedef struct LIB_OBJECT_NODE { struct LIB_OBJECT_NODE* pPrevious; struct LIB_OBJECT_NODE* pNext; union { uint16_t nHandle; S_STORAGE_NAME sStorageName; struct { /* Public fields */ uint8_t sFilename[64]; uint8_t nFilenameLength; } f; } key; } LIB_OBJECT_NODE; typedef enum { LIB_OBJECT_NODE_TYPE_HANDLE16, LIB_OBJECT_NODE_TYPE_STORAGE_NAME, LIB_OBJECT_NODE_TYPE_FILENAME, LIB_OBJECT_NODE_TYPE_UNINDEXED } LIB_OBJECT_NODE_TYPE; /* ----------------------------------------------------------------------- Search functions -----------------------------------------------------------------------*/ static bool libObjectKeyEqualNode( LIB_OBJECT_NODE* pNode, uint32_t nKey1, void* pKey2, LIB_OBJECT_NODE_TYPE eNodeType) { switch (eNodeType) { default: case LIB_OBJECT_NODE_TYPE_HANDLE16: return nKey1 == pNode->key.nHandle; case LIB_OBJECT_NODE_TYPE_STORAGE_NAME: return memcmp( (S_STORAGE_NAME*)pKey2, &pNode->key.sStorageName, sizeof(S_STORAGE_NAME)) == 0; case LIB_OBJECT_NODE_TYPE_FILENAME: { uint32_t nLength1 = nKey1; uint32_t nLength2 = pNode->key.f.nFilenameLength; return nLength1 == nLength2 && memcmp( pKey2, &pNode->key.f.sFilename, nLength1) == 0; } } } /* Polymorphic search function */ static LIB_OBJECT_NODE* libObjectSearch( LIB_OBJECT_NODE* pRoot, uint32_t nKey1, void* pKey2, LIB_OBJECT_NODE_TYPE eNodeType) { if (pRoot != NULL) { LIB_OBJECT_NODE* pNode = pRoot; do { if (libObjectKeyEqualNode(pNode, nKey1, pKey2, eNodeType)) { /* Match found */ return pNode; } pNode = pNode->pNext; } while (pNode != pRoot); } return NULL; } LIB_OBJECT_NODE_HANDLE16* libObjectHandle16Search( LIB_OBJECT_TABLE_HANDLE16* pTable, uint32_t nHandle) { return (LIB_OBJECT_NODE_HANDLE16*)libObjectSearch( (LIB_OBJECT_NODE*)pTable->pRoot, nHandle, NULL, LIB_OBJECT_NODE_TYPE_HANDLE16); } LIB_OBJECT_NODE_STORAGE_NAME* libObjectStorageNameSearch( LIB_OBJECT_TABLE_STORAGE_NAME* pTable, S_STORAGE_NAME* pStorageName) { return (LIB_OBJECT_NODE_STORAGE_NAME*)libObjectSearch( (LIB_OBJECT_NODE*)pTable->pRoot, 0, pStorageName, LIB_OBJECT_NODE_TYPE_STORAGE_NAME); } LIB_OBJECT_NODE_FILENAME* libObjectFilenameSearch( LIB_OBJECT_TABLE_FILENAME* pTable, uint8_t* pFilename, uint32_t nFilenameLength) { return (LIB_OBJECT_NODE_FILENAME*)libObjectSearch( (LIB_OBJECT_NODE*)pTable->pRoot, nFilenameLength, pFilename, LIB_OBJECT_NODE_TYPE_FILENAME); } /* ----------------------------------------------------------------------- Add functions -----------------------------------------------------------------------*/ /* Polymorphic add function. Add the node at the end of the linked list */ static bool libObjectAdd( LIB_OBJECT_NODE** ppRoot, LIB_OBJECT_NODE* pNew, LIB_OBJECT_NODE_TYPE eNodeType) { LIB_OBJECT_NODE* pRoot; LIB_OBJECT_NODE* pLast; if (*ppRoot == NULL) { *ppRoot = pNew; pNew->pNext = pNew; pNew->pPrevious = pNew; if (eNodeType == LIB_OBJECT_NODE_TYPE_HANDLE16) { pNew->key.nHandle = 1; } return true; } else { pRoot = *ppRoot; pLast = pRoot->pPrevious; if (eNodeType == LIB_OBJECT_NODE_TYPE_HANDLE16) { if (pLast->key.nHandle == LIB_OBJECT_HANDLE16_MAX) { /* We cannot just assign last handle + 1 because it will overflow. So, scan the whole list */ goto scan_list; } pNew->key.nHandle = pLast->key.nHandle + 1; } pLast->pNext = pNew; pNew->pPrevious = pLast; pNew->pNext = pRoot; pRoot->pPrevious = pNew; return true; } scan_list: { LIB_OBJECT_NODE* pNode = pRoot; uint32_t nFreeHandle = 1; do { if (pNode->key.nHandle > nFreeHandle) { /* nMaxHandle+1 is not allocated. Insert pNew just before pNode */ pNew->key.nHandle = nFreeHandle; pNew->pNext = pNode; pNew->pPrevious = pNode->pPrevious; pNode->pPrevious->pNext = pNew; pNode->pPrevious = pNew; if (pNode == pRoot) { /* Special case, pNew is the new root */ *ppRoot = pNew; } return true; } pNode = pNode->pNext; nFreeHandle++; } while (pNode != pRoot); /* No free handle */ return false; } } bool libObjectHandle16Add( LIB_OBJECT_TABLE_HANDLE16* pTable, LIB_OBJECT_NODE_HANDLE16* pObject) { return libObjectAdd( (LIB_OBJECT_NODE**)&pTable->pRoot, (LIB_OBJECT_NODE*)pObject, LIB_OBJECT_NODE_TYPE_HANDLE16); } void libObjectStorageNameAdd( LIB_OBJECT_TABLE_STORAGE_NAME* pTable, LIB_OBJECT_NODE_STORAGE_NAME* pObject) { libObjectAdd( (LIB_OBJECT_NODE**)&pTable->pRoot, (LIB_OBJECT_NODE*)pObject, LIB_OBJECT_NODE_TYPE_STORAGE_NAME); } void libObjectFilenameAdd( LIB_OBJECT_TABLE_FILENAME* pTable, LIB_OBJECT_NODE_FILENAME* pObject) { libObjectAdd( (LIB_OBJECT_NODE**)&pTable->pRoot, (LIB_OBJECT_NODE*)pObject, LIB_OBJECT_NODE_TYPE_FILENAME); } void libObjectUnindexedAdd( LIB_OBJECT_TABLE_UNINDEXED* pTable, LIB_OBJECT_NODE_UNINDEXED* pObject) { libObjectAdd( (LIB_OBJECT_NODE**)&pTable->pRoot, (LIB_OBJECT_NODE*)pObject, LIB_OBJECT_NODE_TYPE_UNINDEXED); } /* ----------------------------------------------------------------------- Remove functions -----------------------------------------------------------------------*/ static void libObjectRemove(LIB_OBJECT_NODE** ppRoot, LIB_OBJECT_NODE* pObject) { LIB_OBJECT_NODE* pPrevious = pObject->pPrevious; LIB_OBJECT_NODE* pNext = pObject->pNext; pPrevious->pNext = pNext; pNext->pPrevious = pPrevious; if (pPrevious == pObject) { /* Removed the last object in the table */ *ppRoot = NULL; } else if (pObject == *ppRoot) { /* Removed the first object in the list */ *ppRoot = pNext; } } static LIB_OBJECT_NODE* libObjectRemoveOne(LIB_OBJECT_NODE** ppRoot) { if (*ppRoot == NULL) { return NULL; } else { LIB_OBJECT_NODE* pObject = *ppRoot; libObjectRemove(ppRoot, pObject); return pObject; } } void libObjectHandle16Remove( LIB_OBJECT_TABLE_HANDLE16* pTable, LIB_OBJECT_NODE_HANDLE16* pObject) { libObjectRemove((LIB_OBJECT_NODE**)&pTable->pRoot, (LIB_OBJECT_NODE*)pObject); pObject->nHandle = 0; } LIB_OBJECT_NODE_HANDLE16* libObjectHandle16RemoveOne( LIB_OBJECT_TABLE_HANDLE16* pTable) { LIB_OBJECT_NODE_HANDLE16* pObject = (LIB_OBJECT_NODE_HANDLE16*)libObjectRemoveOne((LIB_OBJECT_NODE**)&pTable->pRoot); if (pObject != NULL) { pObject->nHandle = 0; } return pObject; } void libObjectStorageNameRemove( LIB_OBJECT_TABLE_STORAGE_NAME* pTable, LIB_OBJECT_NODE_STORAGE_NAME* pObject) { libObjectRemove((LIB_OBJECT_NODE**)&pTable->pRoot, (LIB_OBJECT_NODE*)pObject); } LIB_OBJECT_NODE_STORAGE_NAME* libObjectStorageNameRemoveOne( LIB_OBJECT_TABLE_STORAGE_NAME* pTable) { return (LIB_OBJECT_NODE_STORAGE_NAME*)libObjectRemoveOne((LIB_OBJECT_NODE**)&pTable->pRoot); } void libObjectFilenameRemove( LIB_OBJECT_TABLE_FILENAME* pTable, LIB_OBJECT_NODE_FILENAME* pObject) { libObjectRemove((LIB_OBJECT_NODE**)&pTable->pRoot, (LIB_OBJECT_NODE*)pObject); } LIB_OBJECT_NODE_FILENAME* libObjectFilenameRemoveOne( LIB_OBJECT_TABLE_FILENAME* pTable) { return (LIB_OBJECT_NODE_FILENAME*)libObjectRemoveOne((LIB_OBJECT_NODE**)&pTable->pRoot); } void libObjectUnindexedRemove( LIB_OBJECT_TABLE_UNINDEXED* pTable, LIB_OBJECT_NODE_UNINDEXED* pObject) { libObjectRemove((LIB_OBJECT_NODE**)&pTable->pRoot, (LIB_OBJECT_NODE*)pObject); } LIB_OBJECT_NODE_UNINDEXED* libObjectUnindexedRemoveOne(LIB_OBJECT_TABLE_UNINDEXED* pTable) { return (LIB_OBJECT_NODE_UNINDEXED*)libObjectRemoveOne((LIB_OBJECT_NODE**)&pTable->pRoot); } /* ----------------------------------------------------------------------- Get-next functions -----------------------------------------------------------------------*/ static LIB_OBJECT_NODE* libObjectNext(LIB_OBJECT_NODE* pRoot, LIB_OBJECT_NODE* pObject) { if (pObject == NULL) { return pRoot; } else if (pObject == pRoot->pPrevious) { return NULL; } else { return pObject->pNext; } } LIB_OBJECT_NODE_HANDLE16* libObjectHandle16Next( LIB_OBJECT_TABLE_HANDLE16* pTable, LIB_OBJECT_NODE_HANDLE16* pObject) { return (LIB_OBJECT_NODE_HANDLE16*)libObjectNext((LIB_OBJECT_NODE*)pTable->pRoot, (LIB_OBJECT_NODE*)pObject); } LIB_OBJECT_NODE_STORAGE_NAME* libObjectStorageNameNext( LIB_OBJECT_TABLE_STORAGE_NAME* pTable, LIB_OBJECT_NODE_STORAGE_NAME* pObject) { return (LIB_OBJECT_NODE_STORAGE_NAME*)libObjectNext((LIB_OBJECT_NODE*)pTable->pRoot, (LIB_OBJECT_NODE*)pObject); } LIB_OBJECT_NODE_FILENAME* libObjectFilenameNext( LIB_OBJECT_TABLE_FILENAME* pTable, LIB_OBJECT_NODE_FILENAME* pObject) { return (LIB_OBJECT_NODE_FILENAME*)libObjectNext((LIB_OBJECT_NODE*)pTable->pRoot, (LIB_OBJECT_NODE*)pObject); } LIB_OBJECT_NODE_UNINDEXED* libObjectUnindexedNext( LIB_OBJECT_TABLE_UNINDEXED* pTable, LIB_OBJECT_NODE_UNINDEXED* pObject) { return (LIB_OBJECT_NODE_UNINDEXED*)libObjectNext((LIB_OBJECT_NODE*)pTable->pRoot, (LIB_OBJECT_NODE*)pObject); }