core_info.c 91 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082
  1. /* RetroArch - A frontend for libretro.
  2. * Copyright (C) 2010-2014 - Hans-Kristian Arntzen
  3. * Copyright (C) 2011-2017 - Daniel De Matteis
  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 <compat/strl.h>
  18. #include <string/stdstring.h>
  19. #include <file/config_file.h>
  20. #include <file/file_path.h>
  21. #include <streams/file_stream.h>
  22. #include <streams/interface_stream.h>
  23. #include <formats/rjson.h>
  24. #include <lists/dir_list.h>
  25. #include <file/archive_file.h>
  26. #ifdef HAVE_CONFIG_H
  27. #include "config.h"
  28. #endif
  29. #include "retroarch.h"
  30. #include "verbosity.h"
  31. #include "core_info.h"
  32. #include "file_path_special.h"
  33. #if defined(__WINRT__) || defined(WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
  34. #include "uwp/uwp_func.h"
  35. #endif
  36. #if defined(ANDROID)
  37. #include "play_feature_delivery/play_feature_delivery.h"
  38. #endif
  39. /*************************/
  40. /* Core Info Cache START */
  41. /*************************/
  42. #define CORE_INFO_CACHE_VERSION "1.2"
  43. #define CORE_INFO_CACHE_DEFAULT_CAPACITY 8
  44. /* TODO/FIXME: Apparently rzip compression is an issue on UWP */
  45. #if defined(HAVE_ZLIB) && !(defined(__WINRT__) || defined(WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP)
  46. #define CORE_INFO_CACHE_COMPRESS
  47. #endif
  48. typedef struct
  49. {
  50. core_info_t *items;
  51. size_t length;
  52. size_t capacity;
  53. char *version;
  54. bool refresh;
  55. } core_info_cache_list_t;
  56. typedef struct
  57. {
  58. core_info_t *core_info;
  59. core_info_cache_list_t *core_info_cache_list;
  60. char **current_string_val;
  61. struct string_list **current_string_list_val;
  62. uint32_t *current_entry_uint_val;
  63. bool *current_entry_bool_val;
  64. unsigned array_depth;
  65. unsigned object_depth;
  66. bool to_core_file_id;
  67. bool to_firmware;
  68. } CCJSONContext;
  69. /* Forward declarations */
  70. static void core_info_free(core_info_t* info);
  71. static uint32_t core_info_hash_string(const char *str);
  72. #ifdef HAVE_CORE_INFO_CACHE
  73. static core_info_cache_list_t *core_info_cache_list_new(void);
  74. #endif
  75. static void core_info_cache_add(core_info_cache_list_t *list,
  76. core_info_t *info, bool transfer);
  77. static core_info_state_t core_info_st = {
  78. #ifdef HAVE_COMPRESSION
  79. NULL,
  80. #endif
  81. NULL,
  82. NULL,
  83. NULL
  84. };
  85. #ifdef HAVE_CORE_INFO_CACHE
  86. /* JSON Handlers START */
  87. static bool CCJSONObjectMemberHandler(void *context,
  88. const char *pValue, size_t length)
  89. {
  90. CCJSONContext *pCtx = (CCJSONContext *)context;
  91. if ( (pCtx->object_depth == 2)
  92. && (pCtx->array_depth == 1)
  93. && length)
  94. {
  95. pCtx->current_string_val = NULL;
  96. pCtx->current_string_list_val = NULL;
  97. pCtx->current_entry_uint_val = NULL;
  98. pCtx->current_entry_bool_val = NULL;
  99. pCtx->to_core_file_id = false;
  100. pCtx->to_firmware = false;
  101. switch (pValue[0])
  102. {
  103. case 'a':
  104. if (string_is_equal(pValue, "authors"))
  105. {
  106. pCtx->current_string_val = &pCtx->core_info->authors;
  107. pCtx->current_string_list_val = &pCtx->core_info->authors_list;
  108. }
  109. break;
  110. case 'c':
  111. if (string_is_equal(pValue, "categories"))
  112. {
  113. pCtx->current_string_val = &pCtx->core_info->categories;
  114. pCtx->current_string_list_val = &pCtx->core_info->categories_list;
  115. }
  116. else if (string_is_equal(pValue, "core_name"))
  117. pCtx->current_string_val = &pCtx->core_info->core_name;
  118. else if (string_is_equal(pValue, "core_file_id"))
  119. pCtx->to_core_file_id = true;
  120. break;
  121. case 'd':
  122. if (string_is_equal(pValue, "display_name"))
  123. pCtx->current_string_val = &pCtx->core_info->display_name;
  124. else if (string_is_equal(pValue, "display_version"))
  125. pCtx->current_string_val = &pCtx->core_info->display_version;
  126. else if (string_is_equal(pValue, "databases"))
  127. {
  128. pCtx->current_string_val = &pCtx->core_info->databases;
  129. pCtx->current_string_list_val = &pCtx->core_info->databases_list;
  130. }
  131. else if (string_is_equal(pValue, "description"))
  132. pCtx->current_string_val = &pCtx->core_info->description;
  133. else if (string_is_equal(pValue, "database_match_archive_member"))
  134. pCtx->current_entry_bool_val = &pCtx->core_info->database_match_archive_member;
  135. break;
  136. case 'f':
  137. if (string_is_equal(pValue, "firmware"))
  138. pCtx->to_firmware = true;
  139. break;
  140. case 'h':
  141. if (string_is_equal(pValue, "has_info"))
  142. pCtx->current_entry_bool_val = &pCtx->core_info->has_info;
  143. break;
  144. case 'l':
  145. if (string_is_equal(pValue, "licenses"))
  146. {
  147. pCtx->current_string_val = &pCtx->core_info->licenses;
  148. pCtx->current_string_list_val = &pCtx->core_info->licenses_list;
  149. }
  150. else if (string_is_equal(pValue, "is_experimental"))
  151. pCtx->current_entry_bool_val = &pCtx->core_info->is_experimental;
  152. break;
  153. case 'n':
  154. if (string_is_equal(pValue, "notes"))
  155. {
  156. pCtx->current_string_val = &pCtx->core_info->notes;
  157. pCtx->current_string_list_val = &pCtx->core_info->note_list;
  158. }
  159. break;
  160. case 'p':
  161. if (string_is_equal(pValue, "permissions"))
  162. {
  163. pCtx->current_string_val = &pCtx->core_info->permissions;
  164. pCtx->current_string_list_val = &pCtx->core_info->permissions_list;
  165. }
  166. break;
  167. case 'r':
  168. if (string_is_equal(pValue, "required_hw_api"))
  169. {
  170. pCtx->current_string_val = &pCtx->core_info->required_hw_api;
  171. pCtx->current_string_list_val = &pCtx->core_info->required_hw_api_list;
  172. }
  173. break;
  174. case 's':
  175. if (string_is_equal(pValue, "system_manufacturer"))
  176. pCtx->current_string_val = &pCtx->core_info->system_manufacturer;
  177. else if (string_is_equal(pValue, "systemname"))
  178. pCtx->current_string_val = &pCtx->core_info->systemname;
  179. else if (string_is_equal(pValue, "system_id"))
  180. pCtx->current_string_val = &pCtx->core_info->system_id;
  181. else if (string_is_equal(pValue, "supported_extensions"))
  182. {
  183. pCtx->current_string_val = &pCtx->core_info->supported_extensions;
  184. pCtx->current_string_list_val = &pCtx->core_info->supported_extensions_list;
  185. }
  186. else if (string_is_equal(pValue, "supports_no_game"))
  187. pCtx->current_entry_bool_val = &pCtx->core_info->supports_no_game;
  188. else if (string_is_equal(pValue, "single_purpose"))
  189. pCtx->current_entry_bool_val = &pCtx->core_info->single_purpose;
  190. else if (string_is_equal(pValue, "savestate_support_level"))
  191. pCtx->current_entry_uint_val = &pCtx->core_info->savestate_support_level;
  192. break;
  193. }
  194. }
  195. else if ( (pCtx->object_depth == 3)
  196. && (pCtx->array_depth == 1)
  197. && length)
  198. {
  199. pCtx->current_string_val = NULL;
  200. pCtx->current_entry_uint_val = NULL;
  201. if (pCtx->to_core_file_id)
  202. {
  203. if (string_is_equal(pValue, "str"))
  204. pCtx->current_string_val = &pCtx->core_info->core_file_id.str;
  205. else if (string_is_equal(pValue, "hash"))
  206. pCtx->current_entry_uint_val = &pCtx->core_info->core_file_id.hash;
  207. }
  208. }
  209. else if ( (pCtx->object_depth == 3)
  210. && (pCtx->array_depth == 2)
  211. && length)
  212. {
  213. pCtx->current_string_val = NULL;
  214. pCtx->current_entry_bool_val = NULL;
  215. if (pCtx->to_firmware && (pCtx->core_info->firmware_count > 0))
  216. {
  217. size_t firmware_idx = pCtx->core_info->firmware_count - 1;
  218. if (string_is_equal(pValue, "path"))
  219. pCtx->current_string_val = &pCtx->core_info->firmware[firmware_idx].path;
  220. else if (string_is_equal(pValue, "desc"))
  221. pCtx->current_string_val = &pCtx->core_info->firmware[firmware_idx].desc;
  222. else if (string_is_equal(pValue, "optional"))
  223. pCtx->current_entry_bool_val = &pCtx->core_info->firmware[firmware_idx].optional;
  224. }
  225. }
  226. else if ( (pCtx->object_depth == 1)
  227. && (pCtx->array_depth == 0)
  228. && length)
  229. {
  230. pCtx->current_string_val = NULL;
  231. if (string_is_equal(pValue, "version"))
  232. pCtx->current_string_val = &pCtx->core_info_cache_list->version;
  233. }
  234. return true;
  235. }
  236. static bool CCJSONStringHandler(void *context,
  237. const char *pValue, size_t length)
  238. {
  239. CCJSONContext *pCtx = (CCJSONContext*)context;
  240. if ( pCtx->current_string_val
  241. && length
  242. && !string_is_empty(pValue))
  243. {
  244. if (*pCtx->current_string_val)
  245. free(*pCtx->current_string_val);
  246. *pCtx->current_string_val = strdup(pValue);
  247. if (pCtx->current_string_list_val)
  248. {
  249. if (*pCtx->current_string_list_val)
  250. string_list_free(*pCtx->current_string_list_val);
  251. *pCtx->current_string_list_val =
  252. string_split(*pCtx->current_string_val, "|");
  253. }
  254. }
  255. pCtx->current_string_val = NULL;
  256. pCtx->current_string_list_val = NULL;
  257. return true;
  258. }
  259. static bool CCJSONNumberHandler(void *context,
  260. const char *pValue, size_t length)
  261. {
  262. CCJSONContext *pCtx = (CCJSONContext*)context;
  263. if (pCtx->current_entry_uint_val)
  264. *pCtx->current_entry_uint_val = string_to_unsigned(pValue);
  265. pCtx->current_entry_uint_val = NULL;
  266. return true;
  267. }
  268. static bool CCJSONBoolHandler(void *context, bool value)
  269. {
  270. CCJSONContext *pCtx = (CCJSONContext *)context;
  271. if (pCtx->current_entry_bool_val)
  272. *pCtx->current_entry_bool_val = value;
  273. pCtx->current_entry_bool_val = NULL;
  274. return true;
  275. }
  276. static bool CCJSONStartObjectHandler(void *context)
  277. {
  278. CCJSONContext *pCtx = (CCJSONContext*)context;
  279. pCtx->object_depth++;
  280. if ( (pCtx->object_depth == 1)
  281. && (pCtx->array_depth == 0))
  282. {
  283. if (pCtx->core_info_cache_list)
  284. return false;
  285. if (!(pCtx->core_info_cache_list = core_info_cache_list_new()))
  286. return false;
  287. }
  288. else if ((pCtx->object_depth == 2)
  289. && (pCtx->array_depth == 1))
  290. {
  291. if (pCtx->core_info)
  292. {
  293. core_info_free(pCtx->core_info);
  294. free(pCtx->core_info);
  295. pCtx->core_info = NULL;
  296. }
  297. if (!(pCtx->core_info = (core_info_t*)calloc(1, sizeof(core_info_t))))
  298. return false;
  299. /* Assume all cores have 'full' savestate support
  300. * by default */
  301. pCtx->core_info->savestate_support_level =
  302. CORE_INFO_SAVESTATE_DETERMINISTIC;
  303. }
  304. else if ((pCtx->object_depth == 3)
  305. && (pCtx->array_depth == 2))
  306. {
  307. if (pCtx->to_firmware)
  308. {
  309. size_t new_idx = pCtx->core_info->firmware_count;
  310. core_info_firmware_t *tmp = (core_info_firmware_t*)
  311. realloc(pCtx->core_info->firmware,
  312. (pCtx->core_info->firmware_count + 1)
  313. * sizeof(core_info_firmware_t));
  314. if (!tmp)
  315. return false;
  316. tmp[new_idx].path = NULL;
  317. tmp[new_idx].desc = NULL;
  318. tmp[new_idx].missing = false;
  319. tmp[new_idx].optional = false;
  320. pCtx->core_info->firmware = tmp;
  321. pCtx->core_info->firmware_count++;
  322. }
  323. }
  324. return true;
  325. }
  326. static bool CCJSONEndObjectHandler(void *context)
  327. {
  328. CCJSONContext *pCtx = (CCJSONContext*)context;
  329. if ( (pCtx->object_depth == 2)
  330. && (pCtx->array_depth == 1)
  331. && (pCtx->core_info))
  332. {
  333. core_info_cache_add(
  334. pCtx->core_info_cache_list, pCtx->core_info, true);
  335. free(pCtx->core_info);
  336. pCtx->core_info = NULL;
  337. }
  338. else if ((pCtx->object_depth == 3)
  339. && (pCtx->array_depth == 1))
  340. pCtx->to_core_file_id = false;
  341. pCtx->object_depth--;
  342. return true;
  343. }
  344. static bool CCJSONStartArrayHandler(void *context)
  345. {
  346. CCJSONContext *pCtx = (CCJSONContext*)context;
  347. pCtx->array_depth++;
  348. return true;
  349. }
  350. static bool CCJSONEndArrayHandler(void *context)
  351. {
  352. CCJSONContext *pCtx = (CCJSONContext*)context;
  353. if ((pCtx->object_depth == 2) && (pCtx->array_depth == 2))
  354. pCtx->to_firmware = false;
  355. pCtx->array_depth--;
  356. return true;
  357. }
  358. /* JSON Handlers END */
  359. #endif
  360. /* Note: 'dst' must be zero initialised, or memory
  361. * leaks will occur */
  362. static void core_info_copy(core_info_t *src, core_info_t *dst)
  363. {
  364. dst->path = src->path ? strdup(src->path) : NULL;
  365. dst->display_name = src->display_name ? strdup(src->display_name) : NULL;
  366. dst->display_version = src->display_version ? strdup(src->display_version) : NULL;
  367. dst->core_name = src->core_name ? strdup(src->core_name) : NULL;
  368. dst->system_manufacturer = src->system_manufacturer ? strdup(src->system_manufacturer) : NULL;
  369. dst->systemname = src->systemname ? strdup(src->systemname) : NULL;
  370. dst->system_id = src->system_id ? strdup(src->system_id) : NULL;
  371. dst->supported_extensions = src->supported_extensions ? strdup(src->supported_extensions) : NULL;
  372. dst->authors = src->authors ? strdup(src->authors) : NULL;
  373. dst->permissions = src->permissions ? strdup(src->permissions) : NULL;
  374. dst->licenses = src->licenses ? strdup(src->licenses) : NULL;
  375. dst->categories = src->categories ? strdup(src->categories) : NULL;
  376. dst->databases = src->databases ? strdup(src->databases) : NULL;
  377. dst->notes = src->notes ? strdup(src->notes) : NULL;
  378. dst->required_hw_api = src->required_hw_api ? strdup(src->required_hw_api) : NULL;
  379. dst->description = src->description ? strdup(src->description) : NULL;
  380. dst->categories_list = src->categories_list ? string_list_clone(src->categories_list) : NULL;
  381. dst->databases_list = src->databases_list ? string_list_clone(src->databases_list) : NULL;
  382. dst->note_list = src->note_list ? string_list_clone(src->note_list) : NULL;
  383. dst->supported_extensions_list = src->supported_extensions_list ? string_list_clone(src->supported_extensions_list) : NULL;
  384. dst->authors_list = src->authors_list ? string_list_clone(src->authors_list) : NULL;
  385. dst->permissions_list = src->permissions_list ? string_list_clone(src->permissions_list) : NULL;
  386. dst->licenses_list = src->licenses_list ? string_list_clone(src->licenses_list) : NULL;
  387. dst->required_hw_api_list = src->required_hw_api_list ? string_list_clone(src->required_hw_api_list) : NULL;
  388. if (src->firmware_count > 0)
  389. {
  390. dst->firmware = (core_info_firmware_t*)calloc(src->firmware_count,
  391. sizeof(core_info_firmware_t));
  392. if (dst->firmware)
  393. {
  394. size_t i;
  395. dst->firmware_count = src->firmware_count;
  396. for (i = 0; i < src->firmware_count; i++)
  397. {
  398. dst->firmware[i].path = src->firmware[i].path ? strdup(src->firmware[i].path) : NULL;
  399. dst->firmware[i].desc = src->firmware[i].desc ? strdup(src->firmware[i].desc) : NULL;
  400. dst->firmware[i].missing = src->firmware[i].missing;
  401. dst->firmware[i].optional = src->firmware[i].optional;
  402. }
  403. }
  404. else
  405. dst->firmware_count = 0;
  406. }
  407. dst->core_file_id.str = src->core_file_id.str
  408. ? strdup(src->core_file_id.str) : NULL;
  409. dst->core_file_id.hash = src->core_file_id.hash;
  410. dst->savestate_support_level = src->savestate_support_level;
  411. dst->has_info = src->has_info;
  412. dst->supports_no_game = src->supports_no_game;
  413. dst->single_purpose = src->single_purpose;
  414. dst->database_match_archive_member = src->database_match_archive_member;
  415. dst->is_experimental = src->is_experimental;
  416. dst->is_locked = src->is_locked;
  417. dst->is_standalone_exempt = src->is_standalone_exempt;
  418. dst->is_installed = src->is_installed;
  419. }
  420. /* Like core_info_copy, but transfers 'ownership'
  421. * of internal objects/data structures from 'src'
  422. * to 'dst' */
  423. static void core_info_transfer(core_info_t *src, core_info_t *dst)
  424. {
  425. dst->path = src->path;
  426. src->path = NULL;
  427. dst->display_name = src->display_name;
  428. src->display_name = NULL;
  429. dst->display_version = src->display_version;
  430. src->display_version = NULL;
  431. dst->core_name = src->core_name;
  432. src->core_name = NULL;
  433. dst->system_manufacturer = src->system_manufacturer;
  434. src->system_manufacturer = NULL;
  435. dst->systemname = src->systemname;
  436. src->systemname = NULL;
  437. dst->system_id = src->system_id;
  438. src->system_id = NULL;
  439. dst->supported_extensions = src->supported_extensions;
  440. src->supported_extensions = NULL;
  441. dst->authors = src->authors;
  442. src->authors = NULL;
  443. dst->permissions = src->permissions;
  444. src->permissions = NULL;
  445. dst->licenses = src->licenses;
  446. src->licenses = NULL;
  447. dst->categories = src->categories;
  448. src->categories = NULL;
  449. dst->databases = src->databases;
  450. src->databases = NULL;
  451. dst->notes = src->notes;
  452. src->notes = NULL;
  453. dst->required_hw_api = src->required_hw_api;
  454. src->required_hw_api = NULL;
  455. dst->description = src->description;
  456. src->description = NULL;
  457. dst->categories_list = src->categories_list;
  458. src->categories_list = NULL;
  459. dst->databases_list = src->databases_list;
  460. src->databases_list = NULL;
  461. dst->note_list = src->note_list;
  462. src->note_list = NULL;
  463. dst->supported_extensions_list = src->supported_extensions_list;
  464. src->supported_extensions_list = NULL;
  465. dst->authors_list = src->authors_list;
  466. src->authors_list = NULL;
  467. dst->permissions_list = src->permissions_list;
  468. src->permissions_list = NULL;
  469. dst->licenses_list = src->licenses_list;
  470. src->licenses_list = NULL;
  471. dst->required_hw_api_list = src->required_hw_api_list;
  472. src->required_hw_api_list = NULL;
  473. dst->firmware = src->firmware;
  474. dst->firmware_count = src->firmware_count;
  475. src->firmware = NULL;
  476. src->firmware_count = 0;
  477. dst->core_file_id.str = src->core_file_id.str;
  478. src->core_file_id.str = NULL;
  479. dst->core_file_id.hash = src->core_file_id.hash;
  480. dst->savestate_support_level = src->savestate_support_level;
  481. dst->has_info = src->has_info;
  482. dst->supports_no_game = src->supports_no_game;
  483. dst->single_purpose = src->single_purpose;
  484. dst->database_match_archive_member = src->database_match_archive_member;
  485. dst->is_experimental = src->is_experimental;
  486. dst->is_locked = src->is_locked;
  487. dst->is_standalone_exempt = src->is_standalone_exempt;
  488. dst->is_installed = src->is_installed;
  489. }
  490. static void core_info_cache_list_free(
  491. core_info_cache_list_t *core_info_cache_list)
  492. {
  493. size_t i;
  494. if (!core_info_cache_list)
  495. return;
  496. for (i = 0; i < core_info_cache_list->length; i++)
  497. {
  498. core_info_t* info = (core_info_t*)&core_info_cache_list->items[i];
  499. core_info_free(info);
  500. }
  501. free(core_info_cache_list->items);
  502. if (core_info_cache_list->version)
  503. free(core_info_cache_list->version);
  504. free(core_info_cache_list);
  505. }
  506. static core_info_t *core_info_cache_find(
  507. core_info_cache_list_t *list, char *core_file_id)
  508. {
  509. uint32_t hash;
  510. size_t i;
  511. if ( !list
  512. || string_is_empty(core_file_id))
  513. return NULL;
  514. hash = core_info_hash_string(core_file_id);
  515. for (i = 0; i < list->length; i++)
  516. {
  517. core_info_t *info = (core_info_t*)&list->items[i];
  518. if (!info)
  519. continue;
  520. if ( (info->core_file_id.hash == hash)
  521. && string_is_equal(info->core_file_id.str, core_file_id))
  522. {
  523. info->is_installed = true;
  524. return info;
  525. }
  526. }
  527. return NULL;
  528. }
  529. static void core_info_cache_add(
  530. core_info_cache_list_t *list, core_info_t *info,
  531. bool transfer)
  532. {
  533. core_info_t *info_cache = NULL;
  534. if ( !list
  535. || !info
  536. || (info->core_file_id.hash == 0)
  537. || string_is_empty(info->core_file_id.str))
  538. return;
  539. if (list->length >= list->capacity)
  540. {
  541. size_t prev_capacity = list->capacity;
  542. core_info_t *items_tmp = (core_info_t*)realloc(list->items,
  543. (list->capacity << 1) * sizeof(core_info_t));
  544. if (!items_tmp)
  545. return;
  546. list->capacity = list->capacity << 1;
  547. list->items = items_tmp;
  548. memset(&list->items[prev_capacity], 0,
  549. (list->capacity - prev_capacity) * sizeof(core_info_t));
  550. }
  551. info_cache = (core_info_t*)&list->items[list->length];
  552. if (transfer)
  553. core_info_transfer(info, info_cache);
  554. else
  555. core_info_copy(info, info_cache);
  556. list->length++;
  557. }
  558. #ifdef HAVE_CORE_INFO_CACHE
  559. static core_info_cache_list_t *core_info_cache_list_new(void)
  560. {
  561. core_info_cache_list_t *core_info_cache_list =
  562. (core_info_cache_list_t *)malloc(sizeof(*core_info_cache_list));
  563. if (!core_info_cache_list)
  564. return NULL;
  565. core_info_cache_list->length = 0;
  566. core_info_cache_list->items = (core_info_t *)
  567. calloc(CORE_INFO_CACHE_DEFAULT_CAPACITY,
  568. sizeof(core_info_t));
  569. if (!core_info_cache_list->items)
  570. {
  571. core_info_cache_list_free(core_info_cache_list);
  572. return NULL;
  573. }
  574. core_info_cache_list->capacity = CORE_INFO_CACHE_DEFAULT_CAPACITY;
  575. core_info_cache_list->refresh = false;
  576. core_info_cache_list->version = NULL;
  577. return core_info_cache_list;
  578. }
  579. static core_info_cache_list_t *core_info_cache_read(const char *info_dir)
  580. {
  581. intfstream_t *file = NULL;
  582. rjson_t *parser = NULL;
  583. CCJSONContext context = {0};
  584. core_info_cache_list_t *core_info_cache_list = NULL;
  585. char file_path[PATH_MAX_LENGTH];
  586. /* Check whether a 'force refresh' file
  587. * is present */
  588. if (string_is_empty(info_dir))
  589. strlcpy(file_path,
  590. FILE_PATH_CORE_INFO_CACHE_REFRESH, sizeof(file_path));
  591. else
  592. fill_pathname_join_special(file_path,
  593. info_dir, FILE_PATH_CORE_INFO_CACHE_REFRESH,
  594. sizeof(file_path));
  595. if (path_is_valid(file_path))
  596. return core_info_cache_list_new();
  597. /* Open info cache file */
  598. if (string_is_empty(info_dir))
  599. strlcpy(file_path, FILE_PATH_CORE_INFO_CACHE, sizeof(file_path));
  600. else
  601. fill_pathname_join_special(file_path, info_dir,
  602. FILE_PATH_CORE_INFO_CACHE,
  603. sizeof(file_path));
  604. #if defined(HAVE_ZLIB)
  605. file = intfstream_open_rzip_file(file_path,
  606. RETRO_VFS_FILE_ACCESS_READ);
  607. #else
  608. file = intfstream_open_file(file_path,
  609. RETRO_VFS_FILE_ACCESS_READ,
  610. RETRO_VFS_FILE_ACCESS_HINT_NONE);
  611. #endif
  612. if (!file)
  613. return core_info_cache_list_new();
  614. /* Parse info cache file */
  615. if (!(parser = rjson_open_stream(file)))
  616. {
  617. RARCH_ERR("[Core Info] Failed to create JSON parser\n");
  618. goto end;
  619. }
  620. rjson_set_options(parser,
  621. RJSON_OPTION_ALLOW_UTF8BOM
  622. | RJSON_OPTION_ALLOW_COMMENTS
  623. | RJSON_OPTION_ALLOW_UNESCAPED_CONTROL_CHARACTERS
  624. | RJSON_OPTION_REPLACE_INVALID_ENCODING);
  625. if (rjson_parse(parser, &context,
  626. CCJSONObjectMemberHandler,
  627. CCJSONStringHandler,
  628. CCJSONNumberHandler,
  629. CCJSONStartObjectHandler,
  630. CCJSONEndObjectHandler,
  631. CCJSONStartArrayHandler,
  632. CCJSONEndArrayHandler,
  633. CCJSONBoolHandler,
  634. NULL) /* Unused null handler */
  635. != RJSON_DONE)
  636. {
  637. RARCH_WARN("[Core Info] Error parsing chunk:\n---snip---\n%.*s\n---snip---\n",
  638. rjson_get_source_context_len(parser),
  639. rjson_get_source_context_buf(parser));
  640. RARCH_WARN("[Core Info] Error: Invalid JSON at line %d, column %d - %s.\n",
  641. (int)rjson_get_source_line(parser),
  642. (int)rjson_get_source_column(parser),
  643. (*rjson_get_error(parser)
  644. ? rjson_get_error(parser)
  645. : "format error"));
  646. /* Info cache is corrupt - discard it */
  647. core_info_cache_list_free(context.core_info_cache_list);
  648. core_info_cache_list = core_info_cache_list_new();
  649. }
  650. else
  651. core_info_cache_list = context.core_info_cache_list;
  652. rjson_free(parser);
  653. /* Clean up leftovers in the event of
  654. * a parsing error */
  655. if (context.core_info)
  656. {
  657. core_info_free(context.core_info);
  658. free(context.core_info);
  659. }
  660. if (!core_info_cache_list)
  661. goto end;
  662. /* If info cache file has the wrong version
  663. * number, discard it */
  664. if ( string_is_empty(core_info_cache_list->version)
  665. || !string_is_equal(core_info_cache_list->version,
  666. CORE_INFO_CACHE_VERSION))
  667. {
  668. RARCH_WARN("[Core Info] Core info cache has invalid version"
  669. " - forcing refresh (required v%s, found v%s)\n",
  670. CORE_INFO_CACHE_VERSION,
  671. core_info_cache_list->version);
  672. core_info_cache_list_free(context.core_info_cache_list);
  673. core_info_cache_list = core_info_cache_list_new();
  674. }
  675. end:
  676. intfstream_close(file);
  677. free(file);
  678. return core_info_cache_list;
  679. }
  680. #endif
  681. static bool core_info_cache_write(core_info_cache_list_t *list, const char *info_dir)
  682. {
  683. intfstream_t *file = NULL;
  684. rjsonwriter_t *writer = NULL;
  685. bool success = false;
  686. char file_path[PATH_MAX_LENGTH];
  687. size_t i, j;
  688. if (!list)
  689. return false;
  690. /* Open info cache file */
  691. if (string_is_empty(info_dir))
  692. strlcpy(file_path, FILE_PATH_CORE_INFO_CACHE, sizeof(file_path));
  693. else
  694. fill_pathname_join_special(file_path, info_dir,
  695. FILE_PATH_CORE_INFO_CACHE,
  696. sizeof(file_path));
  697. #if defined(CORE_INFO_CACHE_COMPRESS)
  698. file = intfstream_open_rzip_file(file_path,
  699. RETRO_VFS_FILE_ACCESS_WRITE);
  700. #else
  701. file = intfstream_open_file(file_path,
  702. RETRO_VFS_FILE_ACCESS_WRITE,
  703. RETRO_VFS_FILE_ACCESS_HINT_NONE);
  704. #endif
  705. if (!file)
  706. {
  707. RARCH_ERR("[Core Info] Failed to write to core info cache file: %s\n", file_path);
  708. return false;
  709. }
  710. /* Write info cache */
  711. if (!(writer = rjsonwriter_open_stream(file)))
  712. {
  713. RARCH_ERR("[Core Info] Failed to create JSON writer\n");
  714. goto end;
  715. }
  716. #if defined(CORE_INFO_CACHE_COMPRESS)
  717. /* When compressing info cache, human readability
  718. * is not a factor - can skip all indentation
  719. * and new line characters */
  720. rjsonwriter_set_options(writer, RJSONWRITER_OPTION_SKIP_WHITESPACE);
  721. #endif
  722. rjsonwriter_raw(writer, "{", 1);
  723. rjsonwriter_raw(writer, "\n", 1);
  724. rjsonwriter_add_spaces(writer, 2);
  725. rjsonwriter_add_string(writer, "version");
  726. rjsonwriter_raw(writer, ":", 1);
  727. rjsonwriter_raw(writer, " ", 1);
  728. rjsonwriter_add_string(writer, CORE_INFO_CACHE_VERSION);
  729. rjsonwriter_raw(writer, ",", 1);
  730. rjsonwriter_raw(writer, "\n", 1);
  731. rjsonwriter_add_spaces(writer, 2);
  732. rjsonwriter_add_string(writer, "items");
  733. rjsonwriter_raw(writer, ":", 1);
  734. rjsonwriter_raw(writer, " ", 1);
  735. rjsonwriter_raw(writer, "[", 1);
  736. rjsonwriter_raw(writer, "\n", 1);
  737. for (i = 0; i < list->length; i++)
  738. {
  739. core_info_t* info = &list->items[i];
  740. if (!info || !info->is_installed)
  741. continue;
  742. if (i > 0)
  743. {
  744. rjsonwriter_raw(writer, ",", 1);
  745. rjsonwriter_raw(writer, "\n", 1);
  746. }
  747. rjsonwriter_add_spaces(writer, 4);
  748. rjsonwriter_raw(writer, "{", 1);
  749. rjsonwriter_raw(writer, "\n", 1);
  750. rjsonwriter_add_spaces(writer, 6);
  751. rjsonwriter_add_string(writer, "display_name");
  752. rjsonwriter_raw(writer, ":", 1);
  753. rjsonwriter_raw(writer, " ", 1);
  754. rjsonwriter_add_string(writer, info->display_name);
  755. rjsonwriter_raw(writer, ",", 1);
  756. rjsonwriter_raw(writer, "\n", 1);
  757. rjsonwriter_add_spaces(writer, 6);
  758. rjsonwriter_add_string(writer, "display_version");
  759. rjsonwriter_raw(writer, ":", 1);
  760. rjsonwriter_raw(writer, " ", 1);
  761. rjsonwriter_add_string(writer, info->display_version);
  762. rjsonwriter_raw(writer, ",", 1);
  763. rjsonwriter_raw(writer, "\n", 1);
  764. rjsonwriter_add_spaces(writer, 6);
  765. rjsonwriter_add_string(writer, "core_name");
  766. rjsonwriter_raw(writer, ":", 1);
  767. rjsonwriter_raw(writer, " ", 1);
  768. rjsonwriter_add_string(writer, info->core_name);
  769. rjsonwriter_raw(writer, ",", 1);
  770. rjsonwriter_raw(writer, "\n", 1);
  771. rjsonwriter_add_spaces(writer, 6);
  772. rjsonwriter_add_string(writer, "system_manufacturer");
  773. rjsonwriter_raw(writer, ":", 1);
  774. rjsonwriter_raw(writer, " ", 1);
  775. rjsonwriter_add_string(writer, info->system_manufacturer);
  776. rjsonwriter_raw(writer, ",", 1);
  777. rjsonwriter_raw(writer, "\n", 1);
  778. rjsonwriter_add_spaces(writer, 6);
  779. rjsonwriter_add_string(writer, "systemname");
  780. rjsonwriter_raw(writer, ":", 1);
  781. rjsonwriter_raw(writer, " ", 1);
  782. rjsonwriter_add_string(writer, info->systemname);
  783. rjsonwriter_raw(writer, ",", 1);
  784. rjsonwriter_raw(writer, "\n", 1);
  785. rjsonwriter_add_spaces(writer, 6);
  786. rjsonwriter_add_string(writer, "system_id");
  787. rjsonwriter_raw(writer, ":", 1);
  788. rjsonwriter_raw(writer, " ", 1);
  789. rjsonwriter_add_string(writer, info->system_id);
  790. rjsonwriter_raw(writer, ",", 1);
  791. rjsonwriter_raw(writer, "\n", 1);
  792. rjsonwriter_add_spaces(writer, 6);
  793. rjsonwriter_add_string(writer, "supported_extensions");
  794. rjsonwriter_raw(writer, ":", 1);
  795. rjsonwriter_raw(writer, " ", 1);
  796. rjsonwriter_add_string(writer, info->supported_extensions);
  797. rjsonwriter_raw(writer, ",", 1);
  798. rjsonwriter_raw(writer, "\n", 1);
  799. rjsonwriter_add_spaces(writer, 6);
  800. rjsonwriter_add_string(writer, "authors");
  801. rjsonwriter_raw(writer, ":", 1);
  802. rjsonwriter_raw(writer, " ", 1);
  803. rjsonwriter_add_string(writer, info->authors);
  804. rjsonwriter_raw(writer, ",", 1);
  805. rjsonwriter_raw(writer, "\n", 1);
  806. rjsonwriter_add_spaces(writer, 6);
  807. rjsonwriter_add_string(writer, "permissions");
  808. rjsonwriter_raw(writer, ":", 1);
  809. rjsonwriter_raw(writer, " ", 1);
  810. rjsonwriter_add_string(writer, info->permissions);
  811. rjsonwriter_raw(writer, ",", 1);
  812. rjsonwriter_raw(writer, "\n", 1);
  813. rjsonwriter_add_spaces(writer, 6);
  814. rjsonwriter_add_string(writer, "licenses");
  815. rjsonwriter_raw(writer, ":", 1);
  816. rjsonwriter_raw(writer, " ", 1);
  817. rjsonwriter_add_string(writer, info->licenses);
  818. rjsonwriter_raw(writer, ",", 1);
  819. rjsonwriter_raw(writer, "\n", 1);
  820. rjsonwriter_add_spaces(writer, 6);
  821. rjsonwriter_add_string(writer, "categories");
  822. rjsonwriter_raw(writer, ":", 1);
  823. rjsonwriter_raw(writer, " ", 1);
  824. rjsonwriter_add_string(writer, info->categories);
  825. rjsonwriter_raw(writer, ",", 1);
  826. rjsonwriter_raw(writer, "\n", 1);
  827. rjsonwriter_add_spaces(writer, 6);
  828. rjsonwriter_add_string(writer, "databases");
  829. rjsonwriter_raw(writer, ":", 1);
  830. rjsonwriter_raw(writer, " ", 1);
  831. rjsonwriter_add_string(writer, info->databases);
  832. rjsonwriter_raw(writer, ",", 1);
  833. rjsonwriter_raw(writer, "\n", 1);
  834. rjsonwriter_add_spaces(writer, 6);
  835. rjsonwriter_add_string(writer, "notes");
  836. rjsonwriter_raw(writer, ":", 1);
  837. rjsonwriter_raw(writer, " ", 1);
  838. rjsonwriter_add_string(writer, info->notes);
  839. rjsonwriter_raw(writer, ",", 1);
  840. rjsonwriter_raw(writer, "\n", 1);
  841. rjsonwriter_add_spaces(writer, 6);
  842. rjsonwriter_add_string(writer, "required_hw_api");
  843. rjsonwriter_raw(writer, ":", 1);
  844. rjsonwriter_raw(writer, " ", 1);
  845. rjsonwriter_add_string(writer, info->required_hw_api);
  846. rjsonwriter_raw(writer, ",", 1);
  847. rjsonwriter_raw(writer, "\n", 1);
  848. rjsonwriter_add_spaces(writer, 6);
  849. rjsonwriter_add_string(writer, "description");
  850. rjsonwriter_raw(writer, ":", 1);
  851. rjsonwriter_raw(writer, " ", 1);
  852. rjsonwriter_add_string(writer, info->description);
  853. rjsonwriter_raw(writer, ",", 1);
  854. rjsonwriter_raw(writer, "\n", 1);
  855. if (info->firmware_count > 0)
  856. {
  857. rjsonwriter_add_spaces(writer, 6);
  858. rjsonwriter_add_string(writer, "firmware");
  859. rjsonwriter_raw(writer, ":", 1);
  860. rjsonwriter_raw(writer, " ", 1);
  861. rjsonwriter_raw(writer, "[", 1);
  862. rjsonwriter_raw(writer, "\n", 1);
  863. for (j = 0; j < info->firmware_count; j++)
  864. {
  865. rjsonwriter_add_spaces(writer, 8);
  866. rjsonwriter_raw(writer, "{", 1);
  867. rjsonwriter_raw(writer, "\n", 1);
  868. rjsonwriter_add_spaces(writer, 10);
  869. rjsonwriter_add_string(writer, "path");
  870. rjsonwriter_raw(writer, ":", 1);
  871. rjsonwriter_raw(writer, " ", 1);
  872. rjsonwriter_add_string(writer, info->firmware[j].path);
  873. rjsonwriter_raw(writer, ",", 1);
  874. rjsonwriter_raw(writer, "\n", 1);
  875. rjsonwriter_add_spaces(writer, 10);
  876. rjsonwriter_add_string(writer, "desc");
  877. rjsonwriter_raw(writer, ":", 1);
  878. rjsonwriter_raw(writer, " ", 1);
  879. rjsonwriter_add_string(writer, info->firmware[j].desc);
  880. rjsonwriter_raw(writer, ",", 1);
  881. rjsonwriter_raw(writer, "\n", 1);
  882. rjsonwriter_add_spaces(writer, 10);
  883. rjsonwriter_add_string(writer, "optional");
  884. rjsonwriter_raw(writer, ":", 1);
  885. rjsonwriter_raw(writer, " ", 1);
  886. {
  887. bool value = info->firmware[j].optional;
  888. rjsonwriter_raw(writer, (value ? "true" : "false"), (value ? 4 : 5));
  889. }
  890. rjsonwriter_raw(writer, "\n", 1);
  891. rjsonwriter_add_spaces(writer, 8);
  892. rjsonwriter_raw(writer, "}", 1);
  893. if (j < info->firmware_count - 1)
  894. rjsonwriter_raw(writer, ",", 1);
  895. rjsonwriter_raw(writer, "\n", 1);
  896. }
  897. rjsonwriter_add_spaces(writer, 6);
  898. rjsonwriter_raw(writer, "]", 1);
  899. rjsonwriter_raw(writer, ",", 1);
  900. rjsonwriter_raw(writer, "\n", 1);
  901. }
  902. rjsonwriter_add_spaces(writer, 6);
  903. rjsonwriter_add_string(writer, "core_file_id");
  904. rjsonwriter_raw(writer, ":", 1);
  905. rjsonwriter_raw(writer, "\n", 1);
  906. rjsonwriter_add_spaces(writer, 6);
  907. rjsonwriter_raw(writer, "{", 1);
  908. rjsonwriter_raw(writer, "\n", 1);
  909. rjsonwriter_add_spaces(writer, 8);
  910. rjsonwriter_add_string(writer, "str");
  911. rjsonwriter_raw(writer, ":", 1);
  912. rjsonwriter_raw(writer, " ", 1);
  913. rjsonwriter_add_string(writer, info->core_file_id.str);
  914. rjsonwriter_raw(writer, ",", 1);
  915. rjsonwriter_raw(writer, "\n", 1);
  916. rjsonwriter_add_spaces(writer, 8);
  917. rjsonwriter_add_string(writer, "hash");
  918. rjsonwriter_raw(writer, ":", 1);
  919. rjsonwriter_raw(writer, " ", 1);
  920. rjsonwriter_rawf(writer, "%u", info->core_file_id.hash);
  921. rjsonwriter_raw(writer, "\n", 1);
  922. rjsonwriter_add_spaces(writer, 6);
  923. rjsonwriter_raw(writer, "}", 1);
  924. rjsonwriter_raw(writer, ",", 1);
  925. rjsonwriter_raw(writer, "\n", 1);
  926. rjsonwriter_add_spaces(writer, 6);
  927. rjsonwriter_add_string(writer, "firmware_count");
  928. rjsonwriter_raw(writer, ":", 1);
  929. rjsonwriter_raw(writer, " ", 1);
  930. rjsonwriter_rawf(writer, "%u", info->firmware_count);
  931. rjsonwriter_raw(writer, ",", 1);
  932. rjsonwriter_raw(writer, "\n", 1);
  933. rjsonwriter_add_spaces(writer, 6);
  934. rjsonwriter_add_string(writer, "savestate_support_level");
  935. rjsonwriter_raw(writer, ":", 1);
  936. rjsonwriter_raw(writer, " ", 1);
  937. rjsonwriter_rawf(writer, "%u", info->savestate_support_level);
  938. rjsonwriter_raw(writer, ",", 1);
  939. rjsonwriter_raw(writer, "\n", 1);
  940. rjsonwriter_add_spaces(writer, 6);
  941. rjsonwriter_add_string(writer, "has_info");
  942. rjsonwriter_raw(writer, ":", 1);
  943. rjsonwriter_raw(writer, " ", 1);
  944. {
  945. bool value = info->has_info;
  946. rjsonwriter_raw(writer, (value ? "true" : "false"), (value ? 4 : 5));
  947. }
  948. rjsonwriter_raw(writer, ",", 1);
  949. rjsonwriter_raw(writer, "\n", 1);
  950. rjsonwriter_add_spaces(writer, 6);
  951. rjsonwriter_add_string(writer, "supports_no_game");
  952. rjsonwriter_raw(writer, ":", 1);
  953. rjsonwriter_raw(writer, " ", 1);
  954. {
  955. bool value = info->supports_no_game;
  956. rjsonwriter_raw(writer, (value ? "true" : "false"), (value ? 4 : 5));
  957. }
  958. rjsonwriter_raw(writer, ",", 1);
  959. rjsonwriter_raw(writer, "\n", 1);
  960. rjsonwriter_add_spaces(writer, 6);
  961. rjsonwriter_add_string(writer, "single_purpose");
  962. rjsonwriter_raw(writer, ":", 1);
  963. rjsonwriter_raw(writer, " ", 1);
  964. {
  965. bool value = info->single_purpose;
  966. rjsonwriter_raw(writer, (value ? "true" : "false"), (value ? 4 : 5));
  967. }
  968. rjsonwriter_raw(writer, ",", 1);
  969. rjsonwriter_raw(writer, "\n", 1);
  970. rjsonwriter_add_spaces(writer, 6);
  971. rjsonwriter_add_string(writer, "database_match_archive_member");
  972. rjsonwriter_raw(writer, ":", 1);
  973. rjsonwriter_raw(writer, " ", 1);
  974. {
  975. bool value = info->database_match_archive_member;
  976. rjsonwriter_raw(writer, (value ? "true" : "false"), (value ? 4 : 5));
  977. }
  978. rjsonwriter_raw(writer, ",", 1);
  979. rjsonwriter_raw(writer, "\n", 1);
  980. rjsonwriter_add_spaces(writer, 6);
  981. rjsonwriter_add_string(writer, "is_experimental");
  982. rjsonwriter_raw(writer, ":", 1);
  983. rjsonwriter_raw(writer, " ", 1);
  984. {
  985. bool value = info->is_experimental;
  986. rjsonwriter_raw(writer, (value ? "true" : "false"), (value ? 4 : 5));
  987. }
  988. rjsonwriter_raw(writer, "\n", 1);
  989. rjsonwriter_add_spaces(writer, 4);
  990. rjsonwriter_raw(writer, "}", 1);
  991. }
  992. rjsonwriter_raw(writer, "\n", 1);
  993. rjsonwriter_add_spaces(writer, 2);
  994. rjsonwriter_raw(writer, "]", 1);
  995. rjsonwriter_raw(writer, "\n", 1);
  996. rjsonwriter_raw(writer, "}", 1);
  997. rjsonwriter_raw(writer, "\n", 1);
  998. rjsonwriter_free(writer);
  999. RARCH_LOG("[Core Info] Wrote to cache file: %s\n", file_path);
  1000. success = true;
  1001. /* Remove 'force refresh' file, if required */
  1002. if (string_is_empty(info_dir))
  1003. strlcpy(file_path,
  1004. FILE_PATH_CORE_INFO_CACHE_REFRESH, sizeof(file_path));
  1005. else
  1006. fill_pathname_join_special(file_path,
  1007. info_dir, FILE_PATH_CORE_INFO_CACHE_REFRESH,
  1008. sizeof(file_path));
  1009. if (path_is_valid(file_path))
  1010. filestream_delete(file_path);
  1011. end:
  1012. intfstream_close(file);
  1013. free(file);
  1014. list->refresh = false;
  1015. return success;
  1016. }
  1017. static void core_info_check_uninstalled(core_info_cache_list_t *list)
  1018. {
  1019. size_t i;
  1020. if (!list)
  1021. return;
  1022. for (i = 0; i < list->length; i++)
  1023. {
  1024. core_info_t *info = (core_info_t *)&list->items[i];
  1025. if (!info)
  1026. continue;
  1027. if (!info->is_installed)
  1028. {
  1029. list->refresh = true;
  1030. return;
  1031. }
  1032. }
  1033. }
  1034. /* When called, generates a temporary file
  1035. * that will force an info cache refresh the
  1036. * next time that core info is initialised with
  1037. * caching enabled */
  1038. bool core_info_cache_force_refresh(const char *path_info)
  1039. {
  1040. char file_path[PATH_MAX_LENGTH];
  1041. /* Get 'force refresh' file path */
  1042. if (string_is_empty(path_info))
  1043. strlcpy(file_path,
  1044. FILE_PATH_CORE_INFO_CACHE_REFRESH, sizeof(file_path));
  1045. else
  1046. fill_pathname_join_special(file_path,
  1047. path_info, FILE_PATH_CORE_INFO_CACHE_REFRESH,
  1048. sizeof(file_path));
  1049. /* Generate a new, empty 'force refresh' file,
  1050. * if required */
  1051. if (!path_is_valid(file_path))
  1052. {
  1053. RFILE *refresh_file = filestream_open(
  1054. file_path,
  1055. RETRO_VFS_FILE_ACCESS_WRITE,
  1056. RETRO_VFS_FILE_ACCESS_HINT_NONE);
  1057. if (!refresh_file)
  1058. return false;
  1059. /* We have to write something - just output
  1060. * a single character */
  1061. if (filestream_putc(refresh_file, 0) != 0)
  1062. {
  1063. filestream_close(refresh_file);
  1064. return false;
  1065. }
  1066. filestream_close(refresh_file);
  1067. }
  1068. return true;
  1069. }
  1070. /***********************/
  1071. /* Core Info Cache END */
  1072. /***********************/
  1073. typedef struct
  1074. {
  1075. const char *path;
  1076. const char *filename;
  1077. } core_file_path_t;
  1078. typedef struct
  1079. {
  1080. core_file_path_t *list;
  1081. size_t size;
  1082. } core_file_path_list_t;
  1083. typedef struct
  1084. {
  1085. const char *filename;
  1086. uint32_t hash;
  1087. } core_aux_file_path_t;
  1088. typedef struct
  1089. {
  1090. core_aux_file_path_t *list;
  1091. size_t size;
  1092. } core_aux_file_path_list_t;
  1093. typedef struct
  1094. {
  1095. struct string_list *dir_list;
  1096. core_file_path_list_t *core_list;
  1097. core_aux_file_path_list_t *lock_list;
  1098. core_aux_file_path_list_t *standalone_exempt_list;
  1099. } core_path_list_t;
  1100. static uint32_t core_info_hash_string(const char *str)
  1101. {
  1102. unsigned char c;
  1103. uint32_t hash = (uint32_t)0x811c9dc5;
  1104. while ((c = (unsigned char)*(str++)) != '\0')
  1105. hash = ((hash * (uint32_t)0x01000193) ^ (uint32_t)c);
  1106. return (hash ? hash : 1);
  1107. }
  1108. static void core_info_path_list_free(core_path_list_t *path_list)
  1109. {
  1110. if (!path_list)
  1111. return;
  1112. if (path_list->core_list)
  1113. {
  1114. if (path_list->core_list->list)
  1115. free(path_list->core_list->list);
  1116. free(path_list->core_list);
  1117. }
  1118. if (path_list->lock_list)
  1119. {
  1120. if (path_list->lock_list->list)
  1121. free(path_list->lock_list->list);
  1122. free(path_list->lock_list);
  1123. }
  1124. if (path_list->standalone_exempt_list)
  1125. {
  1126. if (path_list->standalone_exempt_list->list)
  1127. free(path_list->standalone_exempt_list->list);
  1128. free(path_list->standalone_exempt_list);
  1129. }
  1130. if (path_list->dir_list)
  1131. string_list_free(path_list->dir_list);
  1132. free(path_list);
  1133. }
  1134. static core_path_list_t *core_info_path_list_new(const char *core_dir,
  1135. const char *core_exts, bool show_hidden_files)
  1136. {
  1137. size_t i;
  1138. char exts[32];
  1139. core_path_list_t *path_list = NULL;
  1140. struct string_list *core_ext_list = NULL;
  1141. bool dir_list_ok = false;
  1142. if (string_is_empty(core_exts))
  1143. return NULL;
  1144. if (!(path_list = (core_path_list_t*)calloc(1, sizeof(*path_list))))
  1145. return NULL;
  1146. if (!(core_ext_list = string_split(core_exts, "|")))
  1147. {
  1148. core_info_path_list_free(path_list);
  1149. return NULL;
  1150. }
  1151. /* Allocate list containers */
  1152. path_list->dir_list = string_list_new();
  1153. path_list->core_list = (core_file_path_list_t*)
  1154. calloc(1, sizeof(*path_list->core_list));
  1155. path_list->lock_list = (core_aux_file_path_list_t*)
  1156. calloc(1, sizeof(*path_list->lock_list));
  1157. path_list->standalone_exempt_list = (core_aux_file_path_list_t*)
  1158. calloc(1, sizeof(*path_list->standalone_exempt_list));
  1159. if ( !path_list->dir_list
  1160. || !path_list->core_list
  1161. || !path_list->lock_list
  1162. || !path_list->standalone_exempt_list)
  1163. goto error;
  1164. /* Get list of file extensions to include
  1165. * > core + lock */
  1166. strlcpy(exts, core_exts, sizeof(exts));
  1167. strlcat(exts, "|lck", sizeof(exts));
  1168. #if defined(HAVE_DYNAMIC)
  1169. /* > 'standalone exempt' */
  1170. strlcat(exts, "|lsae", sizeof(exts));
  1171. #endif
  1172. /* Fetch core directory listing */
  1173. dir_list_ok = dir_list_append(path_list->dir_list,
  1174. core_dir, exts, false, show_hidden_files,
  1175. false, false);
  1176. #if defined(__WINRT__) || defined(WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
  1177. {
  1178. /* UWP: browse the optional packages for additional cores */
  1179. struct string_list core_packages = {0};
  1180. if (string_list_initialize(&core_packages))
  1181. {
  1182. uwp_fill_installed_core_packages(&core_packages);
  1183. for (i = 0; i < core_packages.size; i++)
  1184. dir_list_append(path_list->dir_list,
  1185. core_packages.elems[i].data, exts, false,
  1186. show_hidden_files, false, false);
  1187. string_list_deinitialize(&core_packages);
  1188. }
  1189. }
  1190. #else
  1191. /* Keep the old 'directory not found' behaviour */
  1192. if (!dir_list_ok)
  1193. goto error;
  1194. #endif
  1195. /* Allocate sub lists */
  1196. path_list->core_list->list = (core_file_path_t*)
  1197. malloc(path_list->dir_list->size *
  1198. sizeof(*path_list->core_list->list));
  1199. path_list->lock_list->list = (core_aux_file_path_t*)
  1200. malloc(path_list->dir_list->size *
  1201. sizeof(*path_list->lock_list->list));
  1202. path_list->standalone_exempt_list->list = (core_aux_file_path_t*)
  1203. malloc(path_list->dir_list->size *
  1204. sizeof(*path_list->standalone_exempt_list->list));
  1205. if ( !path_list->core_list->list
  1206. || !path_list->lock_list->list
  1207. || !path_list->standalone_exempt_list->list)
  1208. goto error;
  1209. /* Parse directory listing */
  1210. for (i = 0; i < path_list->dir_list->size; i++)
  1211. {
  1212. const char *file_path = path_list->dir_list->elems[i].data;
  1213. const char *filename = NULL;
  1214. const char *file_ext = NULL;
  1215. if ( string_is_empty(file_path)
  1216. || !(filename = path_basename_nocompression(file_path))
  1217. || !(file_ext = path_get_extension(filename)))
  1218. continue;
  1219. /* Check whether this is a core, lock or
  1220. * 'standalone exempt' file */
  1221. if (string_list_find_elem(core_ext_list, file_ext))
  1222. {
  1223. path_list->core_list->list[
  1224. path_list->core_list->size].path = file_path;
  1225. path_list->core_list->list[
  1226. path_list->core_list->size].filename = filename;
  1227. path_list->core_list->size++;
  1228. }
  1229. else if (string_is_equal(file_ext, FILE_PATH_LOCK_EXTENSION_NO_DOT))
  1230. {
  1231. path_list->lock_list->list[
  1232. path_list->lock_list->size].filename = filename;
  1233. path_list->lock_list->list[
  1234. path_list->lock_list->size].hash = core_info_hash_string(filename);
  1235. path_list->lock_list->size++;
  1236. }
  1237. #if defined(HAVE_DYNAMIC)
  1238. else if (string_is_equal(file_ext, FILE_PATH_STANDALONE_EXEMPT_EXTENSION_NO_DOT))
  1239. {
  1240. path_list->standalone_exempt_list->list[
  1241. path_list->standalone_exempt_list->size].filename = filename;
  1242. path_list->standalone_exempt_list->list[
  1243. path_list->standalone_exempt_list->size].hash = core_info_hash_string(filename);
  1244. path_list->standalone_exempt_list->size++;
  1245. }
  1246. #endif
  1247. }
  1248. string_list_free(core_ext_list);
  1249. return path_list;
  1250. error:
  1251. string_list_free(core_ext_list);
  1252. core_info_path_list_free(path_list);
  1253. return NULL;
  1254. }
  1255. static bool core_info_path_is_locked(
  1256. core_aux_file_path_list_t *lock_list,
  1257. const char *core_file_name)
  1258. {
  1259. size_t i, len;
  1260. uint32_t hash;
  1261. char lock_filename[NAME_MAX_LENGTH];
  1262. if (lock_list->size < 1)
  1263. return false;
  1264. len = strlcpy(lock_filename, core_file_name,
  1265. sizeof(lock_filename));
  1266. lock_filename[len ] = '.';
  1267. lock_filename[len+1] = 'l';
  1268. lock_filename[len+2] = 'c';
  1269. lock_filename[len+3] = 'k';
  1270. lock_filename[len+4] = '\0';
  1271. hash = core_info_hash_string(lock_filename);
  1272. for (i = 0; i < lock_list->size; i++)
  1273. {
  1274. core_aux_file_path_t *lock_file = &lock_list->list[i];
  1275. if ( (lock_file->hash == hash)
  1276. && string_is_equal(lock_file->filename, lock_filename))
  1277. return true;
  1278. }
  1279. return false;
  1280. }
  1281. static bool core_info_path_is_standalone_exempt(
  1282. core_aux_file_path_list_t *exempt_list,
  1283. const char *core_file_name)
  1284. {
  1285. size_t i, len;
  1286. uint32_t hash;
  1287. char exempt_filename[NAME_MAX_LENGTH];
  1288. if (exempt_list->size < 1)
  1289. return false;
  1290. len = strlcpy(exempt_filename, core_file_name,
  1291. sizeof(exempt_filename));
  1292. exempt_filename[len ] = '.';
  1293. exempt_filename[len+1] = 'l';
  1294. exempt_filename[len+2] = 's';
  1295. exempt_filename[len+3] = 'a';
  1296. exempt_filename[len+4] = 'e';
  1297. exempt_filename[len+5] = '\0';
  1298. hash = core_info_hash_string(exempt_filename);
  1299. for (i = 0; i < exempt_list->size; i++)
  1300. {
  1301. core_aux_file_path_t *exempt_file = &exempt_list->list[i];
  1302. if ( (exempt_file->hash == hash)
  1303. && string_is_equal(exempt_file->filename, exempt_filename))
  1304. return true;
  1305. }
  1306. return false;
  1307. }
  1308. static bool core_info_get_file_id(const char *core_filename,
  1309. char *core_file_id, size_t len)
  1310. {
  1311. char *last_underscore = NULL;
  1312. if (string_is_empty(core_filename))
  1313. return false;
  1314. /* Core file 'id' is filename without extension
  1315. * or platform-specific suffix */
  1316. /* > Remove extension */
  1317. strlcpy(core_file_id, core_filename, len);
  1318. path_remove_extension(core_file_id);
  1319. /* > Remove suffix */
  1320. last_underscore = (char*)strrchr(core_file_id, '_');
  1321. if ( !string_is_empty(last_underscore)
  1322. && !string_is_equal(last_underscore, "_libretro"))
  1323. *last_underscore = '\0';
  1324. return !string_is_empty(core_file_id);
  1325. }
  1326. static core_info_t *core_info_find_internal(
  1327. core_info_list_t *list,
  1328. const char *core_path)
  1329. {
  1330. size_t i;
  1331. uint32_t hash;
  1332. char core_file_id[256];
  1333. if ( !list
  1334. || string_is_empty(core_path)
  1335. || !core_info_get_file_id(path_basename_nocompression(core_path),
  1336. core_file_id, sizeof(core_file_id)))
  1337. return NULL;
  1338. hash = core_info_hash_string(core_file_id);
  1339. for (i = 0; i < list->count; i++)
  1340. {
  1341. core_info_t *info = &list->list[i];
  1342. if ( (info->core_file_id.hash == hash)
  1343. && string_is_equal(info->core_file_id.str, core_file_id))
  1344. return info;
  1345. }
  1346. return NULL;
  1347. }
  1348. static void core_info_resolve_firmware(
  1349. core_info_t *info, config_file_t *conf)
  1350. {
  1351. unsigned i;
  1352. size_t _len;
  1353. char prefix[12];
  1354. unsigned firmware_count = 0;
  1355. core_info_firmware_t *firmware = NULL;
  1356. if (!config_get_uint(conf, "firmware_count", &firmware_count))
  1357. return;
  1358. firmware = (core_info_firmware_t*)calloc(
  1359. firmware_count, sizeof(*firmware));
  1360. if (!firmware)
  1361. return;
  1362. _len = strlcpy(prefix, "firmware", sizeof(prefix));
  1363. for (i = 0; i < firmware_count; i++)
  1364. {
  1365. char path_key[64];
  1366. char desc_key[64];
  1367. char opt_key[64];
  1368. struct config_entry_list *entry = NULL;
  1369. bool tmp_bool = false;
  1370. snprintf(prefix + _len, sizeof(prefix) - _len, "%u_", i);
  1371. strlcpy(path_key, prefix, sizeof(path_key));
  1372. strlcat(path_key, "path", sizeof(path_key));
  1373. strlcpy(desc_key, prefix, sizeof(desc_key));
  1374. strlcat(desc_key, "desc", sizeof(desc_key));
  1375. strlcpy(opt_key, prefix, sizeof(opt_key));
  1376. strlcat(opt_key, "opt", sizeof(opt_key));
  1377. entry = config_get_entry(conf, path_key);
  1378. if (entry && !string_is_empty(entry->value))
  1379. {
  1380. firmware[i].path = entry->value;
  1381. entry->value = NULL;
  1382. }
  1383. entry = config_get_entry(conf, desc_key);
  1384. if (entry && !string_is_empty(entry->value))
  1385. {
  1386. firmware[i].desc = entry->value;
  1387. entry->value = NULL;
  1388. }
  1389. if (config_get_bool(conf, opt_key , &tmp_bool))
  1390. firmware[i].optional = tmp_bool;
  1391. }
  1392. info->firmware_count = firmware_count;
  1393. info->firmware = firmware;
  1394. }
  1395. static config_file_t *core_info_get_config_file(
  1396. const char *core_file_id, const char *info_dir)
  1397. {
  1398. if (!string_is_empty(info_dir))
  1399. {
  1400. char info_path[PATH_MAX_LENGTH];
  1401. fill_pathname_join_special(info_path, info_dir,
  1402. core_file_id, sizeof(info_path));
  1403. return config_file_new_from_path_to_string(info_path);
  1404. }
  1405. return config_file_new_from_path_to_string(core_file_id);
  1406. }
  1407. static void core_info_parse_config_file(
  1408. core_info_list_t *list, core_info_t *info,
  1409. config_file_t *conf)
  1410. {
  1411. bool tmp_bool = false;
  1412. struct config_entry_list *entry = config_get_entry(conf, "display_name");
  1413. if (entry && !string_is_empty(entry->value))
  1414. {
  1415. info->display_name = entry->value;
  1416. entry->value = NULL;
  1417. }
  1418. entry = config_get_entry(conf, "display_version");
  1419. if (entry && !string_is_empty(entry->value))
  1420. {
  1421. info->display_version = entry->value;
  1422. entry->value = NULL;
  1423. }
  1424. entry = config_get_entry(conf, "corename");
  1425. if (entry && !string_is_empty(entry->value))
  1426. {
  1427. info->core_name = entry->value;
  1428. entry->value = NULL;
  1429. }
  1430. entry = config_get_entry(conf, "systemname");
  1431. if (entry && !string_is_empty(entry->value))
  1432. {
  1433. info->systemname = entry->value;
  1434. entry->value = NULL;
  1435. }
  1436. entry = config_get_entry(conf, "systemid");
  1437. if (entry && !string_is_empty(entry->value))
  1438. {
  1439. info->system_id = entry->value;
  1440. entry->value = NULL;
  1441. }
  1442. entry = config_get_entry(conf, "manufacturer");
  1443. if (entry && !string_is_empty(entry->value))
  1444. {
  1445. info->system_manufacturer = entry->value;
  1446. entry->value = NULL;
  1447. }
  1448. entry = config_get_entry(conf, "supported_extensions");
  1449. if (entry && !string_is_empty(entry->value))
  1450. {
  1451. info->supported_extensions = entry->value;
  1452. entry->value = NULL;
  1453. info->supported_extensions_list =
  1454. string_split(info->supported_extensions, "|");
  1455. }
  1456. entry = config_get_entry(conf, "authors");
  1457. if (entry && !string_is_empty(entry->value))
  1458. {
  1459. info->authors = entry->value;
  1460. entry->value = NULL;
  1461. info->authors_list =
  1462. string_split(info->authors, "|");
  1463. }
  1464. entry = config_get_entry(conf, "permissions");
  1465. if (entry && !string_is_empty(entry->value))
  1466. {
  1467. info->permissions = entry->value;
  1468. entry->value = NULL;
  1469. info->permissions_list =
  1470. string_split(info->permissions, "|");
  1471. }
  1472. entry = config_get_entry(conf, "license");
  1473. if (entry && !string_is_empty(entry->value))
  1474. {
  1475. info->licenses = entry->value;
  1476. entry->value = NULL;
  1477. info->licenses_list =
  1478. string_split(info->licenses, "|");
  1479. }
  1480. entry = config_get_entry(conf, "categories");
  1481. if (entry && !string_is_empty(entry->value))
  1482. {
  1483. info->categories = entry->value;
  1484. entry->value = NULL;
  1485. info->categories_list =
  1486. string_split(info->categories, "|");
  1487. }
  1488. entry = config_get_entry(conf, "database");
  1489. if (entry && !string_is_empty(entry->value))
  1490. {
  1491. info->databases = entry->value;
  1492. entry->value = NULL;
  1493. info->databases_list =
  1494. string_split(info->databases, "|");
  1495. }
  1496. entry = config_get_entry(conf, "notes");
  1497. if (entry && !string_is_empty(entry->value))
  1498. {
  1499. info->notes = entry->value;
  1500. entry->value = NULL;
  1501. info->note_list =
  1502. string_split(info->notes, "|");
  1503. }
  1504. entry = config_get_entry(conf, "required_hw_api");
  1505. if (entry && !string_is_empty(entry->value))
  1506. {
  1507. info->required_hw_api = entry->value;
  1508. entry->value = NULL;
  1509. info->required_hw_api_list =
  1510. string_split(info->required_hw_api, "|");
  1511. }
  1512. entry = config_get_entry(conf, "description");
  1513. if (entry && !string_is_empty(entry->value))
  1514. {
  1515. info->description = entry->value;
  1516. entry->value = NULL;
  1517. }
  1518. if (config_get_bool(conf, "supports_no_game",
  1519. &tmp_bool))
  1520. info->supports_no_game = tmp_bool;
  1521. if (config_get_bool(conf, "single_purpose",
  1522. &tmp_bool))
  1523. info->single_purpose = tmp_bool;
  1524. if (config_get_bool(conf, "database_match_archive_member",
  1525. &tmp_bool))
  1526. info->database_match_archive_member = tmp_bool;
  1527. if (config_get_bool(conf, "is_experimental",
  1528. &tmp_bool))
  1529. info->is_experimental = tmp_bool;
  1530. /* Savestate support level is slightly more complex,
  1531. * since it is a value derived from two configuration
  1532. * parameters */
  1533. /* > Assume all cores have 'full' savestate support
  1534. * by default */
  1535. info->savestate_support_level =
  1536. CORE_INFO_SAVESTATE_DETERMINISTIC;
  1537. /* > Check whether savestate functionality is defined
  1538. * in the info file */
  1539. if (config_get_bool(conf, "savestate", &tmp_bool))
  1540. {
  1541. if (tmp_bool)
  1542. {
  1543. /* Check if savestate features are defined */
  1544. entry = config_get_entry(conf, "savestate_features");
  1545. if (entry && !string_is_empty(entry->value))
  1546. {
  1547. if (string_is_equal(entry->value, "basic"))
  1548. info->savestate_support_level =
  1549. CORE_INFO_SAVESTATE_BASIC;
  1550. else if (string_is_equal(entry->value, "serialized"))
  1551. info->savestate_support_level =
  1552. CORE_INFO_SAVESTATE_SERIALIZED;
  1553. }
  1554. }
  1555. else
  1556. info->savestate_support_level =
  1557. CORE_INFO_SAVESTATE_DISABLED;
  1558. }
  1559. core_info_resolve_firmware(info, conf);
  1560. info->has_info = true;
  1561. list->info_count++;
  1562. }
  1563. static void core_info_list_resolve_all_extensions(
  1564. core_info_list_t *core_info_list)
  1565. {
  1566. size_t i = 0;
  1567. size_t all_ext_len = 0;
  1568. char *all_ext = NULL;
  1569. for (i = 0; i < core_info_list->count; i++)
  1570. {
  1571. if (core_info_list->list[i].supported_extensions)
  1572. all_ext_len +=
  1573. (strlen(core_info_list->list[i].supported_extensions) + 2);
  1574. }
  1575. all_ext_len += STRLEN_CONST("7z|") + STRLEN_CONST("zip|");
  1576. if (!(all_ext = (char*)calloc(1, all_ext_len)))
  1577. return;
  1578. core_info_list->all_ext = all_ext;
  1579. for (i = 0; i < core_info_list->count; i++)
  1580. {
  1581. if (!core_info_list->list[i].supported_extensions)
  1582. continue;
  1583. strlcat(core_info_list->all_ext,
  1584. core_info_list->list[i].supported_extensions, all_ext_len);
  1585. strlcat(core_info_list->all_ext, "|", all_ext_len);
  1586. }
  1587. #ifdef HAVE_7ZIP
  1588. strlcat(core_info_list->all_ext, "7z|", all_ext_len);
  1589. #endif
  1590. #ifdef HAVE_ZLIB
  1591. strlcat(core_info_list->all_ext, "zip|", all_ext_len);
  1592. #endif
  1593. }
  1594. static void core_info_free(core_info_t* info)
  1595. {
  1596. size_t i;
  1597. free(info->path);
  1598. free(info->core_name);
  1599. free(info->systemname);
  1600. free(info->system_id);
  1601. free(info->system_manufacturer);
  1602. free(info->display_name);
  1603. free(info->display_version);
  1604. free(info->supported_extensions);
  1605. free(info->authors);
  1606. free(info->permissions);
  1607. free(info->licenses);
  1608. free(info->categories);
  1609. free(info->databases);
  1610. free(info->notes);
  1611. free(info->required_hw_api);
  1612. free(info->description);
  1613. string_list_free(info->supported_extensions_list);
  1614. string_list_free(info->authors_list);
  1615. string_list_free(info->note_list);
  1616. string_list_free(info->permissions_list);
  1617. string_list_free(info->licenses_list);
  1618. string_list_free(info->categories_list);
  1619. string_list_free(info->databases_list);
  1620. string_list_free(info->required_hw_api_list);
  1621. for (i = 0; i < info->firmware_count; i++)
  1622. {
  1623. if (info->firmware[i].path)
  1624. free(info->firmware[i].path);
  1625. if (info->firmware[i].desc)
  1626. free(info->firmware[i].desc);
  1627. info->firmware[i].path = NULL;
  1628. info->firmware[i].desc = NULL;
  1629. }
  1630. free(info->firmware);
  1631. free(info->core_file_id.str);
  1632. }
  1633. static void core_info_list_free(core_info_list_t *core_info_list)
  1634. {
  1635. size_t i;
  1636. if (!core_info_list)
  1637. return;
  1638. for (i = 0; i < core_info_list->count; i++)
  1639. {
  1640. core_info_t *info = (core_info_t*)&core_info_list->list[i];
  1641. core_info_free(info);
  1642. }
  1643. free(core_info_list->all_ext);
  1644. free(core_info_list->list);
  1645. free(core_info_list);
  1646. }
  1647. static core_info_list_t *core_info_list_new(const char *path,
  1648. const char *libretro_info_dir,
  1649. const char *exts,
  1650. bool dir_show_hidden_files,
  1651. bool enable_cache,
  1652. bool *cache_supported)
  1653. {
  1654. size_t i;
  1655. core_info_t *core_info = NULL;
  1656. core_info_list_t *core_info_list = NULL;
  1657. core_info_cache_list_t *core_info_cache_list = NULL;
  1658. const char *info_dir = libretro_info_dir;
  1659. core_path_list_t *path_list = core_info_path_list_new(
  1660. path, exts, dir_show_hidden_files);
  1661. if (!path_list)
  1662. goto error;
  1663. if (!(core_info_list = (core_info_list_t*)malloc(sizeof(*core_info_list))))
  1664. goto error;
  1665. core_info_list->list = NULL;
  1666. core_info_list->count = 0;
  1667. core_info_list->info_count = 0;
  1668. core_info_list->all_ext = NULL;
  1669. if (!(core_info = (core_info_t*)calloc(path_list->core_list->size,
  1670. sizeof(*core_info))))
  1671. {
  1672. core_info_list_free(core_info_list);
  1673. goto error;
  1674. }
  1675. core_info_list->list = core_info;
  1676. core_info_list->count = path_list->core_list->size;
  1677. #ifdef HAVE_CORE_INFO_CACHE
  1678. /* Read core info cache, if enabled */
  1679. if (enable_cache)
  1680. {
  1681. core_info_cache_list = core_info_cache_read(info_dir);
  1682. if (!core_info_cache_list)
  1683. goto error;
  1684. }
  1685. #endif
  1686. for (i = 0; i < path_list->core_list->size; i++)
  1687. {
  1688. core_info_t *info = &core_info[i];
  1689. core_file_path_t *core_file = &path_list->core_list->list[i];
  1690. const char *base_path = core_file->path;
  1691. const char *core_filename = core_file->filename;
  1692. config_file_t *conf = NULL;
  1693. char core_file_id[256];
  1694. if (!core_info_get_file_id(core_filename, core_file_id,
  1695. sizeof(core_file_id)))
  1696. continue;
  1697. /* If info cache is available, search for
  1698. * current core */
  1699. if (core_info_cache_list)
  1700. {
  1701. core_info_t *info_cache = core_info_cache_find(
  1702. core_info_cache_list, core_file_id);
  1703. if (info_cache)
  1704. {
  1705. core_info_copy(info_cache, info);
  1706. /* Core path is 'dynamic', and cannot
  1707. * be cached (i.e. core directory may
  1708. * change between runs) */
  1709. if (info->path)
  1710. free(info->path);
  1711. info->path = strdup(base_path);
  1712. /* Core lock status is 'dynamic', and
  1713. * cannot be cached */
  1714. info->is_locked = core_info_path_is_locked(
  1715. path_list->lock_list, core_filename);
  1716. /* Core 'standalone exempt' status is 'dynamic',
  1717. * and cannot be cached
  1718. * > It is also dependent upon whether the core
  1719. * supports contentless operation */
  1720. info->is_standalone_exempt = info->supports_no_game &&
  1721. core_info_path_is_standalone_exempt(
  1722. path_list->standalone_exempt_list,
  1723. core_filename);
  1724. /* 'info_count' is normally incremented inside
  1725. * core_info_parse_config_file(). If core entry
  1726. * is cached, must instead increment the value
  1727. * here */
  1728. if (info->has_info)
  1729. core_info_list->info_count++;
  1730. continue;
  1731. }
  1732. }
  1733. /* Cache core path */
  1734. info->path = strdup(base_path);
  1735. /* Get core lock status */
  1736. info->is_locked = core_info_path_is_locked(
  1737. path_list->lock_list, core_filename);
  1738. /* Cache core file 'id' */
  1739. info->core_file_id.str = strdup(core_file_id);
  1740. info->core_file_id.hash = core_info_hash_string(core_file_id);
  1741. strlcat(core_file_id, ".info", sizeof(core_file_id));
  1742. /* Parse core info file */
  1743. if ((conf = core_info_get_config_file(core_file_id, info_dir)))
  1744. {
  1745. core_info_parse_config_file(core_info_list, info, conf);
  1746. config_file_free(conf);
  1747. }
  1748. /* Get fallback display name, if required */
  1749. if (!info->display_name)
  1750. info->display_name = strdup(core_filename);
  1751. /* Get core 'standalone exempt' status */
  1752. info->is_standalone_exempt = info->supports_no_game &&
  1753. core_info_path_is_standalone_exempt(
  1754. path_list->standalone_exempt_list,
  1755. core_filename);
  1756. info->is_installed = true;
  1757. /* If info cache is enabled and we reach this
  1758. * point, current core is uncached
  1759. * > Add it to the list, and trigger a cache
  1760. * refresh */
  1761. if (core_info_cache_list)
  1762. {
  1763. core_info_cache_add(core_info_cache_list, info, false);
  1764. core_info_cache_list->refresh = true;
  1765. }
  1766. }
  1767. core_info_list_resolve_all_extensions(core_info_list);
  1768. /* If info cache is enabled
  1769. * > Check whether any cached cores have been
  1770. * uninstalled since the last run (triggers
  1771. * a refresh)
  1772. * > Write new cache to disk if updates are
  1773. * required */
  1774. *cache_supported = true;
  1775. if (core_info_cache_list)
  1776. {
  1777. core_info_check_uninstalled(core_info_cache_list);
  1778. if (core_info_cache_list->refresh)
  1779. *cache_supported = core_info_cache_write(
  1780. core_info_cache_list, info_dir);
  1781. core_info_cache_list_free(core_info_cache_list);
  1782. }
  1783. core_info_path_list_free(path_list);
  1784. return core_info_list;
  1785. error:
  1786. core_info_path_list_free(path_list);
  1787. return NULL;
  1788. }
  1789. /* Shallow-copies internal state.
  1790. *
  1791. * Data in *info is invalidated when the
  1792. * core_info_list is freed. */
  1793. bool core_info_list_get_info(core_info_list_t *core_info_list,
  1794. core_info_t *out_info, const char *core_path)
  1795. {
  1796. if (out_info)
  1797. {
  1798. core_info_t *info = core_info_find_internal(
  1799. core_info_list, core_path);
  1800. memset(out_info, 0, sizeof(*out_info));
  1801. if (info)
  1802. {
  1803. *out_info = *info;
  1804. return true;
  1805. }
  1806. }
  1807. return false;
  1808. }
  1809. #ifdef HAVE_COMPRESSION
  1810. static bool core_info_does_support_any_file(const core_info_t *core,
  1811. const struct string_list *list)
  1812. {
  1813. size_t i;
  1814. if (!list || !core || !core->supported_extensions_list)
  1815. return false;
  1816. for (i = 0; i < list->size; i++)
  1817. if (string_list_find_elem_prefix(core->supported_extensions_list,
  1818. ".", path_get_extension(list->elems[i].data)))
  1819. return true;
  1820. return false;
  1821. }
  1822. #endif
  1823. static bool core_info_does_support_file(
  1824. const core_info_t *core, const char *path)
  1825. {
  1826. if (!core || !core->supported_extensions_list)
  1827. return false;
  1828. if (string_is_empty(path))
  1829. return false;
  1830. return string_list_find_elem_prefix(
  1831. core->supported_extensions_list, ".", path_get_extension(path));
  1832. }
  1833. /* qsort_r() is not in standard C, sadly. */
  1834. static int core_info_qsort_cmp(const void *a_, const void *b_)
  1835. {
  1836. core_info_state_t *p_coreinfo = &core_info_st;
  1837. const core_info_t *a = (const core_info_t*)a_;
  1838. const core_info_t *b = (const core_info_t*)b_;
  1839. int support_a = core_info_does_support_file(a,
  1840. p_coreinfo->tmp_path);
  1841. int support_b = core_info_does_support_file(b,
  1842. p_coreinfo->tmp_path);
  1843. #ifdef HAVE_COMPRESSION
  1844. support_a = support_a ||
  1845. core_info_does_support_any_file(a, p_coreinfo->tmp_list);
  1846. support_b = support_b ||
  1847. core_info_does_support_any_file(b, p_coreinfo->tmp_list);
  1848. #endif
  1849. if (support_a != support_b)
  1850. return support_b - support_a;
  1851. return strcasecmp(a->display_name, b->display_name);
  1852. }
  1853. static bool core_info_list_update_missing_firmware_internal(
  1854. core_info_list_t *core_info_list,
  1855. const char *core_path,
  1856. const char *systemdir,
  1857. bool *set_missing_bios)
  1858. {
  1859. size_t i;
  1860. char path[PATH_MAX_LENGTH];
  1861. core_info_t *info = NULL;
  1862. if (!core_info_list)
  1863. return false;
  1864. if (!(info = core_info_find_internal(
  1865. core_info_list, core_path)))
  1866. return false;
  1867. for (i = 0; i < info->firmware_count; i++)
  1868. {
  1869. if (string_is_empty(info->firmware[i].path))
  1870. continue;
  1871. fill_pathname_join(path, systemdir,
  1872. info->firmware[i].path, sizeof(path));
  1873. info->firmware[i].missing = !path_is_valid(path);
  1874. if (info->firmware[i].missing && !info->firmware[i].optional)
  1875. *set_missing_bios = true;
  1876. }
  1877. return true;
  1878. }
  1879. void core_info_free_current_core(void)
  1880. {
  1881. core_info_state_t *p_coreinfo = &core_info_st;
  1882. if (p_coreinfo->current)
  1883. free(p_coreinfo->current);
  1884. p_coreinfo->current = NULL;
  1885. }
  1886. bool core_info_init_current_core(void)
  1887. {
  1888. core_info_state_t *p_coreinfo = &core_info_st;
  1889. core_info_t *current = (core_info_t*)
  1890. malloc(sizeof(*current));
  1891. if (!current)
  1892. return false;
  1893. current->has_info = false;
  1894. current->supports_no_game = false;
  1895. current->single_purpose = false;
  1896. current->database_match_archive_member = false;
  1897. current->is_experimental = false;
  1898. current->is_locked = false;
  1899. current->is_standalone_exempt = false;
  1900. current->is_installed = false;
  1901. current->firmware_count = 0;
  1902. current->savestate_support_level = CORE_INFO_SAVESTATE_DETERMINISTIC;
  1903. current->path = NULL;
  1904. current->display_name = NULL;
  1905. current->display_version = NULL;
  1906. current->core_name = NULL;
  1907. current->system_manufacturer = NULL;
  1908. current->systemname = NULL;
  1909. current->system_id = NULL;
  1910. current->supported_extensions = NULL;
  1911. current->authors = NULL;
  1912. current->permissions = NULL;
  1913. current->licenses = NULL;
  1914. current->categories = NULL;
  1915. current->databases = NULL;
  1916. current->notes = NULL;
  1917. current->required_hw_api = NULL;
  1918. current->description = NULL;
  1919. current->categories_list = NULL;
  1920. current->databases_list = NULL;
  1921. current->note_list = NULL;
  1922. current->supported_extensions_list = NULL;
  1923. current->authors_list = NULL;
  1924. current->permissions_list = NULL;
  1925. current->licenses_list = NULL;
  1926. current->required_hw_api_list = NULL;
  1927. current->firmware = NULL;
  1928. current->core_file_id.str = NULL;
  1929. current->core_file_id.hash = 0;
  1930. p_coreinfo->current = current;
  1931. return true;
  1932. }
  1933. bool core_info_get_current_core(core_info_t **core)
  1934. {
  1935. core_info_state_t *p_coreinfo = &core_info_st;
  1936. if (!core)
  1937. return false;
  1938. *core = p_coreinfo->current;
  1939. return true;
  1940. }
  1941. void core_info_deinit_list(void)
  1942. {
  1943. core_info_state_t *p_coreinfo = &core_info_st;
  1944. if (p_coreinfo->curr_list)
  1945. core_info_list_free(p_coreinfo->curr_list);
  1946. p_coreinfo->curr_list = NULL;
  1947. }
  1948. bool core_info_init_list(
  1949. const char *path_info, const char *dir_cores,
  1950. const char *exts, bool dir_show_hidden_files,
  1951. bool enable_cache, bool *cache_supported)
  1952. {
  1953. core_info_state_t *p_coreinfo = &core_info_st;
  1954. if (!(p_coreinfo->curr_list = core_info_list_new(
  1955. dir_cores,
  1956. !string_is_empty(path_info)
  1957. ? path_info
  1958. : dir_cores,
  1959. exts,
  1960. dir_show_hidden_files,
  1961. enable_cache,
  1962. cache_supported)))
  1963. return false;
  1964. return true;
  1965. }
  1966. bool core_info_get_list(core_info_list_t **core)
  1967. {
  1968. core_info_state_t *p_coreinfo = &core_info_st;
  1969. if (!core)
  1970. return false;
  1971. *core = p_coreinfo->curr_list;
  1972. return true;
  1973. }
  1974. /* Returns number of installed cores */
  1975. size_t core_info_count(void)
  1976. {
  1977. core_info_state_t *p_coreinfo = &core_info_st;
  1978. if (p_coreinfo && p_coreinfo->curr_list)
  1979. return p_coreinfo->curr_list->count;
  1980. return 0;
  1981. }
  1982. bool core_info_list_update_missing_firmware(
  1983. core_info_ctx_firmware_t *info, bool *set_missing_bios)
  1984. {
  1985. core_info_state_t *p_coreinfo = &core_info_st;
  1986. if (info)
  1987. return core_info_list_update_missing_firmware_internal(
  1988. p_coreinfo->curr_list,
  1989. info->path, info->directory.system,
  1990. set_missing_bios);
  1991. return false;
  1992. }
  1993. bool core_info_load(const char *core_path)
  1994. {
  1995. core_info_state_t *p_coreinfo = &core_info_st;
  1996. core_info_t *core_info = NULL;
  1997. if (!p_coreinfo->current)
  1998. core_info_init_current_core();
  1999. core_info_get_current_core(&core_info);
  2000. if (!p_coreinfo->curr_list)
  2001. return false;
  2002. if (!core_info_list_get_info(p_coreinfo->curr_list,
  2003. core_info, core_path))
  2004. return false;
  2005. return true;
  2006. }
  2007. bool core_info_find(const char *core_path,
  2008. core_info_t **core_info)
  2009. {
  2010. core_info_state_t *p_coreinfo = &core_info_st;
  2011. core_info_t *info = NULL;
  2012. if (!core_info || !p_coreinfo->curr_list)
  2013. return false;
  2014. if (!(info = core_info_find_internal(p_coreinfo->curr_list, core_path)))
  2015. return false;
  2016. *core_info = info;
  2017. return true;
  2018. }
  2019. core_info_t *core_info_get(core_info_list_t *list, size_t i)
  2020. {
  2021. core_info_t *info = NULL;
  2022. if (!list || (i >= list->count))
  2023. return NULL;
  2024. info = (core_info_t*)&list->list[i];
  2025. if (!info || !info->path)
  2026. return NULL;
  2027. return info;
  2028. }
  2029. void core_info_list_get_supported_cores(core_info_list_t *core_info_list,
  2030. const char *path, const core_info_t **infos, size_t *num_infos)
  2031. {
  2032. size_t i;
  2033. size_t supported = 0;
  2034. #ifdef HAVE_COMPRESSION
  2035. struct string_list *list = NULL;
  2036. #endif
  2037. core_info_state_t *p_coreinfo = &core_info_st;
  2038. if (!core_info_list)
  2039. return;
  2040. p_coreinfo->tmp_path = path;
  2041. #ifdef HAVE_COMPRESSION
  2042. if (path_is_compressed_file(path))
  2043. list = file_archive_get_file_list(path, NULL);
  2044. p_coreinfo->tmp_list = list;
  2045. #endif
  2046. /* Let supported core come first in list so we can return
  2047. * a pointer to them. */
  2048. qsort(core_info_list->list, core_info_list->count,
  2049. sizeof(core_info_t), core_info_qsort_cmp);
  2050. for (i = 0; i < core_info_list->count; i++, supported++)
  2051. {
  2052. const core_info_t *core = &core_info_list->list[i];
  2053. if (core_info_does_support_file(core, path))
  2054. continue;
  2055. #ifdef HAVE_COMPRESSION
  2056. if (core_info_does_support_any_file(core, list))
  2057. continue;
  2058. #endif
  2059. break;
  2060. }
  2061. #ifdef HAVE_COMPRESSION
  2062. if (list)
  2063. string_list_free(list);
  2064. #endif
  2065. *infos = core_info_list->list;
  2066. *num_infos = supported;
  2067. }
  2068. /*
  2069. * Matches core A and B file IDs
  2070. *
  2071. * e.g.:
  2072. * snes9x_libretro.dll and snes9x_libretro_android.so are matched
  2073. * snes9x__2005_libretro.dll and snes9x_libretro_android.so are
  2074. * NOT matched
  2075. */
  2076. bool core_info_core_file_id_is_equal(const char *core_path_a,
  2077. const char *core_path_b)
  2078. {
  2079. char core_file_id_a[256];
  2080. char core_file_id_b[256];
  2081. if ( string_is_empty(core_path_a)
  2082. || string_is_empty(core_path_b)
  2083. || !core_info_get_file_id(
  2084. path_basename_nocompression(core_path_a),
  2085. core_file_id_a, sizeof(core_file_id_a))
  2086. || !core_info_get_file_id(
  2087. path_basename_nocompression(core_path_b),
  2088. core_file_id_b, sizeof(core_file_id_b)))
  2089. return false;
  2090. return string_is_equal(core_file_id_a, core_file_id_b);
  2091. }
  2092. bool core_info_database_match_archive_member(const char *database_path)
  2093. {
  2094. char *database = NULL;
  2095. const char *new_path = path_basename_nocompression(
  2096. database_path);
  2097. core_info_state_t *p_coreinfo = NULL;
  2098. if (string_is_empty(new_path))
  2099. return false;
  2100. if (!(database = strdup(new_path)))
  2101. return false;
  2102. path_remove_extension(database);
  2103. p_coreinfo = &core_info_st;
  2104. if (p_coreinfo->curr_list)
  2105. {
  2106. size_t i;
  2107. for (i = 0; i < p_coreinfo->curr_list->count; i++)
  2108. {
  2109. const core_info_t *info = &p_coreinfo->curr_list->list[i];
  2110. if (!info->database_match_archive_member)
  2111. continue;
  2112. if (!string_list_find_elem(info->databases_list, database))
  2113. continue;
  2114. free(database);
  2115. return true;
  2116. }
  2117. }
  2118. free(database);
  2119. return false;
  2120. }
  2121. bool core_info_database_supports_content_path(
  2122. const char *database_path, const char *path)
  2123. {
  2124. char *database = NULL;
  2125. const char *new_path = path_basename(database_path);
  2126. core_info_state_t *p_coreinfo = NULL;
  2127. if (string_is_empty(new_path))
  2128. return false;
  2129. if (!(database = strdup(new_path)))
  2130. return false;
  2131. path_remove_extension(database);
  2132. p_coreinfo = &core_info_st;
  2133. if (p_coreinfo->curr_list)
  2134. {
  2135. size_t i;
  2136. for (i = 0; i < p_coreinfo->curr_list->count; i++)
  2137. {
  2138. const core_info_t *info = &p_coreinfo->curr_list->list[i];
  2139. if (!string_list_find_elem(info->supported_extensions_list,
  2140. path_get_extension(path)))
  2141. continue;
  2142. if (!string_list_find_elem(info->databases_list, database))
  2143. continue;
  2144. free(database);
  2145. return true;
  2146. }
  2147. }
  2148. free(database);
  2149. return false;
  2150. }
  2151. bool core_info_list_get_display_name(
  2152. core_info_list_t *core_info_list,
  2153. const char *core_path, char *s, size_t len)
  2154. {
  2155. core_info_t *info;
  2156. if (!core_info_list)
  2157. return false;
  2158. info = core_info_find_internal(
  2159. core_info_list, core_path);
  2160. if ( s
  2161. && info
  2162. && !string_is_empty(info->display_name))
  2163. {
  2164. strlcpy(s, info->display_name, len);
  2165. return true;
  2166. }
  2167. return false;
  2168. }
  2169. /* Returns core_info parameters required for
  2170. * core updater tasks, read from specified file.
  2171. * Returned core_updater_info_t object must be
  2172. * freed using core_info_free_core_updater_info().
  2173. * Returns NULL if 'path' is invalid. */
  2174. core_updater_info_t *core_info_get_core_updater_info(
  2175. const char *info_path)
  2176. {
  2177. struct config_entry_list
  2178. *entry = NULL;
  2179. bool tmp_bool = false;
  2180. core_updater_info_t *info = NULL;
  2181. config_file_t *conf = NULL;
  2182. if (string_is_empty(info_path))
  2183. return NULL;
  2184. /* Read config file */
  2185. if (!(conf = config_file_new_from_path_to_string(info_path)))
  2186. return NULL;
  2187. /* Create info struct */
  2188. if (!(info = (core_updater_info_t*)malloc(sizeof(*info))))
  2189. return NULL;
  2190. info->is_experimental = false;
  2191. info->display_name = NULL;
  2192. info->description = NULL;
  2193. info->licenses = NULL;
  2194. /* Fetch required parameters */
  2195. /* > is_experimental */
  2196. if (config_get_bool(conf, "is_experimental", &tmp_bool))
  2197. info->is_experimental = tmp_bool;
  2198. /* > display_name */
  2199. entry = config_get_entry(conf, "display_name");
  2200. if (entry && !string_is_empty(entry->value))
  2201. {
  2202. info->display_name = entry->value;
  2203. entry->value = NULL;
  2204. }
  2205. /* > description */
  2206. entry = config_get_entry(conf, "description");
  2207. if (entry && !string_is_empty(entry->value))
  2208. {
  2209. info->description = entry->value;
  2210. entry->value = NULL;
  2211. }
  2212. /* > licenses */
  2213. entry = config_get_entry(conf, "license");
  2214. if (entry && !string_is_empty(entry->value))
  2215. {
  2216. info->licenses = entry->value;
  2217. entry->value = NULL;
  2218. }
  2219. /* Clean up */
  2220. config_file_free(conf);
  2221. return info;
  2222. }
  2223. void core_info_free_core_updater_info(core_updater_info_t *info)
  2224. {
  2225. if (!info)
  2226. return;
  2227. if (info->display_name)
  2228. free(info->display_name);
  2229. if (info->description)
  2230. free(info->description);
  2231. if (info->licenses)
  2232. free(info->licenses);
  2233. free(info);
  2234. info = NULL;
  2235. }
  2236. static int core_info_qsort_func_path(const core_info_t *a,
  2237. const core_info_t *b)
  2238. {
  2239. if (!a || !b || string_is_empty(a->path) || string_is_empty(b->path))
  2240. return 0;
  2241. return strcasecmp(a->path, b->path);
  2242. }
  2243. static int core_info_qsort_func_display_name(const core_info_t *a,
  2244. const core_info_t *b)
  2245. {
  2246. if ( !a
  2247. || !b
  2248. || string_is_empty(a->display_name)
  2249. || string_is_empty(b->display_name))
  2250. return 0;
  2251. return strcasecmp(a->display_name, b->display_name);
  2252. }
  2253. static int core_info_qsort_func_core_name(const core_info_t *a,
  2254. const core_info_t *b)
  2255. {
  2256. if ( !a
  2257. || !b
  2258. || string_is_empty(a->core_name)
  2259. || string_is_empty(b->core_name))
  2260. return 0;
  2261. return strcasecmp(a->core_name, b->core_name);
  2262. }
  2263. static int core_info_qsort_func_system_name(const core_info_t *a,
  2264. const core_info_t *b)
  2265. {
  2266. if (
  2267. !a
  2268. || !b
  2269. || string_is_empty(a->systemname)
  2270. || string_is_empty(b->systemname))
  2271. return 0;
  2272. return strcasecmp(a->systemname, b->systemname);
  2273. }
  2274. void core_info_qsort(core_info_list_t *core_info_list,
  2275. enum core_info_list_qsort_type qsort_type)
  2276. {
  2277. if (!core_info_list)
  2278. return;
  2279. if (core_info_list->count < 2)
  2280. return;
  2281. switch (qsort_type)
  2282. {
  2283. case CORE_INFO_LIST_SORT_PATH:
  2284. qsort(core_info_list->list,
  2285. core_info_list->count,
  2286. sizeof(core_info_t),
  2287. (int (*)(const void *, const void *))
  2288. core_info_qsort_func_path);
  2289. break;
  2290. case CORE_INFO_LIST_SORT_DISPLAY_NAME:
  2291. qsort(core_info_list->list,
  2292. core_info_list->count,
  2293. sizeof(core_info_t),
  2294. (int (*)(const void *, const void *))
  2295. core_info_qsort_func_display_name);
  2296. break;
  2297. case CORE_INFO_LIST_SORT_CORE_NAME:
  2298. qsort(core_info_list->list,
  2299. core_info_list->count,
  2300. sizeof(core_info_t),
  2301. (int (*)(const void *, const void *))
  2302. core_info_qsort_func_core_name);
  2303. break;
  2304. case CORE_INFO_LIST_SORT_SYSTEM_NAME:
  2305. qsort(core_info_list->list,
  2306. core_info_list->count,
  2307. sizeof(core_info_t),
  2308. (int (*)(const void *, const void *))
  2309. core_info_qsort_func_system_name);
  2310. break;
  2311. default:
  2312. break;
  2313. }
  2314. }
  2315. bool core_info_current_supports_savestate(void)
  2316. {
  2317. core_info_state_t *p_coreinfo = &core_info_st;
  2318. settings_t *settings = config_get_ptr();
  2319. if (settings->bools.core_info_savestate_bypass)
  2320. return true;
  2321. /* If no core is currently loaded, assume
  2322. * by default that all savestate functionality
  2323. * is supported */
  2324. if (!p_coreinfo->current)
  2325. return true;
  2326. return p_coreinfo->current->savestate_support_level >=
  2327. CORE_INFO_SAVESTATE_BASIC;
  2328. }
  2329. bool core_info_current_supports_rewind(void)
  2330. {
  2331. core_info_state_t *p_coreinfo = &core_info_st;
  2332. settings_t *settings = config_get_ptr();
  2333. if (settings->bools.core_info_savestate_bypass)
  2334. return true;
  2335. /* If no core is currently loaded, assume
  2336. * by default that all savestate functionality
  2337. * is supported */
  2338. if (!p_coreinfo->current)
  2339. return true;
  2340. return p_coreinfo->current->savestate_support_level >=
  2341. CORE_INFO_SAVESTATE_SERIALIZED;
  2342. }
  2343. bool core_info_current_supports_netplay(void)
  2344. {
  2345. core_info_state_t *p_coreinfo = &core_info_st;
  2346. settings_t *settings = config_get_ptr();
  2347. if (settings->bools.core_info_savestate_bypass)
  2348. return true;
  2349. /* If no core is currently loaded, assume
  2350. * by default that all savestate functionality
  2351. * is supported */
  2352. if (!p_coreinfo->current)
  2353. return true;
  2354. return p_coreinfo->current->savestate_support_level >=
  2355. CORE_INFO_SAVESTATE_DETERMINISTIC;
  2356. }
  2357. bool core_info_current_supports_runahead(void)
  2358. {
  2359. core_info_state_t *p_coreinfo = &core_info_st;
  2360. settings_t *settings = config_get_ptr();
  2361. if (settings->bools.core_info_savestate_bypass)
  2362. return true;
  2363. /* If no core is currently loaded, assume
  2364. * by default that all savestate functionality
  2365. * is supported */
  2366. if (!p_coreinfo->current)
  2367. return true;
  2368. return p_coreinfo->current->savestate_support_level >=
  2369. CORE_INFO_SAVESTATE_DETERMINISTIC;
  2370. }
  2371. static bool core_info_update_core_aux_file(const char *path, bool create)
  2372. {
  2373. bool aux_file_exists = false;
  2374. if (string_is_empty(path))
  2375. return false;
  2376. /* Check whether aux file exists */
  2377. aux_file_exists = path_is_valid(path);
  2378. /* Create or delete aux file, as required */
  2379. if (create && !aux_file_exists)
  2380. {
  2381. RFILE *aux_file = filestream_open(path,
  2382. RETRO_VFS_FILE_ACCESS_WRITE,
  2383. RETRO_VFS_FILE_ACCESS_HINT_NONE);
  2384. if (!aux_file)
  2385. return false;
  2386. /* We have to write something - just output
  2387. * a single character */
  2388. if (filestream_putc(aux_file, 0) != 0)
  2389. {
  2390. filestream_close(aux_file);
  2391. return false;
  2392. }
  2393. filestream_close(aux_file);
  2394. }
  2395. else if (!create && aux_file_exists)
  2396. if (filestream_delete(path) != 0)
  2397. return false;
  2398. return true;
  2399. }
  2400. /* Sets 'locked' status of specified core
  2401. * > Returns true if successful
  2402. * > Like all functions that access the cached
  2403. * core info list this is *not* thread safe */
  2404. bool core_info_set_core_lock(const char *core_path, bool lock)
  2405. {
  2406. size_t len;
  2407. core_info_t *core_info = NULL;
  2408. char lock_file_path[PATH_MAX_LENGTH];
  2409. #if defined(ANDROID)
  2410. /* Play Store builds do not support
  2411. * core locking */
  2412. if (play_feature_delivery_enabled())
  2413. return false;
  2414. #endif
  2415. /* Search for specified core */
  2416. if (
  2417. string_is_empty(core_path)
  2418. || !core_info_find(core_path, &core_info)
  2419. || string_is_empty(core_info->path))
  2420. return false;
  2421. /* Get lock file path */
  2422. len = strlcpy(
  2423. lock_file_path, core_info->path, sizeof(lock_file_path));
  2424. lock_file_path[len ] = '.';
  2425. lock_file_path[len+1] = 'l';
  2426. lock_file_path[len+2] = 'c';
  2427. lock_file_path[len+3] = 'k';
  2428. lock_file_path[len+4] = '\0';
  2429. /* Create or delete lock file, as required */
  2430. if (!core_info_update_core_aux_file(lock_file_path, lock))
  2431. return false;
  2432. /* File operations were successful - update
  2433. * core info entry */
  2434. core_info->is_locked = lock;
  2435. return true;
  2436. }
  2437. /* Fetches 'locked' status of specified core
  2438. * > If 'validate_path' is 'true', will search
  2439. * cached core info list for a corresponding
  2440. * 'sanitised' core file path. This is *not*
  2441. * thread safe
  2442. * > If 'validate_path' is 'false', performs a
  2443. * direct filesystem check. This *is* thread
  2444. * safe, but validity of specified core path
  2445. * must be checked externally */
  2446. bool core_info_get_core_lock(const char *core_path, bool validate_path)
  2447. {
  2448. size_t len;
  2449. core_info_t *core_info = NULL;
  2450. const char *core_file_path = NULL;
  2451. bool is_locked = false;
  2452. char lock_file_path[PATH_MAX_LENGTH];
  2453. #if defined(ANDROID)
  2454. /* Play Store builds do not support
  2455. * core locking */
  2456. if (play_feature_delivery_enabled())
  2457. return false;
  2458. #endif
  2459. if (string_is_empty(core_path))
  2460. return false;
  2461. /* Check whether core path is to be validated */
  2462. if (validate_path)
  2463. {
  2464. if (core_info_find(core_path, &core_info))
  2465. core_file_path = core_info->path;
  2466. }
  2467. else
  2468. core_file_path = core_path;
  2469. /* A core cannot be locked if it does not exist... */
  2470. if ( string_is_empty(core_file_path)
  2471. || !path_is_valid(core_file_path))
  2472. return false;
  2473. /* Get lock file path */
  2474. len = strlcpy(
  2475. lock_file_path, core_file_path,
  2476. sizeof(lock_file_path));
  2477. lock_file_path[len ] = '.';
  2478. lock_file_path[len+1] = 'l';
  2479. lock_file_path[len+2] = 'c';
  2480. lock_file_path[len+3] = 'k';
  2481. lock_file_path[len+4] = '\0';
  2482. /* Check whether lock file exists */
  2483. is_locked = path_is_valid(lock_file_path);
  2484. /* If core path has been validated (and a
  2485. * core info object is available), ensure
  2486. * that core info 'is_locked' field is
  2487. * up to date */
  2488. if (validate_path && core_info)
  2489. core_info->is_locked = is_locked;
  2490. return is_locked;
  2491. }
  2492. /* Sets 'standalone exempt' status of specified core
  2493. * > A 'standalone exempt' core will not be shown
  2494. * in the contentless cores menu when display type
  2495. * is set to 'custom'
  2496. * > Returns true if successful
  2497. * > Returns false if core does not support
  2498. * contentless operation
  2499. * > *Not* thread safe */
  2500. bool core_info_set_core_standalone_exempt(const char *core_path, bool exempt)
  2501. {
  2502. /* Static platforms do not support the contentless
  2503. * cores menu */
  2504. #if defined(HAVE_DYNAMIC)
  2505. size_t _len;
  2506. core_info_t *core_info = NULL;
  2507. char exempt_file_path[PATH_MAX_LENGTH];
  2508. /* Search for specified core */
  2509. if ( string_is_empty(core_path)
  2510. || !core_info_find(core_path, &core_info)
  2511. || string_is_empty(core_info->path)
  2512. || !core_info->supports_no_game)
  2513. return false;
  2514. /* Get 'standalone exempt' file path */
  2515. _len = strlcpy(exempt_file_path, core_info->path,
  2516. sizeof(exempt_file_path));
  2517. exempt_file_path[_len ] = '.';
  2518. exempt_file_path[_len+1] = 'l';
  2519. exempt_file_path[_len+2] = 's';
  2520. exempt_file_path[_len+3] = 'a';
  2521. exempt_file_path[_len+4] = 'e';
  2522. exempt_file_path[_len+5] = '\0';
  2523. /* Create or delete 'standalone exempt' file, as required */
  2524. if (core_info_update_core_aux_file(exempt_file_path, exempt))
  2525. {
  2526. /* File operations were successful - update
  2527. * core info entry */
  2528. core_info->is_standalone_exempt = exempt;
  2529. return true;
  2530. }
  2531. #endif
  2532. return false;
  2533. }
  2534. /* Fetches 'standalone exempt' status of specified core
  2535. * > Returns true if core should be excluded from
  2536. * the contentless cores menu when display type is
  2537. * set to 'custom'
  2538. * > *Not* thread safe */
  2539. bool core_info_get_core_standalone_exempt(const char *core_path)
  2540. {
  2541. /* Static platforms do not support the contentless
  2542. * cores menu */
  2543. #if defined(HAVE_DYNAMIC)
  2544. size_t _len;
  2545. core_info_t *core_info = NULL;
  2546. char exempt_file_path[PATH_MAX_LENGTH];
  2547. /* Search for specified core */
  2548. if ( string_is_empty(core_path)
  2549. || !core_info_find(core_path, &core_info)
  2550. || string_is_empty(core_info->path)
  2551. || !core_info->supports_no_game)
  2552. return false;
  2553. /* Get 'standalone exempt' file path */
  2554. _len = strlcpy(
  2555. exempt_file_path, core_info->path,
  2556. sizeof(exempt_file_path));
  2557. exempt_file_path[_len ] = '.';
  2558. exempt_file_path[_len+1] = 'l';
  2559. exempt_file_path[_len+2] = 's';
  2560. exempt_file_path[_len+3] = 'a';
  2561. exempt_file_path[_len+4] = 'e';
  2562. exempt_file_path[_len+5] = '\0';
  2563. /* Check whether 'standalone exempt' file exists */
  2564. if (path_is_valid(exempt_file_path))
  2565. {
  2566. core_info->is_standalone_exempt = true;
  2567. return true;
  2568. }
  2569. core_info->is_standalone_exempt = false;
  2570. #endif
  2571. return false;
  2572. }