Daiki Kato / scan_folder

Dependents:   GR-PEACH_Digital_Signage

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers scan_folder.cpp Source File

scan_folder.cpp

00001 /*******************************************************************************
00002 * DISCLAIMER
00003 * This software is supplied by Renesas Electronics Corporation and is only
00004 * intended for use with Renesas products. No other uses are authorized. This
00005 * software is owned by Renesas Electronics Corporation and is protected under
00006 * all applicable laws, including copyright laws.
00007 * THIS SOFTWARE IS PROVIDED "AS IS" AND RENESAS MAKES NO WARRANTIES REGARDING
00008 * THIS SOFTWARE, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING BUT NOT
00009 * LIMITED TO WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
00010 * AND NON-INFRINGEMENT. ALL SUCH WARRANTIES ARE EXPRESSLY DISCLAIMED.
00011 * TO THE MAXIMUM EXTENT PERMITTED NOT PROHIBITED BY LAW, NEITHER RENESAS
00012 * ELECTRONICS CORPORATION NOR ANY OF ITS AFFILIATED COMPANIES SHALL BE LIABLE
00013 * FOR ANY DIRECT, INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES FOR
00014 * ANY REASON RELATED TO THIS SOFTWARE, EVEN IF RENESAS OR ITS AFFILIATES HAVE
00015 * BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
00016 * Renesas reserves the right, without notice, to make changes to this software
00017 * and to discontinue the availability of this software. By using this software,
00018 * you agree to the additional terms and conditions found by accessing the
00019 * following link:
00020 * http://www.renesas.com/disclaimer*
00021 * Copyright (C) 2015 Renesas Electronics Corporation. All rights reserved.
00022 *******************************************************************************/
00023 
00024 #include "mbed.h"
00025 #include "rtos.h"
00026 #include "FATFileSystem.h"
00027 #include "scan_folder.h"
00028 
00029 /*--- Macro definition of folder structure scan. ---*/
00030 /* The character string to identify root directory. */
00031 #define STR_ROOT_FOR_F_OPENDIR  ""                      /* to use f_opendir() */
00032 
00033 #define CHR_FULL_STOP           '.'         /* 0x2E: FULL STOP */
00034 #define CHR_SOLIDUS             '/'         /* 0x2F: SOLIDUS */
00035 #define FOLD_ID_NOT_EXIST       (0xFFFFFFFFu)
00036 #define OPEN_MODE_READ_ONLY     "r"
00037 
00038 /* File path maximum size including the usb mount name size */
00039 #define FILE_PATH_MAX_SIZE      (64u)
00040 
00041 #define SCAN_WAIT_TIME_MS       (1)
00042 
00043 
00044 void ScanFolder::init() {
00045     scan_data.total_folder = 0u;
00046     scan_data.total_file = 0u;
00047 }
00048 
00049 bool ScanFolder::scan(char_t * p_root_name, const char_t ** pp_extension_tbl) {
00050     bool            ret = false;
00051     bool            result;
00052     bool            chk;
00053     uint32_t        i;
00054     item_t          *p_item;
00055     FATFS_DIR       fdir;
00056     const char_t    *p_name;
00057     bool            flg_dir;
00058     bool            chk_dep;
00059 
00060     /* Initializes the scan data. */
00061     scan_data.total_file = 0u;
00062     scan_data.total_folder = 0u;
00063 
00064     /* Registers the identifier of the root directory to use f_opendir(). */
00065     (void) regist_item(&scan_data.folder_list[0], STR_ROOT_FOR_F_OPENDIR, FOLD_ID_NOT_EXIST);
00066     scan_data.total_folder++;
00067 
00068     /* Checks the item in all registered directory. */
00069     for (i = 0; i < scan_data.total_folder; i++) {
00070         chk_dep = check_folder_depth(i);
00071         result = open_dir(&scan_data.folder_list[i], &fdir);
00072         while (result != false) {
00073             result = read_dir(&fdir, &p_name, &flg_dir);
00074             if (result != false) {
00075                 /* Checks the attribute of this item. */
00076                 if (flg_dir != false) {
00077                     /* This item is directory. */
00078                     if ((chk_dep != false) && (scan_data.total_folder < MAX_FOLDER_NUM)) {
00079                         p_item = &scan_data.folder_list[scan_data.total_folder];
00080                         chk = regist_item(p_item, p_name, i);
00081                         if (chk != false) {
00082                             /* Register of directory item was success. */
00083                             scan_data.total_folder++;
00084                         }
00085                     }
00086                 } else {
00087                     /* This item is file. */
00088                     chk = check_extension(p_name, pp_extension_tbl);
00089                     if ((chk != false) && (scan_data.total_file < MAX_TRACK_NUM)) {
00090                         /* This item is requested file. */
00091                         p_item = &scan_data.track_list[scan_data.total_file];
00092                         chk = regist_item(p_item, p_name, i);
00093                         if (chk != false) {
00094                             /* Register of file item was success. */
00095                             scan_data.total_file++;
00096                         }
00097                     }
00098                 }
00099                 Thread::wait(SCAN_WAIT_TIME_MS);
00100             }
00101         }
00102     }
00103     /* Changes the identifier of the root directory to use fopen(). */
00104     (void) regist_item(&scan_data.folder_list[0], p_root_name, FOLD_ID_NOT_EXIST);
00105 
00106     if (scan_data.total_file > 0u) {
00107         ret = true;
00108     }
00109 
00110     return ret;
00111 }
00112 
00113 FILE * ScanFolder::open(const uint32_t track_id) {
00114     FILE            *fp = NULL;
00115     const char_t    *p_path;
00116     size_t          path_len;
00117 
00118     if (track_id < scan_data.total_file) {
00119         p_path = get_full_path(&scan_data.track_list[track_id]);
00120         if (p_path != NULL) {
00121             path_len = strlen(p_path); 
00122             /* File path maximum length is limited by the specification of "fopen". */
00123             if (path_len < FILE_PATH_MAX_SIZE) {
00124                 fp = fopen(p_path, OPEN_MODE_READ_ONLY);
00125             }
00126         }
00127     }
00128     return fp;
00129 }
00130 
00131 void ScanFolder::close(FILE * const fp) {
00132     if (fp != NULL) {
00133         (void) fclose(fp);
00134     }
00135 }
00136 
00137 const char_t * ScanFolder::getFileName(const uint32_t track_id) {
00138     const char_t    *p_name = NULL;
00139 
00140     if (track_id < scan_data.total_file) {
00141         p_name = &scan_data.track_list[track_id].name[0];
00142     }
00143     return p_name;
00144 }
00145 
00146 uint32_t ScanFolder::getTotalFile() {
00147     uint32_t        ret;
00148 
00149     ret = scan_data.total_file;
00150     return ret;
00151 }
00152 
00153 /** Gets the full path
00154  *
00155  *  @param p_item Pointer to the item structure of the folder / track.
00156  *
00157  *  @returns 
00158  *    Pointer to the full path.
00159  */
00160 const char_t * ScanFolder::get_full_path(const item_t * const p_item) {
00161     const char_t    *p_path = NULL;
00162     const item_t    *p;
00163     const item_t    *item_list[MAX_FOLDER_DEPTH];
00164     uint32_t        i;
00165     uint32_t        item_cnt;
00166     uint32_t        buf_cnt;
00167     uint32_t        len;
00168     bool            err;
00169 
00170     if (p_item != NULL) {
00171         for (i = 0; i < MAX_FOLDER_DEPTH; i++) {
00172             item_list[i] = NULL;
00173         }
00174         scan_data.work_buf[0] = '\0';
00175 
00176         /* Stores the item name until the root folder. */
00177         p = p_item;
00178         item_cnt = 0;
00179         while ((item_cnt < MAX_FOLDER_DEPTH) && 
00180                (p->parent_number < scan_data.total_folder)) {
00181             item_list[item_cnt] = p;
00182             item_cnt++;
00183             p = &scan_data.folder_list[p->parent_number];
00184         } 
00185         if (p->parent_number == FOLD_ID_NOT_EXIST) {
00186             buf_cnt = strlen(p->name);
00187             (void) strncpy(&scan_data.work_buf[0], p->name, sizeof(scan_data.work_buf));
00188             err = false;
00189             while ((item_cnt > 0u) && (err != true)) {
00190                 item_cnt--;
00191                 p = item_list[item_cnt];
00192                 /* Concatenates SOLIDUS character to the "work_buf" variable. */
00193                 if ((buf_cnt + 1u) < sizeof(scan_data.work_buf)) {
00194                     scan_data.work_buf[buf_cnt] = CHR_SOLIDUS;
00195                     buf_cnt++;
00196                 } else {
00197                     err = true;
00198                 }
00199                 /* Concatenates the item name to the "work_buf" variable. */
00200                 if (p != NULL) {
00201                     len = strlen(p->name);
00202                     if ((buf_cnt + len) < sizeof(scan_data.work_buf)) {
00203                         (void) strncpy(&scan_data.work_buf[buf_cnt], p->name, len);
00204                         buf_cnt += len;
00205                     } else {
00206                         err = true;
00207                     }
00208                 }
00209             }
00210             if (err != true) {
00211                 scan_data.work_buf[buf_cnt] = '\0';
00212                 p_path = &scan_data.work_buf[0];
00213             }
00214         }
00215     }
00216     return p_path;
00217 }
00218 
00219 /** Opens the directory
00220  *
00221  *  @param p_item Pointer to the item structure of the folder / track.
00222  *  @param p_fdir Pointer to the structure to store the directory object.
00223  *
00224  *  @returns 
00225  *    Results of process. true is success. false is failure.
00226  */
00227 bool ScanFolder::open_dir(const item_t * const p_item, FATFS_DIR * const p_fdir) {
00228     bool            ret = false;
00229     const char_t    *p_path;
00230     FRESULT         ferr;
00231 
00232     if ((p_item != NULL) && (p_fdir != NULL)) {
00233         p_path = get_full_path(p_item);
00234         if (p_path != NULL) {
00235             ferr = f_opendir(p_fdir, p_path);
00236             if (ferr == FR_OK) {
00237                 ret = true;
00238             }
00239         }
00240     }
00241     return ret;
00242 }
00243 
00244 /** Reads the directory
00245  *
00246  *  @param p_fdir Pointer to the structure of the directory object.
00247  *  @param p_flag_dir Pointer to the variable to store the directory flag.
00248  *
00249  *  @returns 
00250  *    Pointer to the name.
00251  */
00252 bool ScanFolder::read_dir(FATFS_DIR * const p_fdir,  const char_t ** const p_name, bool * const p_flag_dir) {
00253     bool            ret = false;
00254     FRESULT         ferr;
00255     FILINFO         finfo;
00256 
00257     if ((p_fdir != NULL) && 
00258         (p_name != NULL) && (p_flag_dir != NULL)) {
00259         /* Sets the buffer to store the long file name. */
00260         finfo.lfname = &scan_data.work_buf[0];
00261         finfo.lfsize = sizeof(scan_data.work_buf);
00262         ferr = f_readdir(p_fdir, &finfo);
00263         if ((ferr == FR_OK) && ((int32_t)finfo.fname[0] != '\0')) {
00264             if (finfo.lfname != NULL) {
00265                 if ((int32_t)finfo.lfname[0] == '\0') {
00266                     /* Long file name does not exist. */
00267                     (void) strncpy(finfo.lfname, finfo.fname, finfo.lfsize);
00268                 }
00269                 /* Adds the NULL terminal character. */
00270                 /* This is fail-safe processing. */
00271                 finfo.lfname[finfo.lfsize - 1u] = '\0';
00272 
00273                 ret = true;
00274                 *p_name = finfo.lfname;
00275                 if ((finfo.fattrib & AM_DIR) != 0) {
00276                     /* This item is directory. */
00277                     *p_flag_dir = true;
00278                 } else {
00279                     /* This item is file. */
00280                     *p_flag_dir = false;
00281                 }
00282             }
00283         }
00284     }
00285     return ret;
00286 }
00287 
00288 /** Registers the item of the folder / track
00289  *
00290  *  @param p_item Pointer to the structure to store the item of the folder / track.
00291  *  @param p_name Pointer to the name of the item.
00292  *  @param parent Number of the parent folder of the item.
00293  *
00294  *  @returns 
00295  *    Results of process. true is success. false is failure.
00296  */
00297 bool ScanFolder::regist_item(item_t * const p_item, const char_t * const p_name, const uint32_t parent) {
00298     bool        ret = false;
00299     uint32_t    len;
00300 
00301     if ((p_item != NULL) && (p_name != NULL)) {
00302         len = strlen(p_name);
00303         if ((len + 1u) < sizeof(p_item->name)) {
00304             (void) strncpy(p_item->name, p_name, sizeof(p_item->name));
00305             p_item->name[sizeof(p_item->name) - 1u] = '\0';
00306             p_item->parent_number = parent;
00307             ret = true;
00308         }
00309     }
00310     return ret;
00311 }
00312 
00313 /** Checks the extension of the track name
00314  *
00315  *  @param p_name Pointer to the name of the track.
00316  *
00317  *  @returns 
00318  *    Results of the checking. true is requested file. false is other file.
00319  */
00320 bool ScanFolder::check_extension(const char_t * const p_name, const char_t ** pp_extension_tbl) {
00321     bool            ret = false;
00322     const char_t    *p;
00323     size_t          extension_len;
00324     const char_t *  p_extension;
00325 
00326     if (p_name != NULL) {
00327         p = strrchr(p_name, CHR_FULL_STOP);
00328         if (p != NULL) {
00329             while (1) {
00330                 p_extension = *(pp_extension_tbl++);
00331                 if (p_extension != NULL) {
00332                     extension_len = strlen(p_extension);
00333                     if (strncasecmp(p, p_extension, extension_len) == 0) {
00334                         ret = true;
00335                         break;
00336                     }
00337                 } else {
00338                     break;
00339                 }
00340             }
00341         }
00342     }
00343     return ret;
00344 }
00345 
00346 /** Checks the folder depth in the scan range
00347  *
00348  *  @param folder_id Folder ID [0 - (total folder - 1)]
00349  *
00350  *  @returns 
00351  *    Results of the checking. true is the scan range. false is out of a scan range.
00352  */
00353 bool ScanFolder::check_folder_depth(const uint32_t folder_id) {
00354     bool            ret = false;
00355     uint32_t        depth;
00356     uint32_t        parent_id;
00357 
00358     /* Counts the folder depth. */
00359     parent_id = folder_id;
00360     depth = 0u;
00361     while ((depth < MAX_FOLDER_DEPTH) && 
00362            (parent_id < scan_data.total_folder)) {
00363         depth++;
00364         parent_id = scan_data.folder_list[parent_id].parent_number;
00365     } 
00366     if (parent_id == FOLD_ID_NOT_EXIST) {
00367         /* Found the root folder. */
00368         if (depth < MAX_FOLDER_DEPTH) {
00369             ret = true;
00370         }
00371     }
00372     return ret;
00373 }