Webserver+3d print

Dependents:   Nucleo

common/resource_manager.c

Committer:
Sergunb
Date:
2017-02-04
Revision:
0:8918a71cdbe9

File content as of revision 0:8918a71cdbe9:

/**
 * @file resource_manager.c
 * @brief Embedded resource management
 *
 * @section License
 *
 * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 *
 * @author Oryx Embedded SARL (www.oryx-embedded.com)
 * @version 1.7.6
 **/

//Dependencies
#include <string.h>
#include "os_port.h"
#include "resource_manager.h"
#include "debug.h"

//Resource data
extern uint8_t res[];


error_t resGetData(const char_t *path, uint8_t **data, size_t *length)
{
   bool_t found;
   bool_t match;
   uint_t n;
   uint_t dirLength;
   ResEntry *resEntry;

   //Point to the resource header
   ResHeader *resHeader = (ResHeader *) res;

   //Make sure the resource data is valid
   if(resHeader->totalSize < sizeof(ResHeader))
      return ERROR_INVALID_RESOURCE;

   //Retrieve the length of the root directory
   dirLength = resHeader->rootEntry.dataLength;
   //Point to the contents of the root directory
   resEntry = (ResEntry *) (res + resHeader->rootEntry.dataStart);

   //Parse the entire path
   for(found = FALSE; !found && path[0] != '\0'; path += n + 1)
   {
      //Search for the separator that terminates the current token
      for(n = 0; path[n] != '\\' && path[n] != '/' && path[n] != '\0'; n++);

      if(n == 0 && path[n] != '\0')
      {
         path++;
         for(n = 0; path[n] != '\\' && path[n] != '/' && path[n] != '\0'; n++);
      }

      //Loop through the directory
      for(match = FALSE; !match && dirLength > 0; )
      {
         //Check the number of remaining bytes
         if(dirLength < sizeof(ResEntry))
            return ERROR_INVALID_RESOURCE;
         //Make sure the entry is valid
         if(dirLength < (sizeof(ResEntry) + resEntry->nameLength))
            return ERROR_INVALID_RESOURCE;

         //Compare current entry name against the expected one
         if(resEntry->nameLength == n && !strncasecmp(resEntry->name, path, n))
         {
            //Check the type of the entry
            if(resEntry->type == RES_TYPE_DIR)
            {
               //Save the length of the directory
               dirLength = resEntry->dataLength;
               //Point to the contents of the directory
               resEntry = (ResEntry *) (res + resEntry->dataStart);
            }
            else
            {
               //A file may only appear at the end of the path
               if(path[n] != '\0')
                  return ERROR_NOT_FOUND;

               //The search process is complete
               found = TRUE;
            }
            //The current entry matches the specified path
            match = TRUE;
         }
         else
         {
            //Remaining bytes to process
            dirLength -= sizeof(ResEntry) + resEntry->nameLength;
            //Point to the next entry
            resEntry = (ResEntry *) ((uint8_t *) resEntry + sizeof(ResEntry) + resEntry->nameLength);
         }
      }

      //Unable to find the specified file?
      if(!match)
         return ERROR_NOT_FOUND;
   }

   //Unable to find the specified file?
   if(!found)
      return ERROR_NOT_FOUND;
   //Enforce the entry type
   if(resEntry->type != RES_TYPE_FILE)
      return ERROR_NOT_FOUND;

   //Return the location of the specified resource
   *data = res + resEntry->dataStart;
   //Return the length of the resource
   *length = resEntry->dataLength;

   //Successful processing
   return NO_ERROR;
}


