task_database.c 40 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397
  1. /* RetroArch - A frontend for libretro.
  2. * Copyright (C) 2011-2017 - Daniel De Matteis
  3. * Copyright (C) 2014-2017 - Jean-André Santoni
  4. * Copyright (C) 2016-2019 - Brad Parker
  5. *
  6. * RetroArch is free software: you can redistribute it and/or modify it under the terms
  7. * of the GNU General Public License as published by the Free Software Found-
  8. * ation, either version 3 of the License, or (at your option) any later version.
  9. *
  10. * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
  11. * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  12. * PURPOSE. See the GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License along with RetroArch.
  15. * If not, see <http://www.gnu.org/licenses/>.
  16. */
  17. #include <math.h>
  18. #include <compat/strcasestr.h>
  19. #include <compat/strl.h>
  20. #include <retro_miscellaneous.h>
  21. #include <retro_endianness.h>
  22. #include <string/stdstring.h>
  23. #include <lists/dir_list.h>
  24. #include <file/file_path.h>
  25. #include <encodings/crc32.h>
  26. #include <streams/file_stream.h>
  27. #include <streams/chd_stream.h>
  28. #include <streams/interface_stream.h>
  29. #include "tasks_internal.h"
  30. #include "../core_info.h"
  31. #include "../database_info.h"
  32. #include "../file_path_special.h"
  33. #include "../msg_hash.h"
  34. #ifdef HAVE_PLAYLIST
  35. #include "../playlist.h"
  36. #endif
  37. #ifdef RARCH_INTERNAL
  38. #include "../configuration.h"
  39. #include "../ui/ui_companion_driver.h"
  40. #include "../gfx/video_display_server.h"
  41. #endif
  42. #include "../retroarch.h"
  43. #include "../verbosity.h"
  44. #include "task_database_cue.h"
  45. typedef struct database_state_handle
  46. {
  47. database_info_list_t *info;
  48. struct string_list *list;
  49. uint8_t *buf;
  50. size_t list_index;
  51. size_t entry_index;
  52. uint32_t crc;
  53. uint32_t archive_crc;
  54. char archive_name[511];
  55. char serial[4096];
  56. } database_state_handle_t;
  57. enum db_flags_enum
  58. {
  59. DB_HANDLE_FLAG_IS_DIRECTORY = (1 << 0),
  60. DB_HANDLE_FLAG_SCAN_STARTED = (1 << 1),
  61. DB_HANDLE_FLAG_SCAN_WITHOUT_CORE_MATCH = (1 << 2),
  62. DB_HANDLE_FLAG_SHOW_HIDDEN_FILES = (1 << 3)
  63. };
  64. typedef struct db_handle
  65. {
  66. char *playlist_directory;
  67. char *content_database_path;
  68. char *fullpath;
  69. database_info_handle_t *handle;
  70. database_state_handle_t state;
  71. #ifdef HAVE_PLAYLIST
  72. playlist_config_t playlist_config; /* size_t alignment */
  73. #endif
  74. unsigned status;
  75. uint8_t flags;
  76. } db_handle_t;
  77. static const char *database_info_get_current_name(
  78. database_state_handle_t *handle)
  79. {
  80. if (!handle || !handle->list)
  81. return NULL;
  82. return handle->list->elems[handle->list_index].data;
  83. }
  84. static const char *database_info_get_current_element_name(
  85. database_info_handle_t *handle)
  86. {
  87. if (!handle || !handle->list)
  88. return NULL;
  89. #if 1
  90. /* Don't skip pruned entries, otherwise iteration
  91. * ends prematurely */
  92. if (!handle->list->elems[handle->list_ptr].data)
  93. return "";
  94. #else
  95. /* Skip pruned entries */
  96. while (!handle->list->elems[handle->list_ptr].data)
  97. {
  98. if (++handle->list_ptr >= handle->list->size)
  99. return NULL;
  100. }
  101. #endif
  102. return handle->list->elems[handle->list_ptr].data;
  103. }
  104. static int task_database_iterate_start(retro_task_t *task,
  105. database_info_handle_t *db,
  106. const char *name)
  107. {
  108. char msg[256];
  109. const char *basename_path = !string_is_empty(name)
  110. ? path_basename_nocompression(name) : "";
  111. msg[0] = '\0';
  112. if (!string_is_empty(basename_path))
  113. snprintf(msg, sizeof(msg),
  114. STRING_REP_USIZE "/" STRING_REP_USIZE ": %s..\n",
  115. db->list_ptr + 1,
  116. (size_t)db->list->size,
  117. basename_path);
  118. if (!string_is_empty(msg))
  119. {
  120. #ifdef RARCH_INTERNAL
  121. task_free_title(task);
  122. task_set_title(task, strdup(msg));
  123. if (db->list->size != 0)
  124. task_set_progress(task,
  125. roundf((float)db->list_ptr /
  126. ((float)db->list->size / 100.0f)));
  127. RARCH_LOG("[Scanner]: %s", msg);
  128. if (retroarch_override_setting_is_set(RARCH_OVERRIDE_SETTING_DATABASE_SCAN, NULL))
  129. printf("%s", msg);
  130. #else
  131. fprintf(stderr, "msg: %s\n", msg);
  132. #endif
  133. }
  134. db->status = DATABASE_STATUS_ITERATE;
  135. return 0;
  136. }
  137. static int intfstream_get_serial(intfstream_t *fd, char *serial, size_t serial_len, const char *filename)
  138. {
  139. const char *system_name = NULL;
  140. if (detect_system(fd, &system_name, filename) >= 1)
  141. {
  142. if (string_is_equal(system_name, "Sony - PlayStation Portable"))
  143. {
  144. if (detect_psp_game(fd, serial, serial_len, filename) != 0)
  145. return 1;
  146. }
  147. else if (string_is_equal(system_name, "Sony - PlayStation"))
  148. {
  149. if (detect_ps1_game(fd, serial, serial_len, filename) != 0)
  150. return 1;
  151. }
  152. else if (string_is_equal(system_name, "Sony - PlayStation 2"))
  153. {
  154. if (detect_ps2_game(fd, serial, serial_len, filename) != 0)
  155. return 1;
  156. }
  157. else if (string_is_equal(system_name, "Nintendo - GameCube"))
  158. {
  159. if (detect_gc_game(fd, serial, serial_len, filename) != 0)
  160. return 1;
  161. }
  162. else if (string_is_equal(system_name, "Sega - Mega-CD - Sega CD"))
  163. {
  164. if (detect_scd_game(fd, serial, serial_len, filename) != 0)
  165. return 1;
  166. }
  167. else if (string_is_equal(system_name, "Sega - Saturn"))
  168. {
  169. if (detect_sat_game(fd, serial, serial_len, filename) != 0)
  170. return 1;
  171. }
  172. else if (string_is_equal(system_name, "Sega - Dreamcast"))
  173. {
  174. if (detect_dc_game(fd, serial, serial_len, filename) != 0)
  175. return 1;
  176. }
  177. else if (string_is_equal(system_name, "Nintendo - Wii"))
  178. {
  179. if (detect_wii_game(fd, serial, serial_len, filename) != 0)
  180. return 1;
  181. }
  182. }
  183. return 0;
  184. }
  185. static bool intfstream_file_get_serial(const char *name,
  186. uint64_t offset, uint64_t size, char *serial, size_t serial_len)
  187. {
  188. int rv;
  189. uint8_t *data = NULL;
  190. int64_t file_size = -1;
  191. intfstream_t *fd = intfstream_open_file(name,
  192. RETRO_VFS_FILE_ACCESS_READ, RETRO_VFS_FILE_ACCESS_HINT_NONE);
  193. if (!fd)
  194. return 0;
  195. if (intfstream_seek(fd, 0, SEEK_END) == -1)
  196. goto error;
  197. file_size = intfstream_tell(fd);
  198. if (intfstream_seek(fd, 0, SEEK_SET) == -1)
  199. goto error;
  200. if (file_size < 0)
  201. goto error;
  202. if (offset != 0 || size < (uint64_t) file_size)
  203. {
  204. if (intfstream_seek(fd, (int64_t)offset, SEEK_SET) == -1)
  205. goto error;
  206. data = (uint8_t*)malloc((size_t)size);
  207. if (intfstream_read(fd, data, size) != (int64_t) size)
  208. {
  209. free(data);
  210. goto error;
  211. }
  212. intfstream_close(fd);
  213. free(fd);
  214. if (!(fd = intfstream_open_memory(data, RETRO_VFS_FILE_ACCESS_READ,
  215. RETRO_VFS_FILE_ACCESS_HINT_NONE,
  216. size)))
  217. {
  218. free(data);
  219. return 0;
  220. }
  221. }
  222. rv = intfstream_get_serial(fd, serial, serial_len, name);
  223. intfstream_close(fd);
  224. free(fd);
  225. free(data);
  226. return rv;
  227. error:
  228. intfstream_close(fd);
  229. free(fd);
  230. return 0;
  231. }
  232. static int task_database_cue_get_serial(const char *name, char* serial, size_t serial_len)
  233. {
  234. char track_path[PATH_MAX_LENGTH];
  235. uint64_t offset = 0;
  236. uint64_t size = 0;
  237. track_path[0] = '\0';
  238. if (cue_find_track(name, true, &offset, &size, track_path,
  239. sizeof(track_path)) < 0)
  240. {
  241. #ifdef DEBUG
  242. RARCH_LOG("%s\n",
  243. msg_hash_to_str(MSG_COULD_NOT_FIND_VALID_DATA_TRACK));
  244. #endif
  245. return 0;
  246. }
  247. return intfstream_file_get_serial(track_path, offset, size, serial, serial_len);
  248. }
  249. static int task_database_gdi_get_serial(const char *name, char* serial, size_t serial_len)
  250. {
  251. char track_path[PATH_MAX_LENGTH];
  252. track_path[0] = '\0';
  253. if (gdi_find_track(name, true,
  254. track_path, sizeof(track_path)) < 0)
  255. {
  256. #ifdef DEBUG
  257. RARCH_LOG("%s\n",
  258. msg_hash_to_str(MSG_COULD_NOT_FIND_VALID_DATA_TRACK));
  259. #endif
  260. return 0;
  261. }
  262. return intfstream_file_get_serial(track_path, 0, SIZE_MAX, serial, serial_len);
  263. }
  264. static int task_database_chd_get_serial(const char *name, char* serial, size_t serial_len)
  265. {
  266. int result;
  267. intfstream_t *fd = intfstream_open_chd_track(
  268. name,
  269. RETRO_VFS_FILE_ACCESS_READ,
  270. RETRO_VFS_FILE_ACCESS_HINT_NONE,
  271. CHDSTREAM_TRACK_FIRST_DATA);
  272. if (!fd)
  273. return 0;
  274. result = intfstream_get_serial(fd, serial, serial_len, name);
  275. intfstream_close(fd);
  276. free(fd);
  277. return result;
  278. }
  279. static bool intfstream_file_get_crc(const char *name,
  280. uint64_t offset, size_t size, uint32_t *crc)
  281. {
  282. bool rv;
  283. intfstream_t *fd = intfstream_open_file(name,
  284. RETRO_VFS_FILE_ACCESS_READ, RETRO_VFS_FILE_ACCESS_HINT_NONE);
  285. uint8_t *data = NULL;
  286. int64_t file_size = -1;
  287. if (!fd)
  288. return 0;
  289. if (intfstream_seek(fd, 0, SEEK_END) == -1)
  290. goto error;
  291. file_size = intfstream_tell(fd);
  292. if (intfstream_seek(fd, 0, SEEK_SET) == -1)
  293. goto error;
  294. if (file_size < 0)
  295. goto error;
  296. if (offset != 0 || size < (uint64_t) file_size)
  297. {
  298. if (intfstream_seek(fd, (int64_t)offset, SEEK_SET) == -1)
  299. goto error;
  300. data = (uint8_t*)malloc(size);
  301. if (intfstream_read(fd, data, size) != (int64_t) size)
  302. goto error;
  303. intfstream_close(fd);
  304. free(fd);
  305. fd = intfstream_open_memory(data, RETRO_VFS_FILE_ACCESS_READ,
  306. RETRO_VFS_FILE_ACCESS_HINT_NONE, size);
  307. if (!fd)
  308. goto error;
  309. }
  310. rv = intfstream_get_crc(fd, crc);
  311. intfstream_close(fd);
  312. free(fd);
  313. free(data);
  314. return rv;
  315. error:
  316. if (fd)
  317. {
  318. intfstream_close(fd);
  319. free(fd);
  320. }
  321. if (data)
  322. free(data);
  323. return 0;
  324. }
  325. static int task_database_cue_get_crc(const char *name, uint32_t *crc)
  326. {
  327. char track_path[PATH_MAX_LENGTH];
  328. uint64_t offset = 0;
  329. uint64_t size = 0;
  330. track_path[0] = '\0';
  331. if (cue_find_track(name, false, &offset, &size,
  332. track_path, sizeof(track_path)) < 0)
  333. {
  334. #ifdef DEBUG
  335. RARCH_LOG("%s\n",
  336. msg_hash_to_str(MSG_COULD_NOT_FIND_VALID_DATA_TRACK));
  337. #endif
  338. return 0;
  339. }
  340. return intfstream_file_get_crc(track_path, offset, (size_t)size, crc);
  341. }
  342. static int task_database_gdi_get_crc(const char *name, uint32_t *crc)
  343. {
  344. char track_path[PATH_MAX_LENGTH];
  345. track_path[0] = '\0';
  346. if (gdi_find_track(name, true,
  347. track_path, sizeof(track_path)) < 0)
  348. {
  349. #ifdef DEBUG
  350. RARCH_LOG("%s\n",
  351. msg_hash_to_str(MSG_COULD_NOT_FIND_VALID_DATA_TRACK));
  352. #endif
  353. return 0;
  354. }
  355. return intfstream_file_get_crc(track_path, 0, SIZE_MAX, crc);
  356. }
  357. static bool task_database_chd_get_crc(const char *name, uint32_t *crc)
  358. {
  359. bool found_crc = false;
  360. intfstream_t *fd = intfstream_open_chd_track(
  361. name,
  362. RETRO_VFS_FILE_ACCESS_READ,
  363. RETRO_VFS_FILE_ACCESS_HINT_NONE,
  364. CHDSTREAM_TRACK_PRIMARY);
  365. if (!fd)
  366. return 0;
  367. found_crc = intfstream_get_crc(fd, crc);
  368. if (fd)
  369. {
  370. intfstream_close(fd);
  371. free(fd);
  372. }
  373. return found_crc;
  374. }
  375. static void task_database_cue_prune(database_info_handle_t *db,
  376. const char *name)
  377. {
  378. size_t i;
  379. char path[PATH_MAX_LENGTH];
  380. intfstream_t *fd = intfstream_open_file(name,
  381. RETRO_VFS_FILE_ACCESS_READ, RETRO_VFS_FILE_ACCESS_HINT_NONE);
  382. if (!fd)
  383. return;
  384. path[0] = '\0';
  385. while (cue_next_file(fd, name, path, sizeof(path)))
  386. {
  387. for (i = db->list_ptr; i < db->list->size; ++i)
  388. {
  389. if (db->list->elems[i].data
  390. && string_is_equal(path, db->list->elems[i].data))
  391. {
  392. #ifdef DEBUG
  393. RARCH_LOG("Pruning file referenced by cue: %s\n", path);
  394. #endif
  395. free(db->list->elems[i].data);
  396. db->list->elems[i].data = NULL;
  397. }
  398. }
  399. }
  400. intfstream_close(fd);
  401. free(fd);
  402. }
  403. static void gdi_prune(database_info_handle_t *db, const char *name)
  404. {
  405. size_t i;
  406. char path[PATH_MAX_LENGTH];
  407. intfstream_t *fd = intfstream_open_file(name,
  408. RETRO_VFS_FILE_ACCESS_READ, RETRO_VFS_FILE_ACCESS_HINT_NONE);
  409. if (!fd)
  410. return;
  411. path[0] = '\0';
  412. while (gdi_next_file(fd, name, path, sizeof(path)))
  413. {
  414. for (i = db->list_ptr; i < db->list->size; ++i)
  415. {
  416. if (db->list->elems[i].data
  417. && string_is_equal(path, db->list->elems[i].data))
  418. {
  419. RARCH_LOG("Pruning file referenced by gdi: %s\n", path);
  420. free(db->list->elems[i].data);
  421. db->list->elems[i].data = NULL;
  422. }
  423. }
  424. }
  425. free(fd);
  426. }
  427. static enum msg_file_type extension_to_file_type(const char *ext)
  428. {
  429. char ext_lower[6];
  430. /* Copy and convert to lower case */
  431. strlcpy(ext_lower, ext, sizeof(ext_lower));
  432. string_to_lower(ext_lower);
  433. if (
  434. string_is_equal(ext_lower, "7z") ||
  435. string_is_equal(ext_lower, "zip") ||
  436. string_is_equal(ext_lower, "apk")
  437. )
  438. return FILE_TYPE_COMPRESSED;
  439. if (
  440. string_is_equal(ext_lower, "cue")
  441. )
  442. return FILE_TYPE_CUE;
  443. if (
  444. string_is_equal(ext_lower, "gdi")
  445. )
  446. return FILE_TYPE_GDI;
  447. if (
  448. string_is_equal(ext_lower, "iso")
  449. )
  450. return FILE_TYPE_ISO;
  451. if (
  452. string_is_equal(ext_lower, "chd")
  453. )
  454. return FILE_TYPE_CHD;
  455. if (
  456. string_is_equal(ext_lower, "wbfs")
  457. )
  458. return FILE_TYPE_WBFS;
  459. if (
  460. string_is_equal(ext_lower, "rvz")
  461. )
  462. return FILE_TYPE_RVZ;
  463. if (
  464. string_is_equal(ext_lower, "wia")
  465. )
  466. return FILE_TYPE_WIA;
  467. if (
  468. string_is_equal(ext_lower, "lutro")
  469. )
  470. return FILE_TYPE_LUTRO;
  471. return FILE_TYPE_NONE;
  472. }
  473. static int task_database_iterate_playlist(
  474. database_state_handle_t *db_state,
  475. database_info_handle_t *db, const char *name)
  476. {
  477. switch (extension_to_file_type(path_get_extension(name)))
  478. {
  479. case FILE_TYPE_COMPRESSED:
  480. #ifdef HAVE_COMPRESSION
  481. db->type = DATABASE_TYPE_CRC_LOOKUP;
  482. /* first check crc of archive itself */
  483. return intfstream_file_get_crc(name,
  484. 0, SIZE_MAX, &db_state->archive_crc);
  485. #else
  486. break;
  487. #endif
  488. case FILE_TYPE_CUE:
  489. task_database_cue_prune(db, name);
  490. db_state->serial[0] = '\0';
  491. if (task_database_cue_get_serial(name, db_state->serial, sizeof(db_state->serial)))
  492. db->type = DATABASE_TYPE_SERIAL_LOOKUP;
  493. else
  494. {
  495. db->type = DATABASE_TYPE_CRC_LOOKUP;
  496. return task_database_cue_get_crc(name, &db_state->crc);
  497. }
  498. break;
  499. case FILE_TYPE_GDI:
  500. gdi_prune(db, name);
  501. db_state->serial[0] = '\0';
  502. /* There are no serial databases, so don't bother with
  503. serials at the moment */
  504. if (0 && task_database_gdi_get_serial(name, db_state->serial, sizeof(db_state->serial)))
  505. db->type = DATABASE_TYPE_SERIAL_LOOKUP;
  506. else
  507. {
  508. db->type = DATABASE_TYPE_CRC_LOOKUP;
  509. return task_database_gdi_get_crc(name, &db_state->crc);
  510. }
  511. break;
  512. /* Consider WBFS, RVZ and WIA files similar to ISO files. */
  513. case FILE_TYPE_WBFS:
  514. case FILE_TYPE_RVZ:
  515. case FILE_TYPE_WIA:
  516. case FILE_TYPE_ISO:
  517. db_state->serial[0] = '\0';
  518. intfstream_file_get_serial(name, 0, SIZE_MAX, db_state->serial, sizeof(db_state->serial));
  519. db->type = DATABASE_TYPE_SERIAL_LOOKUP;
  520. break;
  521. case FILE_TYPE_CHD:
  522. db_state->serial[0] = '\0';
  523. if (task_database_chd_get_serial(name, db_state->serial, sizeof(db_state->serial)))
  524. db->type = DATABASE_TYPE_SERIAL_LOOKUP;
  525. else
  526. {
  527. db->type = DATABASE_TYPE_CRC_LOOKUP;
  528. return task_database_chd_get_crc(name, &db_state->crc);
  529. }
  530. break;
  531. case FILE_TYPE_LUTRO:
  532. db->type = DATABASE_TYPE_ITERATE_LUTRO;
  533. break;
  534. default:
  535. db_state->serial[0] = '\0';
  536. db->type = DATABASE_TYPE_CRC_LOOKUP;
  537. return intfstream_file_get_crc(name, 0, SIZE_MAX, &db_state->crc);
  538. }
  539. return 1;
  540. }
  541. static int database_info_list_iterate_end_no_match(
  542. database_info_handle_t *db,
  543. database_state_handle_t *db_state,
  544. const char *path,
  545. bool path_contains_compressed_file)
  546. {
  547. /* Reached end of database list,
  548. * CRC match probably didn't succeed. */
  549. /* If this was a compressed file and no match in the database
  550. * list was found then expand the search list to include the
  551. * archive's contents. */
  552. if (!path_contains_compressed_file && path_is_compressed_file(path))
  553. {
  554. struct string_list *archive_list =
  555. file_archive_get_file_list(path, NULL);
  556. if (archive_list && archive_list->size > 0)
  557. {
  558. unsigned i;
  559. size_t path_len = strlen(path);
  560. for (i = 0; i < archive_list->size; i++)
  561. {
  562. if (path_len + strlen(archive_list->elems[i].data)
  563. + 1 < PATH_MAX_LENGTH)
  564. {
  565. char new_path[PATH_MAX_LENGTH];
  566. strlcpy(new_path, path, sizeof(new_path));
  567. new_path[path_len] = '#';
  568. strlcpy(new_path + path_len + 1,
  569. archive_list->elems[i].data,
  570. sizeof(new_path) - path_len);
  571. string_list_append(db->list, new_path,
  572. archive_list->elems[i].attr);
  573. }
  574. else
  575. string_list_append(db->list, path,
  576. archive_list->elems[i].attr);
  577. }
  578. string_list_free(archive_list);
  579. }
  580. }
  581. db_state->list_index = 0;
  582. db_state->entry_index = 0;
  583. if (db_state->crc != 0)
  584. db_state->crc = 0;
  585. if (db_state->archive_crc != 0)
  586. db_state->archive_crc = 0;
  587. return 0;
  588. }
  589. static int database_info_list_iterate_new(database_state_handle_t *db_state,
  590. const char *query)
  591. {
  592. const char *new_database = database_info_get_current_name(db_state);
  593. #ifndef RARCH_INTERNAL
  594. fprintf(stderr, "Check database [%d/%d] : %s\n",
  595. (unsigned)db_state->list_index,
  596. (unsigned)db_state->list->size, new_database);
  597. #endif
  598. if (db_state->info)
  599. {
  600. database_info_list_free(db_state->info);
  601. free(db_state->info);
  602. }
  603. db_state->info = database_info_list_new(new_database, query);
  604. return 0;
  605. }
  606. static int database_info_list_iterate_found_match(
  607. db_handle_t *_db,
  608. database_state_handle_t *db_state,
  609. database_info_handle_t *db,
  610. const char *archive_name
  611. )
  612. {
  613. /* TODO/FIXME - heap allocations are done here to avoid
  614. * running out of stack space on systems with a limited stack size.
  615. * We should use less fullsize paths in the future so that we don't
  616. * need to have all these big char arrays here */
  617. size_t str_len = PATH_MAX_LENGTH * sizeof(char);
  618. char* db_crc = (char*)malloc(str_len);
  619. char* db_playlist_base_str = (char*)malloc(str_len);
  620. char* db_playlist_path = (char*)malloc(str_len);
  621. char* entry_path_str = (char*)malloc(str_len);
  622. char* entry_label = (char*)malloc(str_len);
  623. char *hash = NULL;
  624. #ifdef HAVE_PLAYLIST
  625. playlist_t *playlist = NULL;
  626. #endif
  627. const char *db_path =
  628. database_info_get_current_name(db_state);
  629. const char *entry_path =
  630. database_info_get_current_element_name(db);
  631. database_info_t *db_info_entry =
  632. &db_state->info->list[db_state->entry_index];
  633. db_crc[0] = '\0';
  634. db_playlist_path[0] = '\0';
  635. entry_path_str[0] = '\0';
  636. fill_pathname(db_playlist_base_str,
  637. path_basename_nocompression(db_path), "", str_len);
  638. path_remove_extension(db_playlist_base_str);
  639. strlcat(db_playlist_base_str, ".lpl", str_len);
  640. if (!string_is_empty(_db->playlist_directory))
  641. fill_pathname_join_special(db_playlist_path, _db->playlist_directory,
  642. db_playlist_base_str, str_len);
  643. #ifdef HAVE_PLAYLIST
  644. playlist_config_set_path(&_db->playlist_config, db_playlist_path);
  645. playlist = playlist_init(&_db->playlist_config);
  646. #endif
  647. if (!string_is_empty(db_state->serial))
  648. {
  649. if (snprintf(db_crc, str_len, "%s|serial", db_state->serial) < 0)
  650. RARCH_ERR("Serial string encoding error\n");
  651. }
  652. else
  653. snprintf(db_crc, str_len, "%08lX|crc", (unsigned long)db_info_entry->crc32);
  654. if (entry_path)
  655. strlcpy(entry_path_str, entry_path, str_len);
  656. /* Use database name for label if found,
  657. * otherwise use filename without extension */
  658. if (!string_is_empty(db_info_entry->name))
  659. strlcpy(entry_label, db_info_entry->name, str_len);
  660. else if (!string_is_empty(entry_path))
  661. {
  662. char *delim = (char*)strchr(entry_path, '#');
  663. if (delim)
  664. *delim = '\0';
  665. fill_pathname(entry_label,
  666. path_basename_nocompression(entry_path), "", str_len);
  667. path_remove_extension(entry_label);
  668. RARCH_LOG("[Scanner]: No match for: \"%s\", CRC: 0x%08X\n", entry_path_str, db_state->crc);
  669. }
  670. if (!string_is_empty(archive_name))
  671. fill_pathname_join_delim(entry_path_str,
  672. entry_path_str, archive_name, '#', str_len);
  673. if (core_info_database_match_archive_member(
  674. db_state->list->elems[db_state->list_index].data) &&
  675. (hash = strchr(entry_path_str, '#')))
  676. *hash = '\0';
  677. #if !defined(RARCH_INTERNAL)
  678. fprintf(stderr, "Found match in database !\n");
  679. fprintf(stderr, "Path: %s\n", db_path);
  680. fprintf(stderr, "CRC : %s\n", db_crc);
  681. fprintf(stderr, "Playlist Path: %s\n", db_playlist_path);
  682. fprintf(stderr, "Entry Path: %s\n", entry_path);
  683. fprintf(stderr, "Playlist not NULL: %d\n", playlist != NULL);
  684. fprintf(stderr, "ZIP entry: %s\n", archive_name);
  685. fprintf(stderr, "entry path str: %s\n", entry_path_str);
  686. #endif
  687. #ifdef HAVE_PLAYLIST
  688. if (!playlist_entry_exists(playlist, entry_path_str))
  689. {
  690. struct playlist_entry entry;
  691. /* the push function reads our entry as const,
  692. * so these casts are safe */
  693. entry.path = entry_path_str;
  694. entry.label = entry_label;
  695. entry.core_path = (char*)"DETECT";
  696. entry.core_name = (char*)"DETECT";
  697. entry.db_name = db_playlist_base_str;
  698. entry.crc32 = db_crc;
  699. entry.subsystem_ident = NULL;
  700. entry.subsystem_name = NULL;
  701. entry.subsystem_roms = NULL;
  702. entry.entry_slot = 0;
  703. entry.runtime_hours = 0;
  704. entry.runtime_minutes = 0;
  705. entry.runtime_seconds = 0;
  706. entry.last_played_year = 0;
  707. entry.last_played_month = 0;
  708. entry.last_played_day = 0;
  709. entry.last_played_hour = 0;
  710. entry.last_played_minute= 0;
  711. entry.last_played_second= 0;
  712. playlist_push(playlist, &entry);
  713. RARCH_LOG("[Scanner]: Add \"%s\"\n", entry_label);
  714. if (retroarch_override_setting_is_set(RARCH_OVERRIDE_SETTING_DATABASE_SCAN, NULL))
  715. printf("Add \"%s\"\n", entry.label);
  716. }
  717. playlist_write_file(playlist);
  718. playlist_free(playlist);
  719. #endif
  720. database_info_list_free(db_state->info);
  721. free(db_state->info);
  722. db_state->info = NULL;
  723. db_state->crc = 0;
  724. db_state->archive_crc = 0;
  725. /* Move database to start since we are likely to match against it
  726. again */
  727. if (db_state->list_index != 0)
  728. {
  729. struct string_list_elem entry =
  730. db_state->list->elems[db_state->list_index];
  731. memmove(&db_state->list->elems[1],
  732. &db_state->list->elems[0],
  733. sizeof(entry) * db_state->list_index);
  734. db_state->list->elems[0] = entry;
  735. }
  736. free(db_crc);
  737. free(db_playlist_base_str);
  738. free(db_playlist_path);
  739. free(entry_path_str);
  740. free(entry_label);
  741. return 0;
  742. }
  743. /* End of entries in database info list and didn't find a
  744. * match, go to the next database. */
  745. static int database_info_list_iterate_next(
  746. database_state_handle_t *db_state)
  747. {
  748. db_state->list_index++;
  749. db_state->entry_index = 0;
  750. database_info_list_free(db_state->info);
  751. free(db_state->info);
  752. db_state->info = NULL;
  753. return 1;
  754. }
  755. static int task_database_iterate_crc_lookup(
  756. db_handle_t *_db,
  757. database_state_handle_t *db_state,
  758. database_info_handle_t *db,
  759. const char *name,
  760. const char *archive_entry,
  761. bool path_contains_compressed_file)
  762. {
  763. if (!db_state->list ||
  764. (unsigned)db_state->list_index == (unsigned)db_state->list->size)
  765. return database_info_list_iterate_end_no_match(db, db_state, name,
  766. path_contains_compressed_file);
  767. /* Archive did not contain a CRC for this entry,
  768. * or the file is empty. */
  769. if (!db_state->crc)
  770. {
  771. db_state->crc = file_archive_get_file_crc32(name);
  772. if (!db_state->crc)
  773. return database_info_list_iterate_next(db_state);
  774. }
  775. if (db_state->entry_index == 0)
  776. {
  777. char query[50];
  778. query[0] = '\0';
  779. if (!(_db->flags & DB_HANDLE_FLAG_SCAN_WITHOUT_CORE_MATCH))
  780. {
  781. /* don't scan files that can't be in this database.
  782. *
  783. * Could be because of:
  784. * - A matching core missing
  785. * - Incompatible file extension */
  786. if (!core_info_database_supports_content_path(
  787. db_state->list->elems[db_state->list_index].data, name))
  788. return database_info_list_iterate_next(db_state);
  789. if (!path_contains_compressed_file)
  790. {
  791. if (core_info_database_match_archive_member(
  792. db_state->list->elems[db_state->list_index].data))
  793. return database_info_list_iterate_next(db_state);
  794. }
  795. }
  796. snprintf(query, sizeof(query),
  797. "{crc:or(b\"%08lX\",b\"%08lX\")}",
  798. (unsigned long)db_state->crc, (unsigned long)db_state->archive_crc);
  799. database_info_list_iterate_new(db_state, query);
  800. }
  801. if (db_state->info)
  802. {
  803. database_info_t *db_info_entry =
  804. &db_state->info->list[db_state->entry_index];
  805. if (db_info_entry && db_info_entry->crc32)
  806. {
  807. if (db_state->archive_crc == db_info_entry->crc32)
  808. return database_info_list_iterate_found_match(
  809. _db,
  810. db_state, db, NULL);
  811. if (db_state->crc == db_info_entry->crc32)
  812. return database_info_list_iterate_found_match(
  813. _db,
  814. db_state, db, archive_entry);
  815. }
  816. }
  817. db_state->entry_index++;
  818. if (db_state->info)
  819. {
  820. if (db_state->entry_index >= db_state->info->count)
  821. return database_info_list_iterate_next(db_state);
  822. }
  823. /* If we haven't reached the end of the database list yet,
  824. * continue iterating. */
  825. if (db_state->list_index < db_state->list->size)
  826. return 1;
  827. database_info_list_free(db_state->info);
  828. if (db_state->info)
  829. free(db_state->info);
  830. return 0;
  831. }
  832. static int task_database_iterate_playlist_lutro(
  833. db_handle_t *_db,
  834. database_state_handle_t *db_state,
  835. database_info_handle_t *db,
  836. const char *path)
  837. {
  838. char db_playlist_path[PATH_MAX_LENGTH];
  839. #ifdef HAVE_PLAYLIST
  840. playlist_t *playlist = NULL;
  841. #endif
  842. db_playlist_path[0] = '\0';
  843. if (!string_is_empty(_db->playlist_directory))
  844. fill_pathname_join_special(db_playlist_path,
  845. _db->playlist_directory,
  846. "Lutro.lpl", sizeof(db_playlist_path));
  847. #ifdef HAVE_PLAYLIST
  848. playlist_config_set_path(&_db->playlist_config, db_playlist_path);
  849. playlist = playlist_init(&_db->playlist_config);
  850. if (!playlist_entry_exists(playlist, path))
  851. {
  852. struct playlist_entry entry;
  853. char game_title[PATH_MAX_LENGTH];
  854. fill_pathname(game_title,
  855. path_basename(path), "", sizeof(game_title));
  856. path_remove_extension(game_title);
  857. /* the push function reads our entry as const,
  858. * so these casts are safe */
  859. entry.path = (char*)path;
  860. entry.label = game_title;
  861. entry.core_path = (char*)"DETECT";
  862. entry.core_name = (char*)"DETECT";
  863. entry.db_name = (char*)"Lutro.lpl";
  864. entry.crc32 = (char*)"DETECT";
  865. entry.subsystem_ident = NULL;
  866. entry.subsystem_name = NULL;
  867. entry.subsystem_roms = NULL;
  868. entry.entry_slot = 0;
  869. entry.runtime_hours = 0;
  870. entry.runtime_minutes = 0;
  871. entry.runtime_seconds = 0;
  872. entry.last_played_year = 0;
  873. entry.last_played_month = 0;
  874. entry.last_played_day = 0;
  875. entry.last_played_hour = 0;
  876. entry.last_played_minute = 0;
  877. entry.last_played_second = 0;
  878. playlist_push(playlist, &entry);
  879. }
  880. playlist_write_file(playlist);
  881. playlist_free(playlist);
  882. #endif
  883. return 0;
  884. }
  885. static int task_database_iterate_serial_lookup(
  886. db_handle_t *_db,
  887. database_state_handle_t *db_state,
  888. database_info_handle_t *db, const char *name,
  889. bool path_contains_compressed_file)
  890. {
  891. if (
  892. !db_state->list ||
  893. (unsigned)db_state->list_index == (unsigned)db_state->list->size
  894. )
  895. return database_info_list_iterate_end_no_match(db, db_state, name,
  896. path_contains_compressed_file);
  897. if (db_state->entry_index == 0)
  898. {
  899. size_t _len;
  900. char query[50];
  901. char *serial_buf = bin_to_hex_alloc(
  902. (uint8_t*)db_state->serial,
  903. strlen(db_state->serial) * sizeof(uint8_t));
  904. if (!serial_buf)
  905. return 1;
  906. strlcpy(query, "{'serial': b'", sizeof(query));
  907. _len = strlcat(query, serial_buf, sizeof(query));
  908. query[_len ] = '\'';
  909. query[_len+1] = '}';
  910. query[_len+2] = '\0';
  911. database_info_list_iterate_new(db_state, query);
  912. free(serial_buf);
  913. }
  914. if (db_state->info)
  915. {
  916. database_info_t *db_info_entry = &db_state->info->list[
  917. db_state->entry_index];
  918. if (db_info_entry && db_info_entry->serial)
  919. {
  920. if (string_is_equal(db_state->serial, db_info_entry->serial))
  921. return database_info_list_iterate_found_match(_db,
  922. db_state, db, NULL);
  923. }
  924. }
  925. db_state->entry_index++;
  926. if (db_state->info)
  927. {
  928. if (db_state->entry_index >= db_state->info->count)
  929. return database_info_list_iterate_next(db_state);
  930. }
  931. /* If we haven't reached the end of the database list yet,
  932. * continue iterating. */
  933. if (db_state->list_index < db_state->list->size)
  934. return 1;
  935. database_info_list_free(db_state->info);
  936. free(db_state->info);
  937. return 0;
  938. }
  939. static int task_database_iterate(
  940. db_handle_t *_db,
  941. const char *name,
  942. database_state_handle_t *db_state,
  943. database_info_handle_t *db,
  944. bool path_contains_compressed_file)
  945. {
  946. switch (db->type)
  947. {
  948. case DATABASE_TYPE_ITERATE:
  949. return task_database_iterate_playlist(db_state, db, name);
  950. case DATABASE_TYPE_ITERATE_ARCHIVE:
  951. #ifdef HAVE_COMPRESSION
  952. return task_database_iterate_crc_lookup(
  953. _db, db_state, db, name, db_state->archive_name,
  954. path_contains_compressed_file);
  955. #else
  956. return 1;
  957. #endif
  958. case DATABASE_TYPE_ITERATE_LUTRO:
  959. return task_database_iterate_playlist_lutro(_db, db_state, db, name);
  960. case DATABASE_TYPE_SERIAL_LOOKUP:
  961. return task_database_iterate_serial_lookup(_db, db_state, db, name,
  962. path_contains_compressed_file);
  963. case DATABASE_TYPE_CRC_LOOKUP:
  964. return task_database_iterate_crc_lookup(_db, db_state, db, name, NULL,
  965. path_contains_compressed_file);
  966. case DATABASE_TYPE_NONE:
  967. default:
  968. break;
  969. }
  970. return 0;
  971. }
  972. static void task_database_cleanup_state(
  973. database_state_handle_t *db_state)
  974. {
  975. if (!db_state)
  976. return;
  977. if (db_state->buf)
  978. free(db_state->buf);
  979. db_state->buf = NULL;
  980. }
  981. static void task_database_handler(retro_task_t *task)
  982. {
  983. const char *name = NULL;
  984. database_info_handle_t *dbinfo = NULL;
  985. database_state_handle_t *dbstate = NULL;
  986. db_handle_t *db = NULL;
  987. if (!task)
  988. goto task_finished;
  989. db = (db_handle_t*)task->state;
  990. if (!db)
  991. goto task_finished;
  992. if (!(db->flags & DB_HANDLE_FLAG_SCAN_STARTED))
  993. {
  994. db->flags |= DB_HANDLE_FLAG_SCAN_STARTED;
  995. if (!string_is_empty(db->fullpath))
  996. {
  997. if (db->flags & DB_HANDLE_FLAG_IS_DIRECTORY)
  998. db->handle = database_info_dir_init(
  999. db->fullpath, DATABASE_TYPE_ITERATE,
  1000. task, db->flags & DB_HANDLE_FLAG_SHOW_HIDDEN_FILES);
  1001. else
  1002. db->handle = database_info_file_init(
  1003. db->fullpath, DATABASE_TYPE_ITERATE,
  1004. task);
  1005. }
  1006. if (db->handle)
  1007. db->handle->status = DATABASE_STATUS_ITERATE_BEGIN;
  1008. }
  1009. dbinfo = db->handle;
  1010. dbstate = &db->state;
  1011. if (!dbinfo || task_get_cancelled(task))
  1012. goto task_finished;
  1013. switch (dbinfo->status)
  1014. {
  1015. case DATABASE_STATUS_ITERATE_BEGIN:
  1016. if (dbstate && !dbstate->list)
  1017. {
  1018. if (!string_is_empty(db->content_database_path))
  1019. dbstate->list = dir_list_new(
  1020. db->content_database_path,
  1021. "rdb", false,
  1022. db->flags & DB_HANDLE_FLAG_SHOW_HIDDEN_FILES,
  1023. false, false);
  1024. RARCH_LOG("[Scanner]: %s\"%s\"..\n", msg_hash_to_str(MSG_MANUAL_CONTENT_SCAN_START), db->fullpath);
  1025. if (retroarch_override_setting_is_set(RARCH_OVERRIDE_SETTING_DATABASE_SCAN, NULL))
  1026. printf("%s\"%s\"..\n", msg_hash_to_str(MSG_MANUAL_CONTENT_SCAN_START), db->fullpath);
  1027. /* If the scan path matches a database path exactly then
  1028. * save time by only processing that database. */
  1029. if (dbstate->list && (db->flags & DB_HANDLE_FLAG_IS_DIRECTORY))
  1030. {
  1031. size_t i;
  1032. char *dirname = NULL;
  1033. if (!string_is_empty(db->fullpath))
  1034. dirname = find_last_slash(db->fullpath) + 1;
  1035. if (!string_is_empty(dirname))
  1036. {
  1037. for (i = 0; i < dbstate->list->size; i++)
  1038. {
  1039. const char *data = dbstate->list->elems[i].data;
  1040. char *dbname = NULL;
  1041. bool strmatch = false;
  1042. char *dbpath = strdup(data);
  1043. path_remove_extension(dbpath);
  1044. dbname = find_last_slash(dbpath) + 1;
  1045. strmatch = strcasecmp(dbname, dirname) == 0;
  1046. free(dbpath);
  1047. if (strmatch)
  1048. {
  1049. struct string_list *single_list = string_list_new();
  1050. string_list_append(single_list,
  1051. data,
  1052. dbstate->list->elems[i].attr);
  1053. dir_list_free(dbstate->list);
  1054. dbstate->list = single_list;
  1055. break;
  1056. }
  1057. }
  1058. }
  1059. }
  1060. }
  1061. dbinfo->status = DATABASE_STATUS_ITERATE_START;
  1062. break;
  1063. case DATABASE_STATUS_ITERATE_START:
  1064. name = database_info_get_current_element_name(dbinfo);
  1065. task_database_cleanup_state(dbstate);
  1066. dbstate->list_index = 0;
  1067. dbstate->entry_index = 0;
  1068. task_database_iterate_start(task, dbinfo, name);
  1069. break;
  1070. case DATABASE_STATUS_ITERATE:
  1071. {
  1072. bool path_contains_compressed_file = false;
  1073. const char *name =
  1074. database_info_get_current_element_name(dbinfo);
  1075. if (!name)
  1076. goto task_finished;
  1077. path_contains_compressed_file = path_contains_compressed_file(name);
  1078. if (path_contains_compressed_file)
  1079. if (dbinfo->type == DATABASE_TYPE_ITERATE)
  1080. dbinfo->type = DATABASE_TYPE_ITERATE_ARCHIVE;
  1081. if (task_database_iterate(db, name, dbstate, dbinfo,
  1082. path_contains_compressed_file) == 0)
  1083. {
  1084. dbinfo->status = DATABASE_STATUS_ITERATE_NEXT;
  1085. dbinfo->type = DATABASE_TYPE_ITERATE;
  1086. }
  1087. }
  1088. break;
  1089. case DATABASE_STATUS_ITERATE_NEXT:
  1090. dbinfo->list_ptr++;
  1091. if (dbinfo->list_ptr < dbinfo->list->size)
  1092. {
  1093. dbinfo->status = DATABASE_STATUS_ITERATE_START;
  1094. dbinfo->type = DATABASE_TYPE_ITERATE;
  1095. }
  1096. else
  1097. {
  1098. const char *msg = NULL;
  1099. if (db->flags & DB_HANDLE_FLAG_IS_DIRECTORY)
  1100. msg = msg_hash_to_str(MSG_SCANNING_OF_DIRECTORY_FINISHED);
  1101. else
  1102. msg = msg_hash_to_str(MSG_SCANNING_OF_FILE_FINISHED);
  1103. #ifdef RARCH_INTERNAL
  1104. task_free_title(task);
  1105. task_set_title(task, strdup(msg));
  1106. task_set_progress(task, 100);
  1107. ui_companion_driver_notify_refresh();
  1108. RARCH_LOG("[Scanner]: %s\n", msg);
  1109. if (retroarch_override_setting_is_set(RARCH_OVERRIDE_SETTING_DATABASE_SCAN, NULL))
  1110. printf("%s\n", msg);
  1111. #else
  1112. fprintf(stderr, "msg: %s\n", msg);
  1113. #endif
  1114. goto task_finished;
  1115. }
  1116. break;
  1117. default:
  1118. case DATABASE_STATUS_FREE:
  1119. case DATABASE_STATUS_NONE:
  1120. goto task_finished;
  1121. }
  1122. return;
  1123. task_finished:
  1124. if (task)
  1125. task_set_finished(task, true);
  1126. if (dbstate)
  1127. {
  1128. if (dbstate->list)
  1129. dir_list_free(dbstate->list);
  1130. }
  1131. if (db)
  1132. {
  1133. if (!string_is_empty(db->playlist_directory))
  1134. free(db->playlist_directory);
  1135. if (!string_is_empty(db->content_database_path))
  1136. free(db->content_database_path);
  1137. if (!string_is_empty(db->fullpath))
  1138. free(db->fullpath);
  1139. if (db->state.buf)
  1140. free(db->state.buf);
  1141. if (db->handle)
  1142. database_info_free(db->handle);
  1143. free(db);
  1144. }
  1145. if (dbinfo)
  1146. free(dbinfo);
  1147. }
  1148. #ifdef RARCH_INTERNAL
  1149. static void task_database_progress_cb(retro_task_t *task)
  1150. {
  1151. if (task)
  1152. video_display_server_set_window_progress(task->progress,
  1153. task->finished);
  1154. }
  1155. #endif
  1156. bool task_push_dbscan(
  1157. const char *playlist_directory,
  1158. const char *content_database,
  1159. const char *fullpath,
  1160. bool directory,
  1161. bool db_dir_show_hidden_files,
  1162. retro_task_callback_t cb)
  1163. {
  1164. retro_task_t *t = task_init();
  1165. #ifdef RARCH_INTERNAL
  1166. settings_t *settings = config_get_ptr();
  1167. #endif
  1168. db_handle_t *db = (db_handle_t*)calloc(1, sizeof(db_handle_t));
  1169. if (!t || !db)
  1170. goto error;
  1171. t->handler = task_database_handler;
  1172. t->state = db;
  1173. t->callback = cb;
  1174. t->title = strdup(msg_hash_to_str(
  1175. MSG_PREPARING_FOR_CONTENT_SCAN));
  1176. t->alternative_look = true;
  1177. #ifdef RARCH_INTERNAL
  1178. t->progress_cb = task_database_progress_cb;
  1179. if (settings->bools.scan_without_core_match)
  1180. db->flags |= DB_HANDLE_FLAG_SCAN_WITHOUT_CORE_MATCH;
  1181. #ifdef HAVE_PLAYLIST
  1182. db->playlist_config.capacity = COLLECTION_SIZE;
  1183. db->playlist_config.old_format = settings->bools.playlist_use_old_format;
  1184. db->playlist_config.compress = settings->bools.playlist_compression;
  1185. db->playlist_config.fuzzy_archive_match = settings->bools.playlist_fuzzy_archive_match;
  1186. playlist_config_set_base_content_directory(&db->playlist_config, settings->bools.playlist_portable_paths ? settings->paths.directory_menu_content : NULL);
  1187. #endif
  1188. #else
  1189. #ifdef HAVE_PLAYLIST
  1190. db->playlist_config.capacity = COLLECTION_SIZE;
  1191. db->playlist_config.old_format = false;
  1192. db->playlist_config.compress = false;
  1193. db->playlist_config.fuzzy_archive_match = false;
  1194. playlist_config_set_base_content_directory(&db->playlist_config, NULL);
  1195. #endif
  1196. #endif
  1197. if (db_dir_show_hidden_files)
  1198. db->flags |= DB_HANDLE_FLAG_SHOW_HIDDEN_FILES;
  1199. if (directory)
  1200. db->flags |= DB_HANDLE_FLAG_IS_DIRECTORY;
  1201. db->fullpath = strdup(fullpath);
  1202. db->playlist_directory = strdup(playlist_directory);
  1203. db->content_database_path = strdup(content_database);
  1204. task_queue_push(t);
  1205. return true;
  1206. error:
  1207. if (t)
  1208. free(t);
  1209. if (db)
  1210. free(db);
  1211. return false;
  1212. }