Scans the folder structure.
Dependents: GR-PEACH_Digital_Signage
scan_folder.cpp
- Committer:
- dkato
- Date:
- 2016-05-31
- Revision:
- 0:c72b82f46360
File content as of revision 0:c72b82f46360:
/******************************************************************************* * DISCLAIMER * This software is supplied by Renesas Electronics Corporation and is only * intended for use with Renesas products. No other uses are authorized. This * software is owned by Renesas Electronics Corporation and is protected under * all applicable laws, including copyright laws. * THIS SOFTWARE IS PROVIDED "AS IS" AND RENESAS MAKES NO WARRANTIES REGARDING * THIS SOFTWARE, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING BUT NOT * LIMITED TO WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE * AND NON-INFRINGEMENT. ALL SUCH WARRANTIES ARE EXPRESSLY DISCLAIMED. * TO THE MAXIMUM EXTENT PERMITTED NOT PROHIBITED BY LAW, NEITHER RENESAS * ELECTRONICS CORPORATION NOR ANY OF ITS AFFILIATED COMPANIES SHALL BE LIABLE * FOR ANY DIRECT, INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES FOR * ANY REASON RELATED TO THIS SOFTWARE, EVEN IF RENESAS OR ITS AFFILIATES HAVE * BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. * Renesas reserves the right, without notice, to make changes to this software * and to discontinue the availability of this software. By using this software, * you agree to the additional terms and conditions found by accessing the * following link: * http://www.renesas.com/disclaimer* * Copyright (C) 2015 Renesas Electronics Corporation. All rights reserved. *******************************************************************************/ #include "mbed.h" #include "rtos.h" #include "FATFileSystem.h" #include "scan_folder.h" /*--- Macro definition of folder structure scan. ---*/ /* The character string to identify root directory. */ #define STR_ROOT_FOR_F_OPENDIR "" /* to use f_opendir() */ #define CHR_FULL_STOP '.' /* 0x2E: FULL STOP */ #define CHR_SOLIDUS '/' /* 0x2F: SOLIDUS */ #define FOLD_ID_NOT_EXIST (0xFFFFFFFFu) #define OPEN_MODE_READ_ONLY "r" /* File path maximum size including the usb mount name size */ #define FILE_PATH_MAX_SIZE (64u) #define SCAN_WAIT_TIME_MS (1) void ScanFolder::init() { scan_data.total_folder = 0u; scan_data.total_file = 0u; } bool ScanFolder::scan(char_t * p_root_name, const char_t ** pp_extension_tbl) { bool ret = false; bool result; bool chk; uint32_t i; item_t *p_item; FATFS_DIR fdir; const char_t *p_name; bool flg_dir; bool chk_dep; /* Initializes the scan data. */ scan_data.total_file = 0u; scan_data.total_folder = 0u; /* Registers the identifier of the root directory to use f_opendir(). */ (void) regist_item(&scan_data.folder_list[0], STR_ROOT_FOR_F_OPENDIR, FOLD_ID_NOT_EXIST); scan_data.total_folder++; /* Checks the item in all registered directory. */ for (i = 0; i < scan_data.total_folder; i++) { chk_dep = check_folder_depth(i); result = open_dir(&scan_data.folder_list[i], &fdir); while (result != false) { result = read_dir(&fdir, &p_name, &flg_dir); if (result != false) { /* Checks the attribute of this item. */ if (flg_dir != false) { /* This item is directory. */ if ((chk_dep != false) && (scan_data.total_folder < MAX_FOLDER_NUM)) { p_item = &scan_data.folder_list[scan_data.total_folder]; chk = regist_item(p_item, p_name, i); if (chk != false) { /* Register of directory item was success. */ scan_data.total_folder++; } } } else { /* This item is file. */ chk = check_extension(p_name, pp_extension_tbl); if ((chk != false) && (scan_data.total_file < MAX_TRACK_NUM)) { /* This item is requested file. */ p_item = &scan_data.track_list[scan_data.total_file]; chk = regist_item(p_item, p_name, i); if (chk != false) { /* Register of file item was success. */ scan_data.total_file++; } } } Thread::wait(SCAN_WAIT_TIME_MS); } } } /* Changes the identifier of the root directory to use fopen(). */ (void) regist_item(&scan_data.folder_list[0], p_root_name, FOLD_ID_NOT_EXIST); if (scan_data.total_file > 0u) { ret = true; } return ret; } FILE * ScanFolder::open(const uint32_t track_id) { FILE *fp = NULL; const char_t *p_path; size_t path_len; if (track_id < scan_data.total_file) { p_path = get_full_path(&scan_data.track_list[track_id]); if (p_path != NULL) { path_len = strlen(p_path); /* File path maximum length is limited by the specification of "fopen". */ if (path_len < FILE_PATH_MAX_SIZE) { fp = fopen(p_path, OPEN_MODE_READ_ONLY); } } } return fp; } void ScanFolder::close(FILE * const fp) { if (fp != NULL) { (void) fclose(fp); } } const char_t * ScanFolder::getFileName(const uint32_t track_id) { const char_t *p_name = NULL; if (track_id < scan_data.total_file) { p_name = &scan_data.track_list[track_id].name[0]; } return p_name; } uint32_t ScanFolder::getTotalFile() { uint32_t ret; ret = scan_data.total_file; return ret; } /** Gets the full path * * @param p_item Pointer to the item structure of the folder / track. * * @returns * Pointer to the full path. */ const char_t * ScanFolder::get_full_path(const item_t * const p_item) { const char_t *p_path = NULL; const item_t *p; const item_t *item_list[MAX_FOLDER_DEPTH]; uint32_t i; uint32_t item_cnt; uint32_t buf_cnt; uint32_t len; bool err; if (p_item != NULL) { for (i = 0; i < MAX_FOLDER_DEPTH; i++) { item_list[i] = NULL; } scan_data.work_buf[0] = '\0'; /* Stores the item name until the root folder. */ p = p_item; item_cnt = 0; while ((item_cnt < MAX_FOLDER_DEPTH) && (p->parent_number < scan_data.total_folder)) { item_list[item_cnt] = p; item_cnt++; p = &scan_data.folder_list[p->parent_number]; } if (p->parent_number == FOLD_ID_NOT_EXIST) { buf_cnt = strlen(p->name); (void) strncpy(&scan_data.work_buf[0], p->name, sizeof(scan_data.work_buf)); err = false; while ((item_cnt > 0u) && (err != true)) { item_cnt--; p = item_list[item_cnt]; /* Concatenates SOLIDUS character to the "work_buf" variable. */ if ((buf_cnt + 1u) < sizeof(scan_data.work_buf)) { scan_data.work_buf[buf_cnt] = CHR_SOLIDUS; buf_cnt++; } else { err = true; } /* Concatenates the item name to the "work_buf" variable. */ if (p != NULL) { len = strlen(p->name); if ((buf_cnt + len) < sizeof(scan_data.work_buf)) { (void) strncpy(&scan_data.work_buf[buf_cnt], p->name, len); buf_cnt += len; } else { err = true; } } } if (err != true) { scan_data.work_buf[buf_cnt] = '\0'; p_path = &scan_data.work_buf[0]; } } } return p_path; } /** Opens the directory * * @param p_item Pointer to the item structure of the folder / track. * @param p_fdir Pointer to the structure to store the directory object. * * @returns * Results of process. true is success. false is failure. */ bool ScanFolder::open_dir(const item_t * const p_item, FATFS_DIR * const p_fdir) { bool ret = false; const char_t *p_path; FRESULT ferr; if ((p_item != NULL) && (p_fdir != NULL)) { p_path = get_full_path(p_item); if (p_path != NULL) { ferr = f_opendir(p_fdir, p_path); if (ferr == FR_OK) { ret = true; } } } return ret; } /** Reads the directory * * @param p_fdir Pointer to the structure of the directory object. * @param p_flag_dir Pointer to the variable to store the directory flag. * * @returns * Pointer to the name. */ bool ScanFolder::read_dir(FATFS_DIR * const p_fdir, const char_t ** const p_name, bool * const p_flag_dir) { bool ret = false; FRESULT ferr; FILINFO finfo; if ((p_fdir != NULL) && (p_name != NULL) && (p_flag_dir != NULL)) { /* Sets the buffer to store the long file name. */ finfo.lfname = &scan_data.work_buf[0]; finfo.lfsize = sizeof(scan_data.work_buf); ferr = f_readdir(p_fdir, &finfo); if ((ferr == FR_OK) && ((int32_t)finfo.fname[0] != '\0')) { if (finfo.lfname != NULL) { if ((int32_t)finfo.lfname[0] == '\0') { /* Long file name does not exist. */ (void) strncpy(finfo.lfname, finfo.fname, finfo.lfsize); } /* Adds the NULL terminal character. */ /* This is fail-safe processing. */ finfo.lfname[finfo.lfsize - 1u] = '\0'; ret = true; *p_name = finfo.lfname; if ((finfo.fattrib & AM_DIR) != 0) { /* This item is directory. */ *p_flag_dir = true; } else { /* This item is file. */ *p_flag_dir = false; } } } } return ret; } /** Registers the item of the folder / track * * @param p_item Pointer to the structure to store the item of the folder / track. * @param p_name Pointer to the name of the item. * @param parent Number of the parent folder of the item. * * @returns * Results of process. true is success. false is failure. */ bool ScanFolder::regist_item(item_t * const p_item, const char_t * const p_name, const uint32_t parent) { bool ret = false; uint32_t len; if ((p_item != NULL) && (p_name != NULL)) { len = strlen(p_name); if ((len + 1u) < sizeof(p_item->name)) { (void) strncpy(p_item->name, p_name, sizeof(p_item->name)); p_item->name[sizeof(p_item->name) - 1u] = '\0'; p_item->parent_number = parent; ret = true; } } return ret; } /** Checks the extension of the track name * * @param p_name Pointer to the name of the track. * * @returns * Results of the checking. true is requested file. false is other file. */ bool ScanFolder::check_extension(const char_t * const p_name, const char_t ** pp_extension_tbl) { bool ret = false; const char_t *p; size_t extension_len; const char_t * p_extension; if (p_name != NULL) { p = strrchr(p_name, CHR_FULL_STOP); if (p != NULL) { while (1) { p_extension = *(pp_extension_tbl++); if (p_extension != NULL) { extension_len = strlen(p_extension); if (strncasecmp(p, p_extension, extension_len) == 0) { ret = true; break; } } else { break; } } } } return ret; } /** Checks the folder depth in the scan range * * @param folder_id Folder ID [0 - (total folder - 1)] * * @returns * Results of the checking. true is the scan range. false is out of a scan range. */ bool ScanFolder::check_folder_depth(const uint32_t folder_id) { bool ret = false; uint32_t depth; uint32_t parent_id; /* Counts the folder depth. */ parent_id = folder_id; depth = 0u; while ((depth < MAX_FOLDER_DEPTH) && (parent_id < scan_data.total_folder)) { depth++; parent_id = scan_data.folder_list[parent_id].parent_number; } if (parent_id == FOLD_ID_NOT_EXIST) { /* Found the root folder. */ if (depth < MAX_FOLDER_DEPTH) { ret = true; } } return ret; }