resource_manager.c
Go to the documentation of this file.
1 /**
2  * @file resource_manager.c
3  * @brief Embedded resource management
4  *
5  * @section License
6  *
7  * Copyright (C) 2010-2018 Oryx Embedded SARL. All rights reserved.
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22  *
23  * @author Oryx Embedded SARL (www.oryx-embedded.com)
24  * @version 1.9.0
25  **/
26 
27 //Dependencies
28 #include <string.h>
29 #include "os_port.h"
30 #include "resource_manager.h"
31 #include "debug.h"
32 
33 //Resource data
34 extern uint8_t res[];
35 
36 
37 error_t resGetData(const char_t *path, uint8_t **data, size_t *length)
38 {
39  bool_t found;
40  bool_t match;
41  uint_t n;
42  uint_t dirLength;
43  ResEntry *resEntry;
44 
45  //Point to the resource header
46  ResHeader *resHeader = (ResHeader *) res;
47 
48  //Make sure the resource data is valid
49  if(resHeader->totalSize < sizeof(ResHeader))
51 
52  //Retrieve the length of the root directory
53  dirLength = resHeader->rootEntry.dataLength;
54  //Point to the contents of the root directory
55  resEntry = (ResEntry *) (res + resHeader->rootEntry.dataStart);
56 
57  //Parse the entire path
58  for(found = FALSE; !found && path[0] != '\0'; path += n + 1)
59  {
60  //Search for the separator that terminates the current token
61  for(n = 0; path[n] != '\\' && path[n] != '/' && path[n] != '\0'; n++);
62 
63  if(n == 0 && path[n] != '\0')
64  {
65  path++;
66  for(n = 0; path[n] != '\\' && path[n] != '/' && path[n] != '\0'; n++);
67  }
68 
69  //Loop through the directory
70  for(match = FALSE; !match && dirLength > 0; )
71  {
72  //Check the number of remaining bytes
73  if(dirLength < sizeof(ResEntry))
75  //Make sure the entry is valid
76  if(dirLength < (sizeof(ResEntry) + resEntry->nameLength))
78 
79  //Compare current entry name against the expected one
80  if(resEntry->nameLength == n && !strncasecmp(resEntry->name, path, n))
81  {
82  //Check the type of the entry
83  if(resEntry->type == RES_TYPE_DIR)
84  {
85  //Save the length of the directory
86  dirLength = resEntry->dataLength;
87  //Point to the contents of the directory
88  resEntry = (ResEntry *) (res + resEntry->dataStart);
89  }
90  else
91  {
92  //A file may only appear at the end of the path
93  if(path[n] != '\0')
94  return ERROR_NOT_FOUND;
95 
96  //The search process is complete
97  found = TRUE;
98  }
99  //The current entry matches the specified path
100  match = TRUE;
101  }
102  else
103  {
104  //Remaining bytes to process
105  dirLength -= sizeof(ResEntry) + resEntry->nameLength;
106  //Point to the next entry
107  resEntry = (ResEntry *) ((uint8_t *) resEntry + sizeof(ResEntry) + resEntry->nameLength);
108  }
109  }
110 
111  //Unable to find the specified file?
112  if(!match)
113  return ERROR_NOT_FOUND;
114  }
115 
116  //Unable to find the specified file?
117  if(!found)
118  return ERROR_NOT_FOUND;
119  //Enforce the entry type
120  if(resEntry->type != RES_TYPE_FILE)
121  return ERROR_NOT_FOUND;
122 
123  //Return the location of the specified resource
124  *data = res + resEntry->dataStart;
125  //Return the length of the resource
126  *length = resEntry->dataLength;
127 
128  //Successful processing
129  return NO_ERROR;
130 }
131 
132 
133 error_t resSearchFile(const char_t *path, DirEntry *dirEntry)
134 {
135  bool_t found;
136  bool_t match;
137  uint_t n;
138  uint_t length;
139  ResEntry *resEntry;
140 
141  //Point to the resource header
142  ResHeader *resHeader = (ResHeader *) res;
143 
144  //Make sure the resource data is valid
145  if(resHeader->totalSize < sizeof(ResHeader))
146  return ERROR_INVALID_RESOURCE;
147 
148  //Retrieve the length of the root directory
149  length = resHeader->rootEntry.dataLength;
150  //Point to the contents of the root directory
151  resEntry = (ResEntry *) (res + resHeader->rootEntry.dataStart);
152 
153  //Parse the entire path
154  for(found = FALSE; !found && path[0] != '\0'; path += n + 1)
155  {
156  //Search for the separator that terminates the current token
157  for(n = 0; path[n] != '\\' && path[n] != '/' && path[n] != '\0'; n++);
158 
159  if(n == 0 && path[n] != '\0')
160  {
161  path++;
162  for(n = 0; path[n] != '\\' && path[n] != '/' && path[n] != '\0'; n++);
163  }
164 
165  //Loop through the directory
166  for(match = FALSE; !match && length > 0; )
167  {
168  //Check the number of remaining bytes
169  if(length < sizeof(ResEntry))
170  return ERROR_INVALID_RESOURCE;
171  //Make sure the entry is valid
172  if(length < (sizeof(ResEntry) + resEntry->nameLength))
173  return ERROR_INVALID_RESOURCE;
174 
175  //Compare current entry name against the expected one
176  if(resEntry->nameLength == n && !strncasecmp(resEntry->name, path, n))
177  {
178  //Check the type of the entry
179  if(resEntry->type == RES_TYPE_DIR)
180  {
181  //Save the length of the directory
182  length = resEntry->dataLength;
183  //Point to the contents of the directory
184  resEntry = (ResEntry *) (res + resEntry->dataStart);
185  }
186  else
187  {
188  //A file may only appear at the end of the path
189  if(path[n] != '\0')
190  return ERROR_INVALID_PATH;
191 
192  //The search process is complete
193  found = TRUE;
194  }
195  //The current entry matches the specified path
196  match = TRUE;
197  }
198  else
199  {
200  //Remaining bytes to process
201  length -= sizeof(ResEntry) + resEntry->nameLength;
202  //Point to the next entry
203  resEntry = (ResEntry *) ((uint8_t *) resEntry + sizeof(ResEntry) + resEntry->nameLength);
204  }
205  }
206 
207  //Unable to find the specified file?
208  if(!match)
209  return ERROR_NOT_FOUND;
210  }
211 
212  //Unable to find the specified file?
213  if(!found)
214  return ERROR_NOT_FOUND;
215 
216  //Return information about the file
217  dirEntry->type = resEntry->type;
218  dirEntry->volume = 0;
219  dirEntry->dataStart = resEntry->dataStart;
220  dirEntry->dataLength = resEntry->dataLength;
221  dirEntry->nameLength = 0; //resEntry->nameLength;
222  //Copy the filename
223  //strncpy(dirEntry->name, resEntry->name, dirEntry->nameLength);
224  //Properly terminate the filename
225  //dirEntry->name[dirEntry->nameLength] = '\0';
226 
227  //Successful processing
228  return NO_ERROR;
229 }
230 
231 #if 0
232 
233 error_t resOpenFile(FsFile *file, const DirEntry *dirEntry, uint_t mode)
234 {
235  file->mode = mode;
236  file->offset = 0;
237  file->start = dirEntry->dataStart;
238  file->size = dirEntry->dataLength;
239 
240  return NO_ERROR;
241 }
242 
243 
244 error_t resSeekFile(FsFile *file, uint32_t *position)
245 {
246  return ERROR_NOT_IMPLEMENTED;
247 }
248 
249 
250 uint_t resReadFile(FsFile *file, void *data, size_t length)
251 {
252  length = MIN(length, file->size - file->offset);
253  memcpy(data, res + file->start + file->offset, length);
254  file->offset += length;
255  return length;
256 }
257 
258 FILE *fopen(const char_t *filename, const char_t *mode)
259 {
260  error_t error;
261  DirEntry dirEntry;
262  FsFile *file;
263 
264  error = resSearchFile(filename, &dirEntry);
265  if(error)
266  return NULL;
267 
268  file = osAllocMem(sizeof(FsFile));
269  if(!file)
270  return NULL;
271 
272  error = resOpenFile(file, &dirEntry, MODE_BINARY);
273  if(error)
274  {
275  osFreeMem(file);
276  return NULL;
277  }
278 
279  return (FILE *) file;
280 }
281 
282 
283 size_t fread(void *ptr, size_t size, size_t count, FILE *stream)
284 {
285  uint_t n;
286 
287  n = resReadFile((FsFile *) stream, ptr, size * count);
288 
289  return n / size;
290 }
291 
292 
293 int_t fclose(FILE * stream)
294 {
295  osFreeMem(stream);
296  //The stream is successfully closed
297  return 0;
298 }
299 
300 
301 uint_t fileGetSize(FILE *stream)
302 {
303  uint_t n;
304  n = ((FsFile *) stream)->size;
305  return n;
306 }
307 
308 #endif
char_t filename[]
Definition: tftp_common.h:89
uint_t volume
char char_t
Definition: compiler_port.h:41
__start_packed struct @2 ResHeader
Resource header.
void osFreeMem(void *p)
Release a previously allocated memory block.
Debugging facilities.
uint8_t res[]
__start_packed struct @0 ResEntry
Resource entry.
error_t resSearchFile(const char_t *path, DirEntry *dirEntry)
#define TRUE
Definition: os_port.h:48
uint8_t file[128]
Definition: dhcp_common.h:210
uint8_t nameLength
signed int int_t
Definition: compiler_port.h:42
RTOS abstraction layer.
uint_t type
error_t resGetData(const char_t *path, uint8_t **data, size_t *length)
#define MIN(a, b)
Definition: os_port.h:60
Success.
Definition: error.h:42
void * osAllocMem(size_t size)
Allocate a memory block.
error_t
Error codes.
Definition: error.h:40
uint32_t dataStart
void FsFile
File handle.
Definition: fs_port.h:120
unsigned int uint_t
Definition: compiler_port.h:43
uint32_t dataLength
uint8_t data[]
Definition: dtls_misc.h:167
#define strncasecmp
uint8_t mode
Definition: sntp_client.h:143
Embedded resource management.
uint8_t length
Definition: dtls_misc.h:140
uint8_t n
#define FALSE
Definition: os_port.h:44
int bool_t
Definition: compiler_port.h:47