filesystem.monkey2 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931
  1. Namespace std.filesystem
  2. Using libc
  3. #Import "native/filesystem.h"
  4. #Import "native/filesystem.cpp"
  5. #If __TARGET__="android"
  6. #Import "native/Monkey2FileSystem.java"
  7. Using android
  8. #Elseif __TARGET__="ios"
  9. #Import "native/filesystem.mm"
  10. #endif
  11. #If __TARGET__="android"
  12. Extern Private
  13. Function fopenAsset:FILE Ptr( asset:AAsset )="bbFileSystem::fopenAsset"
  14. #endif
  15. Extern
  16. #rem monkeydoc Gets application directory.
  17. @return The directory containing the application executable.
  18. #end
  19. Function AppDir:String()="bbFileSystem::appDir"
  20. #rem monkeydoc Gets the application file path.
  21. @return The path of the application executable.
  22. #end
  23. Function AppPath:String()="bbFileSystem::appPath"
  24. #rem monkeydoc Gets application command line arguments.
  25. The first argument is always the application name.
  26. @return The application command line arguments.
  27. #end
  28. Function AppArgs:String[]()="bbFileSystem::appArgs"
  29. #rem monkeydoc Copies a file.
  30. Copies a file from `srcPath` to `dstPath`, overwriting `dstpath` if it alreay exits.
  31. Returns true if successful.
  32. @return True if the file was successfully copied.
  33. #end
  34. Function CopyFile:Bool( srcPath:String,dstPath:String )="bbFileSystem::copyFile"
  35. Private
  36. Global _config:=New StringMap<String>
  37. Function FixPath:String( path:String )
  38. path=path.Replace( "\","/" )
  39. Local root:=ExtractRootDir( path )
  40. If Not root.EndsWith( "::" ) Return path
  41. path=path.Slice( root.Length )
  42. Select root
  43. Case "asset::" return AssetsDir()+path
  44. #If __MOBILE_TARGET__
  45. Case "internal::" Return InternalDir()+path
  46. Case "external::" Return ExternalDir()+path
  47. #endif
  48. End
  49. Return ""
  50. End
  51. Function FixFilePath:String( path:String )
  52. Return FixPath( StripSlashes( path ) )
  53. End
  54. #If __TARGET__="android"
  55. Function GetSpecialDir:String( name:String )
  56. Global _class:jclass
  57. Global _getSpecialDir:jmethodID
  58. Local env:=sdl2.Android_JNI_GetEnv()
  59. If Not _getSpecialDir
  60. _class=env.FindClass( "com/monkey2/lib/Monkey2FileSystem" )
  61. _getSpecialDir=env.GetStaticMethodID( _class,"getSpecialDir","(Ljava/lang/String;)Ljava/lang/String;" )
  62. Endif
  63. Local dir:=env.CallStaticStringMethod( _class,_getSpecialDir,New Variant[]( name ) )
  64. Return dir
  65. End
  66. #Elseif __TARGET__="ios"
  67. Extern Private
  68. Function GetSpecialDir:String( name:String )="bbFileSystem::getSpecialDir"
  69. Private
  70. #else
  71. Function GetSpecialDir:String( name:String )
  72. Return ""
  73. End
  74. #Endif
  75. Public
  76. #rem monkeydoc FileType enumeration.
  77. | FileType | Description
  78. |:--------------|:-----------
  79. | `None` | File does not exist.
  80. | `File` | File is a normal file.
  81. | `Directory` | File is a directory.
  82. | `Unknown` | File is of unknown type.
  83. #end
  84. Enum FileType
  85. None=0
  86. File=1
  87. Directory=2
  88. Unknown=3
  89. End
  90. 'For backward compatibility - don't use!
  91. '
  92. #rem monkeydoc @hidden
  93. #end
  94. Const FILETYPE_NONE:=FileType.None
  95. #rem monkeydoc @hidden
  96. #end
  97. Const FILETYPE_FILE:=FileType.File
  98. #rem monkeydoc @hidden
  99. #end
  100. Const FILETYPE_DIR:=FileType.Directory
  101. #rem monkeydoc @hidden
  102. #end
  103. Const FILETYPE_UNKNOWN:=FileType.Unknown
  104. #rem monkeydoc Gets an environment variable.
  105. Returns the value of the given environment variable, or `defaultValue` if none was found.
  106. #end
  107. Function GetEnv:String( name:String,defaultValue:String="" )
  108. Local p:=getenv( name )
  109. If p Return String.FromCString( p )
  110. Return defaultValue
  111. End
  112. #rem monkeydoc Sets an environment variable.
  113. Sets the value of a given environment variable.
  114. #end
  115. Function SetEnv( name:String,value:String )
  116. setenv( name,value,1 )
  117. End
  118. #rem monkeydoc Gets a global config setting.
  119. See also [[SetConfig]] for a list of possible config settings.
  120. #end
  121. Function GetConfig:String( name:String,defaultValue:String="" )
  122. Return _config.Contains( name ) ? _config[name] Else defaultValue
  123. End
  124. #rem monkeydoc Sets a global config setting.
  125. Currently recognized built-in config settings:
  126. | Name | More information
  127. |:----------------------------------|:----------------
  128. | "MOJO\_OPENGL\_PROFILE" | [[mojo:mojo.app.AppInstance|mojo.AppInstance]]
  129. | "MOJO\_OPENGL\_VERSION\_MAJOR" | [[mojo:mojo.app.AppInstance|mojo.AppInstance]]
  130. | "MOJO\_OPENGL\_VERSION\_MINOR" | [[mojo:mojo.app.AppInstance|mojo.AppInstance]]
  131. | "MOJO\_COLOR\_BUFFER\_BITS" | [[mojo:mojo.app.AppInstance|mojo.AppInstance]]
  132. | "MOJO\_DEPTH\_BUFFER\_BITS" | [[mojo:mojo.app.AppInstance|mojo.AppInstance]]
  133. | "MOJO\_STENCIL\_BUFFER\_BITS" | [[mojo:mojo.app.AppInstance|mojo.AppInstance]]
  134. | "MOJO\_TEXTURE\_MAX\_ANISOTROPY" | [[mojo:mojo.graphics.Texture|mojo.Texture]]
  135. | "MOJO3D\_RENDERER" | [[mojo3d:mojo3d.Renderer|mojo3d.Renderer]]
  136. See also: [[GetConfig]].
  137. #end
  138. Function SetConfig( name:String,value:String )
  139. If value _config[name]=value Else _config.Remove( name )
  140. End
  141. Private
  142. Global _assetsDir:String
  143. Public
  144. #rem monkeydoc Gets the filesystem directory of the app's assets directory.
  145. Note that only the desktop and web targets have an assets directory. Other targets will return an empty string.
  146. @return The directory app assets are stored in.
  147. #end
  148. Function AssetsDir:String()
  149. If Not _assetsDir
  150. #If __TARGET__="macos"
  151. _assetsDir=ExtractDir( AppDir() )+"Resources/"
  152. #Else If __DESKTOP_TARGET__ Or __WEB_TARGET__
  153. _assetsDir=AppDir()+"assets/"
  154. #Else If __TARGET__="ios"
  155. _assetsDir=GetSpecialDir( "assets" )
  156. #Else
  157. _assetsDir="${ASSETS}/" '"asset::"
  158. #Endif
  159. Endif
  160. Return _assetsDir
  161. End
  162. #rem monkeydoc Changes the assets dir.
  163. Set to an empty string to use the default assets dir.
  164. #end
  165. Function SetAssetsDir( dir:String )
  166. If dir dir=RealPath( FixFilePath( dir ) )+"/"
  167. _assetsDir=dir
  168. End
  169. #rem monkeydoc Gets the filesystem directory of the user's desktop directory.
  170. Note that only the desktop targets have a desktop directory. Other targets will return an empty string.
  171. @return The desktop directory.
  172. #end
  173. Function DesktopDir:String()
  174. #If __TARGET__="windows"
  175. Return GetEnv( "USERPROFILE" ).Replace( "\","/" )+"/Desktop/"
  176. #Else If __DESKTOP_TARGET__
  177. Return GetEnv( "HOME" )+"/Desktop/"
  178. #Else
  179. Return "${DESKTOP}/"
  180. #Endif
  181. End
  182. #rem monkeydoc Gets the filesystem directory of the user's home directory.
  183. Note that only the desktop targets have a home directory. Other targets will return an empty string.
  184. @return The home directory.
  185. #end
  186. Function HomeDir:String()
  187. #If __TARGET__="windows"
  188. Return GetEnv( "USERPROFILE" ).Replace( "\","/" )+"/"
  189. #Else if __DESKTOP_TARGET__
  190. Return GetEnv( "HOME" )+"/"
  191. #Else
  192. Return "${HOME}/"
  193. #Endif
  194. End
  195. #rem monkeydoc Gets the filesystem directory of the app's internal storage directory.
  196. Returns the absolute path to the directory on the filesystem where files created with openFileOutput(String, int) are stored.
  197. This directory will be removed when your app is uninstalled.
  198. This function is only available on mobile targets.
  199. @return The app's internal directory.
  200. #End
  201. Function InternalDir:String()
  202. Return GetSpecialDir( "internal" )
  203. End
  204. #rem monkeydoc Gets the filesystem directory of the app's external storage directory.
  205. Returns the absolute path to the directory on the primary shared/external storage device where the application can place persistent files it owns. These files are internal to the applications, and not typically visible to the user as media.
  206. This directory will be removed when your app is uninstalled.
  207. This function is only available on mobile targets.
  208. @return The app's external storage directory.
  209. #End
  210. Function ExternalDir:String()
  211. Return GetSpecialDir( "external" )
  212. End
  213. #rem monkeydoc Extracts the root directory from a file system path.
  214. A root directory is a directory path that:
  215. * Starts with '//' or '/', or...
  216. * Starts with 'blah:/', 'blah://' or 'blah::'.
  217. @param path The filesystem path.
  218. @return The root directory of `path`, or an empty string if `path` is not an absolute path.
  219. #end
  220. Function ExtractRootDir:String( path:String )
  221. path=path.Replace( "\","/" )
  222. If path.StartsWith( "//" ) Return "//"
  223. If path.StartsWith( "/" ) Return "/"
  224. Local i:=path.Find( "/" )
  225. If path.StartsWith( "$" ) And i<>-1 Return path.Slice( 0,i+1 )
  226. Local j:=path.Find( ":" )
  227. If j=-1 Or (i<>-1 And j>i) Return ""
  228. If path.Slice( j,j+3 )="://" Return path.Slice( 0,j+3 )
  229. If path.Slice( j,j+2 )=":/" Return path.Slice( 0,j+2 )
  230. If path.Slice( j,j+2 )="::" Return path.Slice( 0,j+2 )
  231. Return ""
  232. End
  233. #rem monkeydoc Checks if a path is a root directory.
  234. @param path The filesystem path to check.
  235. @return True if `path` is a root directory path.
  236. #end
  237. Function IsRootDir:Bool( path:String )
  238. Local root:=ExtractRootDir( path )
  239. Return root And root.Length=path.Length
  240. End
  241. #rem monkeydoc Gets the process current directory.
  242. @return The current directory for the running process.
  243. #end
  244. Function CurrentDir:String()
  245. Local buf:=New char_t[PATH_MAX]
  246. getcwd( buf.Data,PATH_MAX )
  247. Local path:=String.FromCString( buf.Data )
  248. #If __TARGET__="windows"
  249. path=path.Replace( "\","/" )
  250. #Endif
  251. If path.EndsWith( "/" ) Return path
  252. Return path+"/"
  253. End
  254. #rem monkeydoc Converts a path to a real path.
  255. If `path` is a relative path, it is first converted into an absolute path by prefixing the current directory.
  256. Then, any internal './' or '../' references in the path are collapsed.
  257. @param path The filesystem path.
  258. @return An absolute path with any './', '../' references collapsed.
  259. #end
  260. Function RealPath:String( path:String )
  261. path=FixPath( path )
  262. Local root:=ExtractRootDir( path )
  263. If root
  264. path=path.Slice( root.Length )
  265. Else
  266. root=CurrentDir()
  267. Endif
  268. While path
  269. Local i:=path.Find( "/" )
  270. If i=-1 Return root+path
  271. Local t:=path.Slice( 0,i )
  272. path=path.Slice( i+1 )
  273. Select t
  274. Case ""
  275. Case "."
  276. Case ".."
  277. If Not root root=CurrentDir()
  278. root=ExtractDir( root )
  279. Default
  280. root+=t+"/"
  281. End
  282. Wend
  283. Return root
  284. #rem Not working on macos!
  285. path=FixPath( path )
  286. Local buf:=New char_t[PATH_MAX]
  287. If Not libc.realpath( path,buf.Data ) Return ""
  288. Local rpath:=String.FromCString( buf.Data )
  289. #If __TARGET__="windows"
  290. rpath=rpath.Replace( "\","/" )
  291. #Endif
  292. Return rpath
  293. #end
  294. End
  295. #rem monkeydoc Strips any trailing slashes from a filesystem path.
  296. This function will not strip slashes from a root directory path.
  297. @param path The filesystem path.
  298. @return The path stripped of trailing slashes.
  299. #end
  300. Function StripSlashes:String( path:String )
  301. path=path.Replace( "\","/" )
  302. If Not path.EndsWith( "/" ) Return path
  303. Local root:=ExtractRootDir( path )
  304. Repeat
  305. If path=root Return path
  306. path=path.Slice( 0,-1 )
  307. Until Not path.EndsWith( "/" )
  308. Return path
  309. End
  310. #rem monkeydoc Extracts the directory component from a filesystem path.
  311. If `path` is a root directory it is returned without modification.
  312. If `path` does not contain a directory component, an empty string is returned.
  313. @param path The filesystem path.
  314. @return The directory component of `path`.
  315. #end
  316. Function ExtractDir:String( path:String )
  317. path=path.Replace( "\","/" )
  318. path=StripSlashes( path )
  319. If IsRootDir( path ) Return path
  320. Local i:=path.FindLast( "/" )
  321. If i>=0 Return path.Slice( 0,i+1 )
  322. i=path.Find( "::" )
  323. If i>=0 Return path.Slice( 0,i+2 )
  324. Return ""
  325. End
  326. #rem monkeydoc Strips the directory component from a filesystem path.
  327. If `path` is a root directory an empty string is returned.
  328. If `path` does not contain a directory component, `path` is returned without modification.
  329. @param path The filesystem path.
  330. @return The path with the directory component stripped.
  331. #end
  332. Function StripDir:String( path:String )
  333. path=StripSlashes( path )
  334. If IsRootDir( path ) Return ""
  335. Local i:=path.FindLast( "/" )
  336. If i>=0 Return path.Slice( i+1 )
  337. i=path.Find( "::" )
  338. If i>=0 Return path.Slice( i+2 )
  339. Return path
  340. End
  341. #rem monkeydoc Extracts the extension component from a filesystem path.
  342. @param path The filesystem path.
  343. @return The extension component of `path` including the '.' if any.
  344. #end
  345. Function ExtractExt:String( path:String )
  346. path=path.Replace( "\","/" )
  347. Local i:=path.FindLast( "." )
  348. If i=-1 Return ""
  349. Local j:=path.Find( "/",i+1 )
  350. If j=-1 Return path.Slice( i )
  351. Return ""
  352. End
  353. #rem monkeydoc Strips the extension component from a filesystem path.
  354. @param path The filesystem path.
  355. @return The path with the extension stripped.
  356. #end
  357. Function StripExt:String( path:String )
  358. path=path.Replace( "\","/" )
  359. Local i:=path.FindLast( "." )
  360. If i=-1 Return path
  361. Local j:=path.Find( "/",i+1 )
  362. If j=-1 Return path.Slice( 0,i )
  363. Return path
  364. End
  365. #rem monkeydoc Gets the type of the file at a filesystem path.
  366. @param path The filesystem path.
  367. @return The file type of the file at `path`, one of: FileType.None, FileType.File or FileType.Directory.
  368. #end
  369. Function GetFileType:FileType( path:String )
  370. path=FixFilePath( path )
  371. #If __TARGET__="android"
  372. If path.StartsWith( "${ASSETS}/" )
  373. path=path.Slice( 10 )
  374. Local asset:=AAssetManager_open( GetAssetManager(),path,0 )
  375. If Not asset Return FileType.Unknown
  376. Local length:=AAsset_getLength( asset )
  377. AAsset_close( asset )
  378. Return length<>0 ? FileType.File Else FileType.Unknown
  379. End
  380. #Endif
  381. Local st:stat_t
  382. If stat( path,Varptr st )<0 Return FileType.None
  383. Select st.st_mode & S_IFMT
  384. Case S_IFREG Return FileType.File
  385. Case S_IFDIR Return FileType.Directory
  386. End
  387. Return FileType.Unknown
  388. End
  389. #rem monkeydoc Gets the time a file was most recently modified.
  390. @param path The filesystem path.
  391. @return The time the file at `path` was most recently modified.
  392. #end
  393. Function GetFileTime:Long( path:String )
  394. path=FixFilePath( path )
  395. Local st:stat_t
  396. If stat( path,Varptr st )<0 Return 0
  397. Return libc.tolong( st.st_mtime )
  398. End
  399. #rem monkeydoc Gets the size of the file at a filesystem path.
  400. @param path The filesystem path.
  401. @return The size file at `path` in bytes.
  402. #end
  403. Function GetFileSize:Long( path:String )
  404. path=FixFilePath( path )
  405. #If __TARGET__="android"
  406. If path.StartsWith( "${ASSETS}/" )
  407. path=path.Slice( 10 )
  408. Local asset:=AAssetManager_open( GetAssetManager(),path,0 )
  409. If Not asset Return 0
  410. Local length:=AAsset_getLength( asset )
  411. AAsset_close( asset )
  412. Return length
  413. End
  414. #Endif
  415. Local st:stat_t
  416. If stat( path,Varptr st )<0 Return 0
  417. return st.st_size
  418. End
  419. #rem monkeydoc Changes the process current directory.
  420. @param path The filesystem path of the directory to make current.
  421. #end
  422. Function ChangeDir( path:String )
  423. path=FixFilePath( path )
  424. chdir( path )
  425. End
  426. #rem monkeydoc Loads a directory.
  427. Loads the contents of directory into an array.
  428. Does not return any '.' or '..' entries in a directory.
  429. @param path The filesystem path of the directory to load.
  430. @return An array containing all filenames in the `path`, excluding '.' and '..' entries.
  431. #end
  432. Function LoadDir:String[]( path:String )
  433. Local files:=New StringStack
  434. path=FixFilePath( path )
  435. #If __TARGET__="android"
  436. If path.StartsWith( "${ASSETS}/" )
  437. path=path.Slice( 10 )
  438. Local assetDir:=AAssetManager_openDir( GetAssetManager(),path )
  439. If assetDir
  440. Repeat
  441. Local file:=AAssetDir_getNextFileName( assetDir )
  442. If Not file Exit
  443. files.Add( file )
  444. Forever
  445. AAssetDir_close( assetDir )
  446. Endif
  447. Return files.ToArray()
  448. Endif
  449. #endif
  450. Local dir:=opendir( path )
  451. If Not dir Return Null
  452. Repeat
  453. Local ent:=readdir( dir )
  454. If Not ent Exit
  455. Local file:=ent[0].d_name 'String.FromCString( ent[0].d_name )
  456. If file="." Or file=".." Continue
  457. files.Push( file )
  458. Forever
  459. closedir( dir )
  460. Return files.ToArray()
  461. End
  462. #rem monkeydoc Creates a file at a filesystem path.
  463. Any existing file at the path will be overwritten.
  464. Returns true if successful.
  465. @param path The filesystem path of the file file to create.
  466. @param createDir If true, also creates the file directory if necessary.
  467. @return True if a file at the given path was created.
  468. #end
  469. Function CreateFile:Bool( path:String,createDir:Bool=True )
  470. path=FixFilePath( path )
  471. If createDir And Not CreateDir( ExtractDir( path ),True ) Return False
  472. Local f:=fopen( path,"wb" )
  473. If Not f Return False
  474. fclose( f )
  475. Return True
  476. End
  477. #rem monkeydoc Creates a directory at a filesystem path.
  478. @param path The filesystem path of the directory to create.
  479. @param recursive If true, any required parent directories are also created.
  480. @param clean If true, any existing directory at `dir` is first deleted.
  481. @return True if a directory at `path` was successfully created or already existed.
  482. #end
  483. Function CreateDir:Bool( dir:String,recursive:Bool=True,clean:Bool=False )
  484. dir=FixFilePath( dir )
  485. If recursive
  486. Local parent:=ExtractDir( dir )
  487. If parent And Not IsRootDir( parent )
  488. Select GetFileType( parent )
  489. Case FileType.None
  490. If Not CreateDir( parent,True,False ) Return False
  491. Case FileType.File
  492. Return False
  493. End
  494. Endif
  495. Endif
  496. If clean And Not DeleteDir( dir,True ) Return False
  497. mkdir( dir,$1ff )
  498. Return GetFileType( dir )=FileType.Directory
  499. End
  500. #rem monkeydoc Deletes a file at a filesystem path.
  501. Returns true if successful.
  502. @param path The filesystem path.
  503. @return True if the file was successfully deleted.
  504. #end
  505. Function DeleteFile:Bool( path:String )
  506. path=FixFilePath( path )
  507. remove( path )
  508. Return GetFileType( path )=FileType.None
  509. End
  510. #rem monkeydoc Deletes a directory at a filesystem path.
  511. If `recursive` is true, all subdirectories are also deleted.
  512. Returns true if successful.
  513. @param path The filesystem path.
  514. @param recursive True to delete subdirectories too.
  515. @return True if the directory was successfully deleted or never existed.
  516. #end
  517. Function DeleteDir:Bool( dir:String,recursive:Bool=False )
  518. dir=FixFilePath( dir )
  519. If GetFileType( dir )=FileType.Directory
  520. If recursive
  521. For Local f:=Eachin LoadDir( dir )
  522. Local p:=dir+"/"+f
  523. Select GetFileType( p )
  524. Case FileType.File
  525. If Not DeleteFile( p ) Return False
  526. Case FileType.Directory
  527. If Not DeleteDir( p,True ) Return false
  528. End
  529. Next
  530. Endif
  531. rmdir( dir )
  532. Endif
  533. Return GetFileType( dir )=FileType.None
  534. End
  535. #rem monkeydoc Copies a directory.
  536. Copies a directory from `srcDir` to `dstDir`.
  537. If `recursive` is true, all subdirectories are also copied.
  538. Returns true if successful.
  539. @param srcDir Source directory.
  540. @param dstDir Destination directory.
  541. @param recursive Recursive flag.
  542. @return True if successful.
  543. #end
  544. Function CopyDir:Bool( srcDir:String,dstDir:String,recursive:Bool=True )
  545. srcDir=FixFilePath( srcDir )
  546. dstDir=FixFilePath( dstDir )
  547. If GetFileType( srcDir )<>FileType.Directory Return False
  548. If GetFileType( dstDir )<>FileType.Directory And Not CreateDir( dstDir,True ) Return False
  549. For Local f:=Eachin LoadDir( srcDir )
  550. Local src:=srcDir+"/"+f
  551. Local dst:=dstDir+"/"+f
  552. Select GetFileType( src )
  553. Case FileType.File
  554. If Not CopyFile( src,dst ) Return False
  555. Case FileType.Directory
  556. If recursive And Not CopyDir( src,dst ) Return False
  557. End
  558. Next
  559. Return True
  560. End
  561. #rem monkeydoc Opens a 'C' file.
  562. Opens a file that can be used with the 'C' calls fopen, fread, fwrite and fclose. Similar to plain libc.fopen, except that it can also handle assets on android.
  563. `mode` should be one of: "r", "w" or "rw". When opening a file using "r" or "rw", the file must already exist or the function will fail and null will be returned. When opening a file using "w", any existing file at the same path will be overwritten.
  564. #end
  565. Function OpenCFile:FILE Ptr( path:String,mode:String )
  566. path=FixFilePath( path )
  567. Select mode
  568. Case "r" mode="rb"
  569. Case "w" mode="wb"
  570. Case "rw" mode="r+b"
  571. End
  572. #If __TARGET__="android"
  573. If path.StartsWith( "${ASSETS}/" )
  574. path=path.Slice( 10 )
  575. Local asset:=AAssetManager_open( GetAssetManager(),path,0 )
  576. If Not asset Return Null
  577. Return fopenAsset( asset )
  578. Endif
  579. #Endif
  580. Return libc.fopen( path,mode )
  581. End