1 /**
2  * Copyright(c) 2011 Trusted Logic.   All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  *  * Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  *  * Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in
12  *    the documentation and/or other materials provided with the
13  *    distribution.
14  *  * Neither the name Trusted Logic nor the names of its
15  *    contributors may be used to endorse or promote products derived
16  *    from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 /** Simple implementation of lib_object using doubly-linked lists. This
32    implementation should outperform more sophisticated data structures
33    like blanced binary trees when the tables have fewer than 10 to 20
34    elements.  */
35 
36 #include <string.h>
37 #include "s_type.h"
38 
39 #include "lib_object.h"
40 
41 /* Generic node */
42 typedef struct LIB_OBJECT_NODE
43 {
44    struct LIB_OBJECT_NODE* pPrevious;
45    struct LIB_OBJECT_NODE* pNext;
46    union
47    {
48       uint16_t nHandle;
49 
50       S_STORAGE_NAME sStorageName;
51 
52       struct
53       {
54          /* Public fields */
55          uint8_t  sFilename[64];
56          uint8_t  nFilenameLength;
57       }
58       f;
59    }
60    key;
61 }
62 LIB_OBJECT_NODE;
63 
64 typedef enum
65 {
66    LIB_OBJECT_NODE_TYPE_HANDLE16,
67    LIB_OBJECT_NODE_TYPE_STORAGE_NAME,
68    LIB_OBJECT_NODE_TYPE_FILENAME,
69    LIB_OBJECT_NODE_TYPE_UNINDEXED
70 }
71 LIB_OBJECT_NODE_TYPE;
72 
73 /* -----------------------------------------------------------------------
74    Search functions
75    -----------------------------------------------------------------------*/
libObjectKeyEqualNode(LIB_OBJECT_NODE * pNode,uint32_t nKey1,void * pKey2,LIB_OBJECT_NODE_TYPE eNodeType)76 static bool libObjectKeyEqualNode(
77    LIB_OBJECT_NODE* pNode,
78    uint32_t nKey1,
79    void* pKey2,
80    LIB_OBJECT_NODE_TYPE eNodeType)
81 {
82    switch (eNodeType)
83    {
84    default:
85    case LIB_OBJECT_NODE_TYPE_HANDLE16:
86       return
87          nKey1 == pNode->key.nHandle;
88    case LIB_OBJECT_NODE_TYPE_STORAGE_NAME:
89       return
90          memcmp(
91             (S_STORAGE_NAME*)pKey2,
92             &pNode->key.sStorageName,
93             sizeof(S_STORAGE_NAME)) == 0;
94    case LIB_OBJECT_NODE_TYPE_FILENAME:
95    {
96       uint32_t nLength1 = nKey1;
97       uint32_t nLength2 = pNode->key.f.nFilenameLength;
98       return
99          nLength1 == nLength2
100          &&
101          memcmp(
102             pKey2,
103             &pNode->key.f.sFilename,
104             nLength1) == 0;
105    }
106    }
107 }
108 
109 /* Polymorphic search function */
libObjectSearch(LIB_OBJECT_NODE * pRoot,uint32_t nKey1,void * pKey2,LIB_OBJECT_NODE_TYPE eNodeType)110 static LIB_OBJECT_NODE* libObjectSearch(
111    LIB_OBJECT_NODE* pRoot,
112    uint32_t nKey1,
113    void* pKey2,
114    LIB_OBJECT_NODE_TYPE eNodeType)
115 {
116    if (pRoot != NULL)
117    {
118       LIB_OBJECT_NODE* pNode = pRoot;
119       do
120       {
121          if (libObjectKeyEqualNode(pNode, nKey1, pKey2, eNodeType))
122          {
123             /* Match found */
124             return pNode;
125          }
126          pNode = pNode->pNext;
127       }
128       while (pNode != pRoot);
129    }
130    return NULL;
131 }
132 
libObjectHandle16Search(LIB_OBJECT_TABLE_HANDLE16 * pTable,uint32_t nHandle)133 LIB_OBJECT_NODE_HANDLE16* libObjectHandle16Search(
134                LIB_OBJECT_TABLE_HANDLE16* pTable,
135                uint32_t nHandle)
136 {
137    return (LIB_OBJECT_NODE_HANDLE16*)libObjectSearch(
138       (LIB_OBJECT_NODE*)pTable->pRoot, nHandle, NULL, LIB_OBJECT_NODE_TYPE_HANDLE16);
139 }
140 
141 
libObjectStorageNameSearch(LIB_OBJECT_TABLE_STORAGE_NAME * pTable,S_STORAGE_NAME * pStorageName)142 LIB_OBJECT_NODE_STORAGE_NAME* libObjectStorageNameSearch(
143                LIB_OBJECT_TABLE_STORAGE_NAME* pTable,
144                S_STORAGE_NAME* pStorageName)
145 {
146    return (LIB_OBJECT_NODE_STORAGE_NAME*)libObjectSearch(
147       (LIB_OBJECT_NODE*)pTable->pRoot, 0, pStorageName, LIB_OBJECT_NODE_TYPE_STORAGE_NAME);
148 }
149 
libObjectFilenameSearch(LIB_OBJECT_TABLE_FILENAME * pTable,uint8_t * pFilename,uint32_t nFilenameLength)150 LIB_OBJECT_NODE_FILENAME* libObjectFilenameSearch(
151                LIB_OBJECT_TABLE_FILENAME* pTable,
152                uint8_t* pFilename,
153                uint32_t  nFilenameLength)
154 {
155    return (LIB_OBJECT_NODE_FILENAME*)libObjectSearch(
156       (LIB_OBJECT_NODE*)pTable->pRoot, nFilenameLength, pFilename, LIB_OBJECT_NODE_TYPE_FILENAME);
157 }
158 
159 /* -----------------------------------------------------------------------
160    Add functions
161    -----------------------------------------------------------------------*/
162 
163 /* Polymorphic add function. Add the node at the end of the linked list */
libObjectAdd(LIB_OBJECT_NODE ** ppRoot,LIB_OBJECT_NODE * pNew,LIB_OBJECT_NODE_TYPE eNodeType)164 static bool libObjectAdd(
165    LIB_OBJECT_NODE** ppRoot,
166    LIB_OBJECT_NODE* pNew,
167    LIB_OBJECT_NODE_TYPE eNodeType)
168 {
169    LIB_OBJECT_NODE* pRoot;
170    LIB_OBJECT_NODE* pLast;
171    if (*ppRoot == NULL)
172    {
173       *ppRoot = pNew;
174       pNew->pNext = pNew;
175       pNew->pPrevious = pNew;
176       if (eNodeType == LIB_OBJECT_NODE_TYPE_HANDLE16)
177       {
178          pNew->key.nHandle = 1;
179       }
180       return true;
181    }
182    else
183    {
184       pRoot = *ppRoot;
185       pLast = pRoot->pPrevious;
186       if (eNodeType == LIB_OBJECT_NODE_TYPE_HANDLE16)
187       {
188          if (pLast->key.nHandle == LIB_OBJECT_HANDLE16_MAX)
189          {
190             /* We cannot just assign last handle + 1 because it will
191                overflow. So, scan the whole list */
192             goto scan_list;
193          }
194          pNew->key.nHandle = pLast->key.nHandle + 1;
195       }
196       pLast->pNext = pNew;
197       pNew->pPrevious = pLast;
198       pNew->pNext = pRoot;
199       pRoot->pPrevious = pNew;
200       return true;
201    }
202 scan_list:
203    {
204       LIB_OBJECT_NODE* pNode = pRoot;
205       uint32_t nFreeHandle = 1;
206       do
207       {
208          if (pNode->key.nHandle > nFreeHandle)
209          {
210             /* nMaxHandle+1 is not allocated. Insert pNew just before pNode */
211             pNew->key.nHandle = nFreeHandle;
212             pNew->pNext = pNode;
213             pNew->pPrevious = pNode->pPrevious;
214             pNode->pPrevious->pNext = pNew;
215             pNode->pPrevious = pNew;
216             if (pNode == pRoot)
217             {
218                /* Special case, pNew is the new root */
219                *ppRoot = pNew;
220             }
221             return true;
222          }
223          pNode = pNode->pNext;
224          nFreeHandle++;
225       }
226       while (pNode != pRoot);
227       /* No free handle */
228       return false;
229    }
230 }
231 
libObjectHandle16Add(LIB_OBJECT_TABLE_HANDLE16 * pTable,LIB_OBJECT_NODE_HANDLE16 * pObject)232 bool libObjectHandle16Add(
233                LIB_OBJECT_TABLE_HANDLE16* pTable,
234                LIB_OBJECT_NODE_HANDLE16* pObject)
235 {
236    return libObjectAdd(
237       (LIB_OBJECT_NODE**)&pTable->pRoot,
238       (LIB_OBJECT_NODE*)pObject,
239       LIB_OBJECT_NODE_TYPE_HANDLE16);
240 }
241 
242 
libObjectStorageNameAdd(LIB_OBJECT_TABLE_STORAGE_NAME * pTable,LIB_OBJECT_NODE_STORAGE_NAME * pObject)243 void libObjectStorageNameAdd(
244                LIB_OBJECT_TABLE_STORAGE_NAME* pTable,
245                LIB_OBJECT_NODE_STORAGE_NAME* pObject)
246 {
247    libObjectAdd(
248       (LIB_OBJECT_NODE**)&pTable->pRoot,
249       (LIB_OBJECT_NODE*)pObject,
250       LIB_OBJECT_NODE_TYPE_STORAGE_NAME);
251 }
252 
253 
libObjectFilenameAdd(LIB_OBJECT_TABLE_FILENAME * pTable,LIB_OBJECT_NODE_FILENAME * pObject)254 void libObjectFilenameAdd(
255                LIB_OBJECT_TABLE_FILENAME* pTable,
256                LIB_OBJECT_NODE_FILENAME* pObject)
257 {
258    libObjectAdd(
259       (LIB_OBJECT_NODE**)&pTable->pRoot,
260       (LIB_OBJECT_NODE*)pObject,
261       LIB_OBJECT_NODE_TYPE_FILENAME);
262 }
263 
264 
libObjectUnindexedAdd(LIB_OBJECT_TABLE_UNINDEXED * pTable,LIB_OBJECT_NODE_UNINDEXED * pObject)265 void libObjectUnindexedAdd(
266          LIB_OBJECT_TABLE_UNINDEXED* pTable,
267          LIB_OBJECT_NODE_UNINDEXED* pObject)
268 {
269    libObjectAdd(
270       (LIB_OBJECT_NODE**)&pTable->pRoot,
271       (LIB_OBJECT_NODE*)pObject,
272       LIB_OBJECT_NODE_TYPE_UNINDEXED);
273 }
274 
275 
276 /* -----------------------------------------------------------------------
277    Remove functions
278    -----------------------------------------------------------------------*/
libObjectRemove(LIB_OBJECT_NODE ** ppRoot,LIB_OBJECT_NODE * pObject)279 static void libObjectRemove(LIB_OBJECT_NODE** ppRoot, LIB_OBJECT_NODE* pObject)
280 {
281    LIB_OBJECT_NODE* pPrevious = pObject->pPrevious;
282    LIB_OBJECT_NODE* pNext = pObject->pNext;
283 
284    pPrevious->pNext = pNext;
285    pNext->pPrevious = pPrevious;
286 
287    if (pPrevious == pObject)
288    {
289       /* Removed the last object in the table */
290       *ppRoot = NULL;
291    }
292    else if (pObject == *ppRoot)
293    {
294       /* Removed the first object in the list */
295       *ppRoot = pNext;
296    }
297 }
298 
libObjectRemoveOne(LIB_OBJECT_NODE ** ppRoot)299 static LIB_OBJECT_NODE* libObjectRemoveOne(LIB_OBJECT_NODE** ppRoot)
300 {
301    if (*ppRoot == NULL)
302    {
303       return NULL;
304    }
305    else
306    {
307       LIB_OBJECT_NODE* pObject = *ppRoot;
308       libObjectRemove(ppRoot, pObject);
309       return pObject;
310    }
311 }
312 
libObjectHandle16Remove(LIB_OBJECT_TABLE_HANDLE16 * pTable,LIB_OBJECT_NODE_HANDLE16 * pObject)313 void libObjectHandle16Remove(
314                LIB_OBJECT_TABLE_HANDLE16* pTable,
315                LIB_OBJECT_NODE_HANDLE16* pObject)
316 {
317    libObjectRemove((LIB_OBJECT_NODE**)&pTable->pRoot, (LIB_OBJECT_NODE*)pObject);
318    pObject->nHandle = 0;
319 }
320 
libObjectHandle16RemoveOne(LIB_OBJECT_TABLE_HANDLE16 * pTable)321 LIB_OBJECT_NODE_HANDLE16* libObjectHandle16RemoveOne(
322                LIB_OBJECT_TABLE_HANDLE16* pTable)
323 {
324    LIB_OBJECT_NODE_HANDLE16* pObject = (LIB_OBJECT_NODE_HANDLE16*)libObjectRemoveOne((LIB_OBJECT_NODE**)&pTable->pRoot);
325    if (pObject != NULL)
326    {
327       pObject->nHandle = 0;
328    }
329    return pObject;
330 }
331 
libObjectStorageNameRemove(LIB_OBJECT_TABLE_STORAGE_NAME * pTable,LIB_OBJECT_NODE_STORAGE_NAME * pObject)332 void libObjectStorageNameRemove(
333                LIB_OBJECT_TABLE_STORAGE_NAME* pTable,
334                LIB_OBJECT_NODE_STORAGE_NAME* pObject)
335 {
336    libObjectRemove((LIB_OBJECT_NODE**)&pTable->pRoot, (LIB_OBJECT_NODE*)pObject);
337 }
338 
libObjectStorageNameRemoveOne(LIB_OBJECT_TABLE_STORAGE_NAME * pTable)339 LIB_OBJECT_NODE_STORAGE_NAME* libObjectStorageNameRemoveOne(
340                LIB_OBJECT_TABLE_STORAGE_NAME* pTable)
341 {
342    return (LIB_OBJECT_NODE_STORAGE_NAME*)libObjectRemoveOne((LIB_OBJECT_NODE**)&pTable->pRoot);
343 }
344 
libObjectFilenameRemove(LIB_OBJECT_TABLE_FILENAME * pTable,LIB_OBJECT_NODE_FILENAME * pObject)345 void libObjectFilenameRemove(
346                LIB_OBJECT_TABLE_FILENAME* pTable,
347                LIB_OBJECT_NODE_FILENAME* pObject)
348 {
349    libObjectRemove((LIB_OBJECT_NODE**)&pTable->pRoot, (LIB_OBJECT_NODE*)pObject);
350 }
351 
libObjectFilenameRemoveOne(LIB_OBJECT_TABLE_FILENAME * pTable)352 LIB_OBJECT_NODE_FILENAME* libObjectFilenameRemoveOne(
353                LIB_OBJECT_TABLE_FILENAME* pTable)
354 {
355    return (LIB_OBJECT_NODE_FILENAME*)libObjectRemoveOne((LIB_OBJECT_NODE**)&pTable->pRoot);
356 }
357 
libObjectUnindexedRemove(LIB_OBJECT_TABLE_UNINDEXED * pTable,LIB_OBJECT_NODE_UNINDEXED * pObject)358 void libObjectUnindexedRemove(
359          LIB_OBJECT_TABLE_UNINDEXED* pTable,
360          LIB_OBJECT_NODE_UNINDEXED* pObject)
361 {
362    libObjectRemove((LIB_OBJECT_NODE**)&pTable->pRoot, (LIB_OBJECT_NODE*)pObject);
363 }
364 
libObjectUnindexedRemoveOne(LIB_OBJECT_TABLE_UNINDEXED * pTable)365 LIB_OBJECT_NODE_UNINDEXED* libObjectUnindexedRemoveOne(LIB_OBJECT_TABLE_UNINDEXED* pTable)
366 {
367    return (LIB_OBJECT_NODE_UNINDEXED*)libObjectRemoveOne((LIB_OBJECT_NODE**)&pTable->pRoot);
368 }
369 
370 
371 /* -----------------------------------------------------------------------
372    Get-next functions
373    -----------------------------------------------------------------------*/
374 
libObjectNext(LIB_OBJECT_NODE * pRoot,LIB_OBJECT_NODE * pObject)375 static LIB_OBJECT_NODE* libObjectNext(LIB_OBJECT_NODE* pRoot, LIB_OBJECT_NODE* pObject)
376 {
377    if (pObject == NULL)
378    {
379       return pRoot;
380    }
381    else if (pObject == pRoot->pPrevious)
382    {
383       return NULL;
384    }
385    else
386    {
387       return pObject->pNext;
388    }
389 }
390 
391 
libObjectHandle16Next(LIB_OBJECT_TABLE_HANDLE16 * pTable,LIB_OBJECT_NODE_HANDLE16 * pObject)392 LIB_OBJECT_NODE_HANDLE16* libObjectHandle16Next(
393                LIB_OBJECT_TABLE_HANDLE16* pTable,
394                LIB_OBJECT_NODE_HANDLE16* pObject)
395 {
396    return (LIB_OBJECT_NODE_HANDLE16*)libObjectNext((LIB_OBJECT_NODE*)pTable->pRoot, (LIB_OBJECT_NODE*)pObject);
397 }
398 
libObjectStorageNameNext(LIB_OBJECT_TABLE_STORAGE_NAME * pTable,LIB_OBJECT_NODE_STORAGE_NAME * pObject)399 LIB_OBJECT_NODE_STORAGE_NAME* libObjectStorageNameNext(
400                LIB_OBJECT_TABLE_STORAGE_NAME* pTable,
401                LIB_OBJECT_NODE_STORAGE_NAME* pObject)
402 {
403    return (LIB_OBJECT_NODE_STORAGE_NAME*)libObjectNext((LIB_OBJECT_NODE*)pTable->pRoot, (LIB_OBJECT_NODE*)pObject);
404 }
405 
libObjectFilenameNext(LIB_OBJECT_TABLE_FILENAME * pTable,LIB_OBJECT_NODE_FILENAME * pObject)406 LIB_OBJECT_NODE_FILENAME* libObjectFilenameNext(
407                LIB_OBJECT_TABLE_FILENAME* pTable,
408                LIB_OBJECT_NODE_FILENAME* pObject)
409 {
410    return (LIB_OBJECT_NODE_FILENAME*)libObjectNext((LIB_OBJECT_NODE*)pTable->pRoot, (LIB_OBJECT_NODE*)pObject);
411 }
412 
libObjectUnindexedNext(LIB_OBJECT_TABLE_UNINDEXED * pTable,LIB_OBJECT_NODE_UNINDEXED * pObject)413 LIB_OBJECT_NODE_UNINDEXED* libObjectUnindexedNext(
414                LIB_OBJECT_TABLE_UNINDEXED* pTable,
415                LIB_OBJECT_NODE_UNINDEXED* pObject)
416 {
417    return (LIB_OBJECT_NODE_UNINDEXED*)libObjectNext((LIB_OBJECT_NODE*)pTable->pRoot, (LIB_OBJECT_NODE*)pObject);
418 }
419