filetypes.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. /* sd2snes - SD card based universal cartridge for the SNES
  2. Copyright (C) 2009-2010 Maximilian Rehkopf <otakon@gmx.net>
  3. AVR firmware portion
  4. Inspired by and based on code from sd2iec, written by Ingo Korb et al.
  5. See sdcard.c|h, config.h.
  6. FAT file system access based on code by ChaN, Jim Brain, Ingo Korb,
  7. see ff.c|h.
  8. This program is free software; you can redistribute it and/or modify
  9. it under the terms of the GNU General Public License as published by
  10. the Free Software Foundation; version 2 of the License only.
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. GNU General Public License for more details.
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  18. filetypes.c: directory scanning and file type detection
  19. */
  20. #include <string.h>
  21. #include "config.h"
  22. #include "uart.h"
  23. #include "filetypes.h"
  24. #include "ff.h"
  25. #include "smc.h"
  26. #include "fileops.h"
  27. #include "crc32.h"
  28. #include "memory.h"
  29. #include "led.h"
  30. #include "sort.h"
  31. uint16_t scan_flat(const char* path) {
  32. DIR dir;
  33. FRESULT res;
  34. FILINFO fno;
  35. fno.lfname = NULL;
  36. res = f_opendir(&dir, (TCHAR*)path);
  37. uint16_t numentries = 0;
  38. if (res == FR_OK) {
  39. for (;;) {
  40. res = f_readdir(&dir, &fno);
  41. if(res != FR_OK || fno.fname[0] == 0)break;
  42. numentries++;
  43. }
  44. }
  45. return numentries;
  46. }
  47. uint32_t scan_dir(char* path, FILINFO* fno_param, char mkdb, uint32_t this_dir_tgt) {
  48. DIR dir;
  49. FILINFO fno;
  50. FRESULT res;
  51. uint8_t len;
  52. TCHAR* fn;
  53. static unsigned char depth = 0;
  54. static uint32_t crc;
  55. static uint32_t db_tgt;
  56. static uint32_t next_subdir_tgt;
  57. static uint32_t parent_tgt;
  58. static uint32_t dir_end = 0;
  59. static uint8_t was_empty = 0;
  60. static uint16_t num_files_total = 0;
  61. static uint16_t num_dirs_total = 0;
  62. uint32_t dir_tgt;
  63. uint16_t numentries;
  64. uint32_t dirsize;
  65. uint8_t pass = 0;
  66. char buf[7];
  67. char *size_units[3] = {" ", "k", "M"};
  68. uint32_t entry_fsize;
  69. uint8_t entry_unit_idx;
  70. dir_tgt = this_dir_tgt;
  71. if(depth==0) {
  72. crc = 0;
  73. db_tgt = SRAM_DB_ADDR+0x10;
  74. dir_tgt = SRAM_DIR_ADDR;
  75. next_subdir_tgt = SRAM_DIR_ADDR;
  76. this_dir_tgt = SRAM_DIR_ADDR;
  77. parent_tgt = 0;
  78. printf("root dir @%lx\n", dir_tgt);
  79. }
  80. fno.lfsize = 255;
  81. fno.lfname = (TCHAR*)file_lfn;
  82. numentries=0;
  83. for(pass = 0; pass < 2; pass++) {
  84. if(pass) {
  85. num_dirs_total++;
  86. dirsize = 4*(numentries);
  87. next_subdir_tgt += dirsize + 4;
  88. if(parent_tgt) next_subdir_tgt += 4;
  89. if(next_subdir_tgt > dir_end) {
  90. dir_end = next_subdir_tgt;
  91. }
  92. // printf("path=%s depth=%d ptr=%lx entries=%d parent=%lx next subdir @%lx\n", path, depth, db_tgt, numentries, parent_tgt, next_subdir_tgt);
  93. if(mkdb) {
  94. // printf("d=%d Saving %lx to Address %lx [end]\n", depth, 0L, next_subdir_tgt - 4);
  95. sram_writelong(0L, next_subdir_tgt - 4);
  96. }
  97. }
  98. if(fno_param) {
  99. res = dir_open_by_filinfo(&dir, fno_param);
  100. } else {
  101. res = f_opendir(&dir, path);
  102. }
  103. if (res == FR_OK) {
  104. if(pass && parent_tgt && mkdb) {
  105. /* write backlink to parent dir
  106. switch to next bank if record does not fit in current bank */
  107. if((db_tgt&0xffff) > ((0x10000-(sizeof(next_subdir_tgt)+sizeof(len)+4))&0xffff)) {
  108. printf("switch! old=%lx ", db_tgt);
  109. db_tgt &= 0xffff0000;
  110. db_tgt += 0x00010000;
  111. printf("new=%lx\n", db_tgt);
  112. }
  113. // printf("writing link to parent, %lx to address %lx [../]\n", parent_tgt-SRAM_MENU_ADDR, db_tgt);
  114. sram_writelong((parent_tgt-SRAM_MENU_ADDR), db_tgt);
  115. sram_writebyte(0, db_tgt+sizeof(next_subdir_tgt));
  116. sram_writeblock("../\0", db_tgt+sizeof(next_subdir_tgt)+sizeof(len), 4);
  117. sram_writelong((db_tgt-SRAM_MENU_ADDR)|((uint32_t)0x81<<24), dir_tgt);
  118. db_tgt += sizeof(next_subdir_tgt)+sizeof(len)+4;
  119. dir_tgt += 4;
  120. }
  121. len = strlen((char*)path);
  122. for (;;) {
  123. // toggle_read_led();
  124. res = f_readdir(&dir, &fno);
  125. if (res != FR_OK || fno.fname[0] == 0) {
  126. if(pass) {
  127. if(!numentries) was_empty=1;
  128. }
  129. break;
  130. }
  131. fn = *fno.lfname ? fno.lfname : fno.fname;
  132. if ((*fn == '.') || !(memcmp(fn, SYS_DIR_NAME, sizeof(SYS_DIR_NAME)))) continue;
  133. if (fno.fattrib & AM_DIR) {
  134. depth++;
  135. if(depth < FS_MAX_DEPTH) {
  136. numentries++;
  137. if(pass) {
  138. path[len]='/';
  139. strncpy(path+len+1, (char*)fn, sizeof(fs_path)-len);
  140. if(mkdb) {
  141. uint16_t pathlen = strlen(path);
  142. // printf("d=%d Saving %lx to Address %lx [dir]\n", depth, db_tgt, dir_tgt);
  143. /* save element:
  144. - path name
  145. - pointer to sub dir structure */
  146. if((db_tgt&0xffff) > ((0x10000-(sizeof(next_subdir_tgt) + sizeof(len) + pathlen + 2))&0xffff)) {
  147. printf("switch! old=%lx ", db_tgt);
  148. db_tgt &= 0xffff0000;
  149. db_tgt += 0x00010000;
  150. printf("new=%lx\n", db_tgt);
  151. }
  152. // printf(" Saving dir descriptor to %lx tgt=%lx, path=%s\n", db_tgt, next_subdir_tgt, path);
  153. /* write element pointer to current dir structure */
  154. sram_writelong((db_tgt-SRAM_MENU_ADDR)|((uint32_t)0x80<<24), dir_tgt);
  155. /* save element:
  156. - path name
  157. - pointer to sub dir structure */
  158. sram_writelong((next_subdir_tgt-SRAM_MENU_ADDR), db_tgt);
  159. sram_writebyte(len+1, db_tgt+sizeof(next_subdir_tgt));
  160. sram_writeblock(path, db_tgt+sizeof(next_subdir_tgt)+sizeof(len), pathlen);
  161. sram_writeblock("/\0", db_tgt + sizeof(next_subdir_tgt) + sizeof(len) + pathlen, 2);
  162. db_tgt += sizeof(next_subdir_tgt) + sizeof(len) + pathlen + 2;
  163. }
  164. parent_tgt = this_dir_tgt;
  165. scan_dir(path, &fno, mkdb, next_subdir_tgt);
  166. dir_tgt += 4;
  167. was_empty = 0;
  168. }
  169. }
  170. depth--;
  171. path[len]=0;
  172. } else {
  173. SNES_FTYPE type = determine_filetype((char*)fn);
  174. if(type != TYPE_UNKNOWN) {
  175. num_files_total++;
  176. numentries++;
  177. if(pass) {
  178. if(mkdb) {
  179. /* snes_romprops_t romprops; */
  180. path[len]='/';
  181. strncpy(path+len+1, (char*)fn, sizeof(fs_path)-len);
  182. uint16_t pathlen = strlen(path);
  183. switch(type) {
  184. case TYPE_IPS:
  185. case TYPE_SMC:
  186. /* file_open_by_filinfo(&fno);
  187. if(file_res){
  188. printf("ZOMG NOOOO %d\n", file_res);
  189. }
  190. smc_id(&romprops);
  191. file_close(); */
  192. /* write element pointer to current dir structure */
  193. DBG_FS printf("d=%d Saving %lX to Address %lX [file %s]\n", depth, db_tgt, dir_tgt, path);
  194. if((db_tgt&0xffff) > ((0x10000-(sizeof(len) + pathlen + sizeof(buf)-1 + 1))&0xffff)) {
  195. printf("switch! old=%lx ", db_tgt);
  196. db_tgt &= 0xffff0000;
  197. db_tgt += 0x00010000;
  198. printf("new=%lx\n", db_tgt);
  199. }
  200. sram_writelong((db_tgt-SRAM_MENU_ADDR) | ((uint32_t)type << 24), dir_tgt);
  201. dir_tgt += 4;
  202. /* save element:
  203. - index of last slash character
  204. - file name
  205. - file size */
  206. /* sram_writeblock((uint8_t*)&romprops, db_tgt, sizeof(romprops)); */
  207. entry_fsize = fno.fsize;
  208. entry_unit_idx = 0;
  209. while(entry_fsize > 9999) {
  210. entry_fsize >>= 10;
  211. entry_unit_idx++;
  212. }
  213. snprintf(buf, sizeof(buf), "% 5ld", entry_fsize);
  214. strncat(buf, size_units[entry_unit_idx], 1);
  215. sram_writeblock(buf, db_tgt, sizeof(buf)-1);
  216. sram_writebyte(len+1, db_tgt + sizeof(buf)-1);
  217. sram_writeblock(path, db_tgt + sizeof(len) + sizeof(buf)-1, pathlen + 1);
  218. // sram_writelong(fno.fsize, db_tgt + sizeof(len) + pathlen + 1);
  219. db_tgt += sizeof(len) + pathlen + sizeof(buf)-1 + 1;
  220. break;
  221. case TYPE_UNKNOWN:
  222. default:
  223. break;
  224. }
  225. path[len]=0;
  226. /* printf("%s ", path);
  227. _delay_ms(30); */
  228. }
  229. } else {
  230. TCHAR* fn2 = fn;
  231. while(*fn2 != 0) {
  232. crc += crc32_update(crc, *((unsigned char*)fn2++));
  233. }
  234. }
  235. }
  236. /* printf("%s/%s\n", path, fn);
  237. _delay_ms(50); */
  238. }
  239. }
  240. } else uart_putc(0x30+res);
  241. }
  242. // printf("db_tgt=%lx dir_end=%lx\n", db_tgt, dir_end);
  243. sram_writelong(db_tgt, SRAM_DB_ADDR+4);
  244. sram_writelong(dir_end, SRAM_DB_ADDR+8);
  245. sram_writeshort(num_files_total, SRAM_DB_ADDR+12);
  246. sram_writeshort(num_dirs_total, SRAM_DB_ADDR+14);
  247. return crc;
  248. }
  249. SNES_FTYPE determine_filetype(char* filename) {
  250. char* ext = strrchr(filename, '.');
  251. if(ext == NULL)
  252. return TYPE_UNKNOWN;
  253. if( (!strcasecmp(ext+1, "SMC"))
  254. ||(!strcasecmp(ext+1, "SFC"))
  255. ||(!strcasecmp(ext+1, "FIG"))
  256. ||(!strcasecmp(ext+1, "BS"))
  257. ) {
  258. return TYPE_SMC;
  259. }
  260. if( (!strcasecmp(ext+1, "IPS"))
  261. ||(!strcasecmp(ext+1, "UPS"))
  262. ) {
  263. return TYPE_IPS;
  264. }
  265. /* later
  266. if(!strcasecmp_P(ext+1, PSTR("SRM"))) {
  267. return TYPE_SRM;
  268. }
  269. if(!strcasecmp_P(ext+1, PSTR("SPC"))) {
  270. return TYPE_SPC;
  271. }*/
  272. return TYPE_UNKNOWN;
  273. }
  274. FRESULT get_db_id(uint32_t* id) {
  275. file_open((uint8_t*)"/sd2snes/sd2snes.db", FA_READ);
  276. if(file_res == FR_OK) {
  277. file_readblock(id, 0, 4);
  278. /* XXX */// *id=0xdead;
  279. file_close();
  280. } else {
  281. *id=0xdeadbeef;
  282. }
  283. return file_res;
  284. }
  285. int get_num_dirent(uint32_t addr) {
  286. int result = 0;
  287. while(sram_readlong(addr+result*4)) {
  288. result++;
  289. }
  290. return result;
  291. }
  292. void sort_all_dir(uint32_t endaddr) {
  293. uint32_t entries = 0;
  294. uint32_t current_base = SRAM_DIR_ADDR;
  295. while(current_base<(endaddr)) {
  296. while(sram_readlong(current_base+entries*4)) {
  297. entries++;
  298. }
  299. printf("sorting dir @%lx, entries: %ld\n", current_base, entries);
  300. sort_dir(current_base, entries);
  301. current_base += 4*entries + 4;
  302. entries = 0;
  303. }
  304. }