error_t resSearchFile(const char_t *path, DirEntry *dirEntry)
{
   bool_t found;
   bool_t match;
   uint_t n;
   uint_t length;
   ResEntry *resEntry;

   //Point to the resource header
   ResHeader *resHeader = (ResHeader *) res;

   //Make sure the resource data is valid
   if(resHeader->totalSize < sizeof(ResHeader))
      return ERROR_INVALID_RESOURCE;

   //Retrieve the length of the root directory
   length = resHeader->rootEntry.dataLength;
   //Point to the contents of the root directory
   resEntry = (ResEntry *) (res + resHeader->rootEntry.dataStart);

   //Parse the entire path
   for(found = FALSE; !found && path[0] != '\0'; path += n + 1)
   {
      //Search for the separator that terminates the current token
      for(n = 0; path[n] != '\\' && path[n] != '/' && path[n] != '\0'; n++);

      if(n == 0 && path[n] != '\0')
      {
         path++;
         for(n = 0; path[n] != '\\' && path[n] != '/' && path[n] != '\0'; n++);
      }

      //Loop through the directory
      for(match = FALSE; !match && length > 0; )
      {
         //Check the number of remaining bytes
         if(length < sizeof(ResEntry))
            return ERROR_INVALID_RESOURCE;
         //Make sure the entry is valid
         if(length < (sizeof(ResEntry) + resEntry->nameLength))
            return ERROR_INVALID_RESOURCE;

         //Compare current entry name against the expected one
         if(resEntry->nameLength == n && !strncasecmp(resEntry->name, path, n))
         {
            //Check the type of the entry
            if(resEntry->type == RES_TYPE_DIR)
            {
               //Save the length of the directory
               length = resEntry->dataLength;
               //Point to the contents of the directory
               resEntry = (ResEntry *) (res + resEntry->dataStart);
            }
            else
            {
               //A file may only appear at the end of the path
               if(path[n] != '\0')
                  return ERROR_INVALID_PATH;

               //The search process is complete
               found = TRUE;
            }
            //The current entry matches the specified path
            match = TRUE;
         }
         else
         {
            //Remaining bytes to process
            length -= sizeof(ResEntry) + resEntry->nameLength;
            //Point to the next entry
            resEntry = (ResEntry *) ((uint8_t *) resEntry + sizeof(ResEntry) + resEntry->nameLength);
         }
      }

      //Unable to find the specified file?
      if(!match)
         return ERROR_NOT_FOUND;
   }

   //Unable to find the specified file?
   if(!found)
      return ERROR_NOT_FOUND;

   //Return information about the file
   dirEntry->type = resEntry->type;
   dirEntry->volume = 0;
   dirEntry->dataStart = resEntry->dataStart;
   dirEntry->dataLength = resEntry->dataLength;
   dirEntry->nameLength = 0; //resEntry->nameLength;
   //Copy the filename
   //strncpy(dirEntry->name, resEntry->name, dirEntry->nameLength);
   //Properly terminate the filename
   //dirEntry->name[dirEntry->nameLength] = '\0';

   //Successful processing
   return NO_ERROR;
}

#if 0

error_t resOpenFile(FsFile *file, const DirEntry *dirEntry, uint_t mode)
{
   file->mode = mode;
   file->offset = 0;
   file->start = dirEntry->dataStart;
   file->size = dirEntry->dataLength;

   return NO_ERROR;
}


error_t resSeekFile(FsFile *file, uint32_t *position)
{
   return ERROR_NOT_IMPLEMENTED;
}


uint_t resReadFile(FsFile *file, void *data, size_t length)
{
   length = MIN(length, file->size - file->offset);
   memcpy(data, res + file->start + file->offset, length);
   file->offset += length;
   return length;
}

FILE *fopen(const char_t *filename, const char_t *mode)
{
   error_t error;
   DirEntry dirEntry;
   FsFile *file;

   error = resSearchFile(filename, &dirEntry);
   if(error)
      return NULL;

   file = osAllocMem(sizeof(FsFile));
   if(!file)
      return NULL;

   error = resOpenFile(file, &dirEntry, MODE_BINARY);
   if(error)
   {
      osFreeMem(file);
      return NULL;
   }

   return (FILE *) file;
}


size_t fread(void *ptr, size_t size, size_t count, FILE *stream)
{
   uint_t n;

   n = resReadFile((FsFile *) stream, ptr, size * count);

   return n / size;
}


int_t fclose(FILE * stream)
{
   osFreeMem(stream);
   //The stream is successfully closed
   return 0;
}


uint_t fileGetSize(FILE *stream)
{
   uint_t n;
   n = ((FsFile *) stream)->size;
   return n;
}

#endif