filesystem.monkey2 18 KB

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