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