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