tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / wizards / source / scriptforge / SF_FileSystem.xba
blobba1838a12f756500f62638dd923ec8b4f6203708
1 <?xml version="1.0" encoding="UTF-8"?>
2 <!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
3 <script:module xmlns:script="http://openoffice.org/2000/script" script:name="SF_FileSystem" script:language="StarBasic" script:moduleType="normal">REM =======================================================================================================================
4 REM === The ScriptForge library and its associated libraries are part of the LibreOffice project. ===
5 REM === Full documentation is available on https://help.libreoffice.org/ ===
6 REM =======================================================================================================================
8 Option Compatible
9 Option Explicit
11 &apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;
12 &apos;&apos;&apos; SF_FileSystem
13 &apos;&apos;&apos; =============
14 &apos;&apos;&apos; Class implementing the file system service
15 &apos;&apos;&apos; for common file and folder handling routines
16 &apos;&apos;&apos; Including copy and move of files and folders, with or without wildcards
17 &apos;&apos;&apos; The design choices are largely inspired by
18 &apos;&apos;&apos; https://docs.microsoft.com/en-us/office/vba/language/reference/user-interface-help/filesystemobject-object
19 &apos;&apos;&apos; The File and Folder classes have been found redundant with the current class and have not been implemented
20 &apos;&apos;&apos; The implementation is mainly based on the XSimpleFileAccess UNO interface
21 &apos;&apos;&apos; https://api.libreoffice.org/docs/idl/ref/interfacecom_1_1sun_1_1star_1_1ucb_1_1XSimpleFileAccess.html
22 &apos;&apos;&apos;
23 &apos;&apos;&apos; Subclasses:
24 &apos;&apos;&apos; SF_TextStream
25 &apos;&apos;&apos;
26 &apos;&apos;&apos; Definitions:
27 &apos;&apos;&apos; File and folder names may be expressed either in the (preferable because portable) URL form
28 &apos;&apos;&apos; or in the more usual operating system notation (e.g. C:\... for Windows)
29 &apos;&apos;&apos; The notation, both for arguments and for returned values
30 &apos;&apos;&apos; is determined by the FileNaming property: either &quot;ANY&quot; (default), &quot;URL&quot; or &quot;SYS&quot;
31 &apos;&apos;&apos;
32 &apos;&apos;&apos; FileName: the full name of the file including the path without any ending path separator
33 &apos;&apos;&apos; FolderName: the full name of the folder including the path and the ending path separator
34 &apos;&apos;&apos; Name: the last component of the File- or FolderName including its extension
35 &apos;&apos;&apos; BaseName: the last component of the File- or FolderName without its extension
36 &apos;&apos;&apos; NamePattern: any of the above names containing wildcards in its last component
37 &apos;&apos;&apos; Admitted wildcards are: the &quot;?&quot; represents any single character
38 &apos;&apos;&apos; the &quot;*&quot; represents zero, one, or multiple characters
39 &apos;&apos;&apos;
40 &apos;&apos;&apos; Disk file systems and document&apos;s internal file systems
41 &apos;&apos;&apos; All the implemented properties and methods are applicable on usual disk file systems.
42 &apos;&apos;&apos; Root is usually something like &quot;C:\&quot; or &quot;/&quot; or their URL equivalents
43 &apos;&apos;&apos; Now, Libreoffice documents have an internal file system as well. Many of the proposed methods
44 &apos;&apos;&apos; support document&apos;s file systems too, however, for some of them, with restrictions.
45 &apos;&apos;&apos; Read the comments in the individual methods below.
46 &apos;&apos;&apos; It makes browsing folders and files, adding, replacing files possible. Updates will be
47 &apos;&apos;&apos; saved with the document.
48 &apos;&apos;&apos; VERY POWERFUL but KNOW WHAT YOU&apos;RE DOING !!
49 &apos;&apos;&apos; The root of a document&apos;s file system is obtained from the &quot;FileSystem&quot; property of a document instance, like in:
50 &apos;&apos;&apos; Dim root As String, doc As Object, ui As Object
51 &apos;&apos;&apos; Set ui = CreateScriptService(&quot;ui&quot;)
52 &apos;&apos;&apos; Set doc = ui.GetDocument(ThisComponent)
53 &apos;&apos;&apos; root = doc.FileSystem
54 &apos;&apos;&apos; The file manifest.xml is managed automatically.
55 &apos;&apos;&apos; The FileNaming setting is ignored.
56 &apos;&apos;&apos;
57 &apos;&apos;&apos; Service invocation example:
58 &apos;&apos;&apos; Dim FSO As Variant
59 &apos;&apos;&apos; Set FSO = CreateScriptService(&quot;FileSystem&quot;)
60 &apos;&apos;&apos;
61 &apos;&apos;&apos; Detailed user documentation:
62 &apos;&apos;&apos; https://help.libreoffice.org/latest/en-US/text/sbasic/shared/03/sf_filesystem.html?DbPAR=BASIC
63 &apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;
65 REM ================================================================== EXCEPTIONS
67 Const UNKNOWNFILEERROR = &quot;UNKNOWNFILEERROR&quot; &apos; Source file does not exist
68 Const UNKNOWNFOLDERERROR = &quot;UNKNOWNFOLDERERROR&quot; &apos; Source folder or Destination folder does not exist
69 Const NOTAFILEERROR = &quot;NOTAFILEERROR&quot; &apos; Destination is a folder, not a file
70 Const NOTAFOLDERERROR = &quot;NOTAFOLDERERROR&quot; &apos; Destination is a file, not a folder
71 Const OVERWRITEERROR = &quot;OVERWRITEERROR&quot; &apos; Destination can not be overwritten
72 Const READONLYERROR = &quot;READONLYERROR&quot; &apos; Destination has its read-only attribute set
73 Const NOFILEMATCHERROR = &quot;NOFILEMATCHFOUND&quot; &apos; No file matches Source containing wildcards
74 Const FOLDERCREATIONERROR = &quot;FOLDERCREATIONERROR&quot; &apos; FolderName is an existing folder or file
75 Const FILESYSTEMERROR = &quot;FILESYSTEMERROR&quot; &apos; The method is not applicable on document&apos;s file systems
77 REM ============================================================ MODULE CONSTANTS
79 &apos;&apos;&apos; TextStream open modes
80 Const cstForReading = 1
81 Const cstForWriting = 2
82 Const cstForAppending = 8
84 &apos;&apos;&apos; Document file system
85 Const DOCFILESYSTEM = &quot;vnd.sun.star.tdoc:/&quot;
87 &apos;&apos;&apos; Folders and files scanning
88 Const cstSEPARATOR = &quot;//;&quot; &apos; Separates folders or files in the accumulators
89 Const cstFILES = 1 &apos; Caler = Files()
90 Const cstFOLDERS = 2 &apos; Caller = SubFolders()
92 REM ===================================================== CONSTRUCTOR/DESTRUCTOR
94 REM -----------------------------------------------------------------------------
95 Public Function Dispose() As Variant
96 Set Dispose = Nothing
97 End Function &apos; ScriptForge.SF_FileSystem Explicit destructor
99 REM ================================================================== PROPERTIES
101 REM -----------------------------------------------------------------------------
102 Property Get ConfigFolder() As String
103 &apos;&apos;&apos; Return the configuration folder of LibreOffice
105 Const cstThisSub = &quot;FileSystem.getConfigFolder&quot;
107 SF_Utils._EnterFunction(cstThisSub)
108 ConfigFolder = SF_FileSystem._GetConfigFolder(&quot;user&quot;)
109 SF_Utils._ExitFunction(cstThisSub)
111 End Property &apos; ScriptForge.SF_FileSystem.ConfigFolder
113 REM -----------------------------------------------------------------------------
114 Property Get ExtensionsFolder() As String
115 &apos;&apos;&apos; Return the folder containing the extensions installed for the current user
117 Dim oMacro As Object &apos; /singletons/com.sun.star.util.theMacroExpander
118 Const cstThisSub = &quot;FileSystem.getExtensionsFolder&quot;
120 SF_Utils._EnterFunction(cstThisSub)
121 Set oMacro = SF_Utils._GetUNOService(&quot;MacroExpander&quot;)
122 ExtensionsFolder = SF_FileSystem._ConvertFromUrl(oMacro.ExpandMacros(&quot;$UNO_USER_PACKAGES_CACHE&quot;) &amp; &quot;/&quot;)
123 SF_Utils._ExitFunction(cstThisSub)
125 End Property &apos; ScriptForge.SF_FileSystem.ExtensionsFolder
127 REM -----------------------------------------------------------------------------
128 Property Get FileNaming() As Variant
129 &apos;&apos;&apos; Return the current files and folder notation, either &quot;ANY&quot;, &quot;URL&quot; or &quot;SYS&quot;
130 &apos;&apos;&apos; &quot;ANY&quot;: methods receive either URL or native file names, but always return URL file names
131 &apos;&apos;&apos; &quot;URL&quot;: methods expect URL arguments and return URL strings (when relevant)
132 &apos;&apos;&apos; &quot;SYS&quot;: idem but operating system notation
134 Const cstThisSub = &quot;FileSystem.getFileNaming&quot;
135 SF_Utils._EnterFunction(cstThisSub)
136 FileNaming = _SF_.FileSystemNaming
137 SF_Utils._ExitFunction(cstThisSub)
139 End Property &apos; ScriptForge.SF_FileSystem.FileNaming (get)
141 REM -----------------------------------------------------------------------------
142 Property Let FileNaming(ByVal pvNotation As Variant)
143 &apos;&apos;&apos; Set the files and folders notation: &quot;ANY&quot;, &quot;URL&quot; or &quot;SYS&quot;
145 Const cstThisSub = &quot;FileSystem.setFileNaming&quot;
146 SF_Utils._EnterFunction(cstThisSub)
147 If VarType(pvNotation) = V_STRING Then
148 Select Case UCase(pvNotation)
149 Case &quot;ANY&quot;, &quot;URL&quot;, &quot;SYS&quot; : _SF_.FileSystemNaming = UCase(pvNotation)
150 Case Else &apos; Unchanged
151 End Select
152 End If
153 SF_Utils._ExitFunction(cstThisSub)
155 End Property &apos; ScriptForge.SF_FileSystem.FileNaming (let)
157 REM -----------------------------------------------------------------------------
158 Property Get ForAppending As Integer
159 &apos;&apos;&apos; Convenient constant (see documentation)
160 ForAppending = cstForAppending
161 End Property &apos; ScriptForge.SF_FileSystem.ForAppending
163 REM -----------------------------------------------------------------------------
164 Property Get ForReading As Integer
165 &apos;&apos;&apos; Convenient constant (see documentation)
166 ForReading = cstForReading
167 End Property &apos; ScriptForge.SF_FileSystem.ForReading
169 REM -----------------------------------------------------------------------------
170 Property Get ForWriting As Integer
171 &apos;&apos;&apos; Convenient constant (see documentation)
172 ForWriting = cstForWriting
173 End Property &apos; ScriptForge.SF_FileSystem.ForWriting
175 REM -----------------------------------------------------------------------------
176 Property Get HomeFolder() As String
177 &apos;&apos;&apos; Return the user home folder
179 Const cstThisSub = &quot;FileSystem.getHomeFolder&quot;
181 SF_Utils._EnterFunction(cstThisSub)
182 HomeFolder = SF_FileSystem._GetConfigFolder(&quot;home&quot;)
183 SF_Utils._ExitFunction(cstThisSub)
185 End Property &apos; ScriptForge.SF_FileSystem.HomeFolder
187 REM -----------------------------------------------------------------------------
188 Property Get InstallFolder() As String
189 &apos;&apos;&apos; Return the installation folder of LibreOffice
191 Const cstThisSub = &quot;FileSystem.getInstallFolder&quot;
193 SF_Utils._EnterFunction(cstThisSub)
194 InstallFolder = SF_FileSystem._GetConfigFolder(&quot;inst&quot;)
195 SF_Utils._ExitFunction(cstThisSub)
197 End Property &apos; ScriptForge.SF_FileSystem.InstallFolder
199 REM -----------------------------------------------------------------------------
200 Property Get ObjectType As String
201 &apos;&apos;&apos; Only to enable object representation
202 ObjectType = &quot;SF_FileSystem&quot;
203 End Property &apos; ScriptForge.SF_FileSystem.ObjectType
205 REM -----------------------------------------------------------------------------
206 Property Get ServiceName As String
207 &apos;&apos;&apos; Internal use
208 ServiceName = &quot;ScriptForge.FileSystem&quot;
209 End Property &apos; ScriptForge.SF_FileSystem.ServiceName
211 REM -----------------------------------------------------------------------------
212 Property Get TemplatesFolder() As String
213 &apos;&apos;&apos; Return the folder defined in the LibreOffice paths options as intended for templates files
215 Dim sPath As String &apos; Template property of com.sun.star.util.PathSettings
216 Const cstThisSub = &quot;FileSystem.getTemplatesFolder&quot;
218 SF_Utils._EnterFunction(cstThisSub)
219 sPath = SF_Utils._GetUNOService(&quot;PathSettings&quot;).Template
220 TemplatesFolder = SF_FileSystem._ConvertFromUrl(Split(sPath, &quot;;&quot;)(0) &amp; &quot;/&quot;)
221 SF_Utils._ExitFunction(cstThisSub)
223 End Property &apos; ScriptForge.SF_FileSystem.TemplatesFolder
225 REM -----------------------------------------------------------------------------
226 Property Get TemporaryFolder() As String
227 &apos;&apos;&apos; Return the folder defined in the LibreOffice paths options as intended for temporary files
229 Const cstThisSub = &quot;FileSystem.getTemporaryFolder&quot;
231 SF_Utils._EnterFunction(cstThisSub)
232 TemporaryFolder = SF_FileSystem._GetConfigFolder(&quot;temp&quot;)
233 SF_Utils._ExitFunction(cstThisSub)
235 End Property &apos; ScriptForge.SF_FileSystem.TemporaryFolder
237 REM -----------------------------------------------------------------------------
238 Property Get UserTemplatesFolder() As String
239 &apos;&apos;&apos; Return the folder defined in the LibreOffice paths options as intended for User templates files
241 Dim sPath As String &apos; Template_writable property of com.sun.star.util.PathSettings
242 Const cstThisSub = &quot;FileSystem.getUserTemplatesFolder&quot;
244 SF_Utils._EnterFunction(cstThisSub)
245 sPath = SF_Utils._GetUNOService(&quot;PathSettings&quot;).Template_writable
246 UserTemplatesFolder = SF_FileSystem._ConvertFromUrl(sPath &amp; &quot;/&quot;)
247 SF_Utils._ExitFunction(cstThisSub)
249 End Property &apos; ScriptForge.SF_FileSystem.UserTemplatesFolder
251 REM ===================================================================== METHODS
253 REM -----------------------------------------------------------------------------
254 Public Function BuildPath(Optional ByVal FolderName As Variant _
255 , Optional ByVal Name As Variant _
256 ) As String
257 &apos;&apos;&apos; Combines a folder path and the name of a file and returns the combination with a valid path separator
258 &apos;&apos;&apos; Inserts an additional path separator between the foldername and the name, only if necessary
259 &apos;&apos;&apos; Args:
260 &apos;&apos;&apos; FolderName: Path with which Name is combined. Path need not specify an existing folder
261 &apos;&apos;&apos; Name: To be appended to the existing path.
262 &apos;&apos;&apos; Returns:
263 &apos;&apos;&apos; The path concatenated with the file name after insertion of a path separator, if necessary
264 &apos;&apos;&apos; Example:
265 &apos;&apos;&apos; Dim a As String
266 &apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
267 &apos;&apos;&apos; a = FSO.BuildPath(&quot;C:\Windows&quot;, &quot;Notepad.exe&quot;) returns C:\Windows\Notepad.exe
269 Dim sBuild As String &apos; Return value
270 Dim sFile As String &apos; Alias for Name
271 Const cstFileProtocol = &quot;file:///&quot;
272 Const cstThisSub = &quot;FileSystem.BuildPath&quot;
273 Const cstSubArgs = &quot;FolderName, Name&quot;
275 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
276 sBuild = &quot;&quot;
278 Check:
279 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
280 If Not SF_Utils._ValidateFile(FolderName, &quot;FolderName&quot;) Then GoTo Finally
281 If Not SF_Utils._Validate(Name, &quot;Name&quot;, V_STRING) Then GoTo Finally
282 End If
283 FolderName = SF_FileSystem._ConvertToUrl(FolderName)
285 Try:
286 &apos; Add separator if necessary. FolderName is now in URL notation
287 If Len(FolderName) &gt; 0 Then
288 If Right(FolderName, 1) &lt;&gt; &quot;/&quot; Then sBuild = FolderName &amp; &quot;/&quot; Else sBuild = FolderName
289 Else
290 sBuild = cstFileProtocol
291 End If
292 &apos; Encode the file name
293 sFile = ConvertToUrl(Name)
294 &apos; Some file names produce http://file.name.suffix/
295 If Left(sFile, 7) = &quot;http://&quot; Then sFile = cstFileProtocol &amp; Mid(sFile, 8, Len(sFile) - 8)
296 &apos; Combine both parts
297 If Left(sFile, Len(cstFileProtocol)) = cstFileProtocol Then sBuild = sBuild &amp; Mid(sFile, Len(cstFileProtocol) + 1) Else sBuild = sBuild &amp; sFile
299 Finally:
300 BuildPath = SF_FileSystem._ConvertFromUrl(sBuild)
301 SF_Utils._ExitFunction(cstThisSub)
302 Exit Function
303 Catch:
304 GoTo Finally
305 End Function &apos; ScriptForge.SF_FileSystem.BuildPath
307 REM -----------------------------------------------------------------------------
308 Public Function CompareFiles(Optional ByVal FileName1 As Variant _
309 , Optional ByVal FileName2 As Variant _
310 , Optional ByVal CompareContents As Variant _
312 &apos;&apos;&apos; Compare 2 files and return True if they seem identical
313 &apos;&apos;&apos; The comparison may be based on the file attributes, like modification time,
314 &apos;&apos;&apos; or on their contents.
315 &apos;&apos;&apos; The method is not supported for document&apos;s internal file systems.
316 &apos;&apos;&apos; Args:
317 &apos;&apos;&apos; FileName1: The 1st file to compare
318 &apos;&apos;&apos; FileName2: The 2nd file to compare
319 &apos;&apos;&apos; CompareContents: When True, the contents of the files are compared. Default = False
320 &apos;&apos;&apos; Returns:
321 &apos;&apos;&apos; True when the files seem identical
322 &apos;&apos;&apos; Exceptions:
323 &apos;&apos;&apos; UNKNOWNFILEERROR One of the files does not exist
324 &apos;&apos;&apos; FILESYSTEMERROR The method is not applicable on document&apos;s file systems
325 &apos;&apos;&apos; Example:
326 &apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
327 &apos;&apos;&apos; MsgBox FSO.CompareFiles(&quot;C:\myFile1.txt&quot;, &quot;C:\myFile2.txt&quot;, CompareContents := True)
329 Dim bCompare As Boolean &apos; Return value
330 Dim sFile As String &apos; Alias of FileName1 and 2
331 Dim iFile As Integer &apos; 1 or 2
332 Const cstPyHelper = &quot;$&quot; &amp; &quot;_SF_FileSystem__CompareFiles&quot;
334 Const cstThisSub = &quot;FileSystem.CompareFiles&quot;
335 Const cstSubArgs = &quot;FileName1, FileName2, [CompareContents=False]&quot;
337 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
338 bCompare = False
340 Check:
341 If IsMissing(CompareContents) Or IsEmpty(CompareContents) Then CompareContents = False
342 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
343 If Not SF_Utils._ValidateFile(FileName1, &quot;FileName1&quot;, False) Then GoTo Finally
344 If Not SF_Utils._ValidateFile(FileName2, &quot;FileName2&quot;, False) Then GoTo Finally
345 If Not SF_Utils._Validate(CompareContents, &quot;CompareContents&quot;, V_BOOLEAN) Then GoTo Finally
346 End If
347 &apos; Do the files exist ? Otherwise raise error
348 sFile = FileName1 : iFile = 1
349 If Not SF_FileSystem.FileExists(sFile) Then GoTo CatchNotExists
350 sFile = FileName2 : iFile = 2
351 If Not SF_FileSystem.FileExists(sFile) Then GoTo CatchNotExists
353 sFile = FileName1 : iFile = 1
354 If SF_FileSystem._IsDocFileSystem(sFile) Then GoTo CatchNotSupported
355 sFile = FileName2 : iFile = 2
356 If SF_FileSystem._IsDocFileSystem(sFile) Then GoTo CatchNotSupported
358 Try:
359 With ScriptForge.SF_Session
360 bCompare = .ExecutePythonScript(.SCRIPTISSHARED, _SF_.PythonHelper &amp; cstPyHelper _
361 , _ConvertFromUrl(FileName1) _
362 , _ConvertFromUrl(FileName2) _
363 , CompareContents)
364 End With
366 Finally:
367 CompareFiles = bCompare
368 SF_Utils._ExitFunction(cstThisSub)
369 Exit Function
370 Catch:
371 GoTo Finally
372 CatchNotExists:
373 SF_Exception.RaiseFatal(UNKNOWNFILEERROR, &quot;FileName&quot; &amp; iFile, sFile)
374 GoTo Finally
375 CatchNotSupported:
376 SF_Exception.RaiseFatal(FILESYSTEMERROR, &quot;FileName&quot; &amp; iFile, Split(cstThisSub, &quot;.&quot;)(1), sFile)
377 GoTo Finally
378 End Function &apos; ScriptForge.SF_FileSystem.CompareFiles
380 REM -----------------------------------------------------------------------------
381 Public Function CopyFile(Optional ByVal Source As Variant _
382 , Optional ByVal Destination As Variant _
383 , Optional ByVal Overwrite As Variant _
384 ) As Boolean
385 &apos;&apos;&apos; Copies one or more files from one location to another
386 &apos;&apos;&apos; Args:
387 &apos;&apos;&apos; Source: FileName or NamePattern which can include wildcard characters, for one or more files to be copied
388 &apos;&apos;&apos; Destination: FileName where the single Source file is to be copied
389 &apos;&apos;&apos; or FolderName where the multiple files from Source are to be copied
390 &apos;&apos;&apos; If FolderName does not exist, it is created
391 &apos;&apos;&apos; Anyway, wildcard characters are not allowed in Destination
392 &apos;&apos;&apos; Overwrite: If True (default), files may be overwritten
393 &apos;&apos;&apos; CopyFile will fail if Destination has the read-only attribute set, regardless of the value of Overwrite.
394 &apos;&apos;&apos; Returns:
395 &apos;&apos;&apos; True if at least one file has been copied
396 &apos;&apos;&apos; False if an error occurred
397 &apos;&apos;&apos; An error also occurs if a source using wildcard characters doesn&apos;t match any files.
398 &apos;&apos;&apos; The method stops on the first error it encounters
399 &apos;&apos;&apos; No attempt is made to roll back or undo any changes made before an error occurs
400 &apos;&apos;&apos; Exceptions:
401 &apos;&apos;&apos; UNKNOWNFILEERROR Source does not exist
402 &apos;&apos;&apos; UNKNOWNFOLDERERROR Source folder or Destination folder does not exist
403 &apos;&apos;&apos; NOFILEMATCHERROR No file matches Source containing wildcards
404 &apos;&apos;&apos; NOTAFOLDERERROR Destination is a file, not a folder
405 &apos;&apos;&apos; NOTAFILEERROR Destination is a folder, not a file
406 &apos;&apos;&apos; OVERWRITEERROR Destination can not be overwritten
407 &apos;&apos;&apos; READONLYERROR Destination has its read-only attribute set
408 &apos;&apos;&apos; Example:
409 &apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
410 &apos;&apos;&apos; FSO.CopyFile(&quot;C:\Windows\*.*&quot;, &quot;C:\Temp\&quot;, Overwrite := False) &apos; Only files are copied, subfolders are not
412 Dim bCopy As Boolean &apos; Return value
414 Const cstThisSub = &quot;FileSystem.CopyFile&quot;
415 Const cstSubArgs = &quot;Source, Destination, [Overwrite=True]&quot;
417 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
418 bCopy = False
420 Check:
421 If IsMissing(Overwrite) Or IsEmpty(Overwrite) Then Overwrite = True
422 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
423 If Not SF_Utils._ValidateFile(Source, &quot;Source&quot;, True) Then GoTo Finally
424 If Not SF_Utils._ValidateFile(Destination, &quot;Destination&quot;, False) Then GoTo Finally
425 If Not SF_Utils._Validate(Overwrite, &quot;Overwrite&quot;, V_BOOLEAN) Then GoTo Finally
426 End If
428 Try:
429 bCopy = SF_FileSystem._CopyMove(&quot;CopyFile&quot;, Source, Destination, Overwrite)
431 Finally:
432 CopyFile = bCopy
433 SF_Utils._ExitFunction(cstThisSub)
434 Exit Function
435 Catch:
436 GoTo Finally
437 End Function &apos; ScriptForge.SF_FileSystem.CopyFile
439 REM -----------------------------------------------------------------------------
440 Public Function CopyFolder(Optional ByVal Source As Variant _
441 , Optional ByVal Destination As Variant _
442 , Optional ByVal Overwrite As Variant _
443 ) As Boolean
444 &apos;&apos;&apos; Copies one or more folders from one location to another
445 &apos;&apos;&apos; Args:
446 &apos;&apos;&apos; Source: FolderName or NamePattern which can include wildcard characters, for one or more folders to be copied
447 &apos;&apos;&apos; Destination: FolderName where the single Source folder is to be copied
448 &apos;&apos;&apos; or FolderName where the multiple folders from Source are to be copied
449 &apos;&apos;&apos; If FolderName does not exist, it is created
450 &apos;&apos;&apos; Anyway, wildcard characters are not allowed in Destination
451 &apos;&apos;&apos; Overwrite: If True (default), folders and their content may be overwritten
452 &apos;&apos;&apos; CopyFile will fail if Destination has the read-only attribute set, regardless of the value of Overwrite.
453 &apos;&apos;&apos; Returns:
454 &apos;&apos;&apos; True if at least one folder has been copied
455 &apos;&apos;&apos; False if an error occurred
456 &apos;&apos;&apos; An error also occurs if a source using wildcard characters doesn&apos;t match any folders.
457 &apos;&apos;&apos; The method stops on the first error it encounters
458 &apos;&apos;&apos; No attempt is made to roll back or undo any changes made before an error occurs
459 &apos;&apos;&apos; Exceptions:
460 &apos;&apos;&apos; UNKNOWNFILEERROR Source does not exist
461 &apos;&apos;&apos; UNKNOWNFOLDERERROR Source folder or Destination folder does not exist
462 &apos;&apos;&apos; NOFILEMATCHERROR No file matches Source containing wildcards
463 &apos;&apos;&apos; NOTAFOLDERERROR Destination is a file, not a folder
464 &apos;&apos;&apos; OVERWRITEERROR Destination can not be overwritten
465 &apos;&apos;&apos; READONLYERROR Destination has its read-only attribute set
466 &apos;&apos;&apos; Example:
467 &apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
468 &apos;&apos;&apos; FSO.CopyFolder(&quot;C:\Windows\*&quot;, &quot;C:\Temp\&quot;, Overwrite := False)
470 Dim bCopy As Boolean &apos; Return value
472 Const cstThisSub = &quot;FileSystem.CopyFolder&quot;
473 Const cstSubArgs = &quot;Source, Destination, [Overwrite=True]&quot;
475 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
476 bCopy = False
478 Check:
479 If IsMissing(Overwrite) Or IsEmpty(Overwrite) Then Overwrite = True
480 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
481 If Not SF_Utils._ValidateFile(Source, &quot;Source&quot;, True) Then GoTo Finally
482 If Not SF_Utils._ValidateFile(Destination, &quot;Destination&quot;, False) Then GoTo Finally
483 If Not SF_Utils._Validate(Overwrite, &quot;Overwrite&quot;, V_BOOLEAN) Then GoTo Finally
484 End If
486 Try:
487 bCopy = SF_FileSystem._CopyMove(&quot;CopyFolder&quot;, Source, Destination, Overwrite)
489 Finally:
490 CopyFolder = bCopy
491 SF_Utils._ExitFunction(cstThisSub)
492 Exit Function
493 Catch:
494 GoTo Finally
495 End Function &apos; ScriptForge.SF_FileSystem.CopyFolder
497 REM -----------------------------------------------------------------------------
498 Public Function CreateFolder(Optional ByVal FolderName As Variant) As Boolean
499 &apos;&apos;&apos; Return True if the given folder name could be created successfully
500 &apos;&apos;&apos; The parent folder does not need to exist beforehand
501 &apos;&apos;&apos; Args:
502 &apos;&apos;&apos; FolderName: a string representing the folder to create. It must not exist
503 &apos;&apos;&apos; Returns:
504 &apos;&apos;&apos; True if FolderName is a valid folder name, does not exist and creation was successful
505 &apos;&apos;&apos; False otherwise including when FolderName is a file
506 &apos;&apos;&apos; Exceptions:
507 &apos;&apos;&apos; FOLDERCREATIONERROR FolderName is an existing folder or file
508 &apos;&apos;&apos; Example:
509 &apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
510 &apos;&apos;&apos; FSO.CreateFolder(&quot;C:\NewFolder\&quot;)
512 Dim bCreate As Boolean &apos; Return value
513 Dim oSfa As Object &apos; com.sun.star.ucb.SimpleFileAccess
515 Const cstThisSub = &quot;FileSystem.CreateFolder&quot;
516 Const cstSubArgs = &quot;FolderName&quot;
518 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
519 bCreate = False
521 Check:
522 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
523 If Not SF_Utils._ValidateFile(FolderName, &quot;FolderName&quot;) Then GoTo Finally
524 End If
526 Try:
527 Set oSfa = SF_Utils._GetUnoService(&quot;FileAccess&quot;)
528 If SF_FileSystem.FolderExists(FolderName) Then GoTo CatchExists
529 If SF_FileSystem.FileExists(FolderName) Then GoTo CatchExists
530 oSfa.createFolder(SF_FileSystem._ConvertToUrl(FolderName))
531 bCreate = True
533 Finally:
534 CreateFolder = bCreate
535 SF_Utils._ExitFunction(cstThisSub)
536 Exit Function
537 Catch:
538 GoTo Finally
539 CatchExists:
540 SF_Exception.RaiseFatal(FOLDERCREATIONERROR, &quot;FolderName&quot;, FolderName)
541 GoTo Finally
542 End Function &apos; ScriptForge.SF_FileSystem.CreateFolder
544 REM -----------------------------------------------------------------------------
545 Public Function CreateTextFile(Optional ByVal FileName As Variant _
546 , Optional ByVal Overwrite As Variant _
547 , Optional ByVal Encoding As Variant _
548 ) As Object
549 &apos;&apos;&apos; Creates a specified file and returns a TextStream object that can be used to write to the file
550 &apos;&apos;&apos; Args:
551 &apos;&apos;&apos; FileName: Identifies the file to create
552 &apos;&apos;&apos; Overwrite: Boolean value that indicates if an existing file can be overwritten (default = True)
553 &apos;&apos;&apos; Encoding: The character set that should be used
554 &apos;&apos;&apos; Use one of the Names listed in https://www.iana.org/assignments/character-sets/character-sets.xhtml
555 &apos;&apos;&apos; Note that LibreOffice does not implement all existing sets
556 &apos;&apos;&apos; Default = UTF-8
557 &apos;&apos;&apos; Returns:
558 &apos;&apos;&apos; An instance of the SF_TextStream class representing the opened file or a Null object if an error occurred
559 &apos;&apos;&apos; It doesn&apos;t check either if the given encoding is implemented in LibreOffice
560 &apos;&apos;&apos; Exceptions:
561 &apos;&apos;&apos; OVERWRITEERROR File exists, creation impossible
562 &apos;&apos;&apos; Example:
563 &apos;&apos;&apos; Dim myFile As Object
564 &apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
565 &apos;&apos;&apos; Set myFile = FSO.CreateTextFile(&quot;C:\Temp\ThisFile.txt&quot;, Overwrite := True)
567 Dim oTextStream As Object &apos; Return value
568 Const cstThisSub = &quot;FileSystem.CreateTextFile&quot;
569 Const cstSubArgs = &quot;FileName, [Overwrite=True], [Encoding=&quot;&quot;UTF-8&quot;&quot;]&quot;
571 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
572 Set oTextStream = Nothing
574 Check:
575 If IsMissing(Overwrite) Or IsEmpty(Overwrite) Then Overwrite = True
576 If IsMissing(Encoding) Or IsEmpty(Encoding) Then Encoding = &quot;UTF-8&quot;
577 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
578 If Not SF_Utils._ValidateFile(FileName, &quot;FileName&quot;) Then GoTo Finally
579 If Not SF_Utils._Validate(Overwrite, &quot;Overwrite&quot;, V_BOOLEAN) Then GoTo Finally
580 If Not SF_Utils._Validate(Encoding, &quot;Encoding&quot;, V_STRING) Then GoTo Finally
581 End If
583 With SF_FileSystem
584 If .FileExists(FileName) Then
585 If Overwrite Then .DeleteFile(FileName) Else GoTo CatchOverWrite
586 End If
588 Try:
589 Set oTextStream = .OpenTextFile(FileName, .ForWriting, Create := True, Encoding := Encoding)
590 End With
592 Finally:
593 Set CreateTextFile = oTextStream
594 SF_Utils._ExitFunction(cstThisSub)
595 Exit Function
596 Catch:
597 GoTo Finally
598 CatchOverWrite:
599 SF_Exception.RaiseFatal(OVERWRITEERROR, &quot;FileName&quot;, FileName)
600 GoTo Finally
601 End Function &apos; ScriptForge.SF_FileSystem.CreateTextFile
603 REM -----------------------------------------------------------------------------
604 Public Function DeleteFile(Optional ByVal FileName As Variant) As Boolean
605 &apos;&apos;&apos; Deletes one or more files
606 &apos;&apos;&apos; Args:
607 &apos;&apos;&apos; FileName: FileName or NamePattern which can include wildcard characters, for one or more files to be deleted
608 &apos;&apos;&apos; Returns:
609 &apos;&apos;&apos; True if at least one file has been deleted
610 &apos;&apos;&apos; False if an error occurred
611 &apos;&apos;&apos; An error also occurs if a FileName using wildcard characters doesn&apos;t match any files.
612 &apos;&apos;&apos; The method stops on the first error it encounters
613 &apos;&apos;&apos; No attempt is made to roll back or undo any changes made before an error occurs
614 &apos;&apos;&apos; Exceptions:
615 &apos;&apos;&apos; UNKNOWNFILEERROR FileName does not exist
616 &apos;&apos;&apos; NOFILEMATCHERROR No file matches FileName containing wildcards
617 &apos;&apos;&apos; NOTAFILEERROR Argument is a folder, not a file
618 &apos;&apos;&apos; Example:
619 &apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
620 &apos;&apos;&apos; FSO.DeleteFile(&quot;C:\Temp\*.*&quot;) &apos; Only files are deleted, subfolders are not
622 Dim bDelete As Boolean &apos; Return value
624 Const cstThisSub = &quot;FileSystem.DeleteFile&quot;
625 Const cstSubArgs = &quot;FileName&quot;
627 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
628 bDelete = False
630 Check:
631 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
632 If Not SF_Utils._ValidateFile(FileName, &quot;FileName&quot;, True) Then GoTo Finally
633 End If
635 Try:
636 bDelete = SF_FileSystem._Delete(&quot;DeleteFile&quot;, FileName)
638 Finally:
639 DeleteFile = bDelete
640 SF_Utils._ExitFunction(cstThisSub)
641 Exit Function
642 Catch:
643 GoTo Finally
644 End Function &apos; ScriptForge.SF_FileSystem.DeleteFile
646 REM -----------------------------------------------------------------------------
647 Public Function DeleteFolder(Optional ByVal FolderName As Variant) As Boolean
648 &apos;&apos;&apos; Deletes one or more Folders
649 &apos;&apos;&apos; Args:
650 &apos;&apos;&apos; FolderName: FolderName or NamePattern which can include wildcard characters, for one or more Folders to be deleted
651 &apos;&apos;&apos; Returns:
652 &apos;&apos;&apos; True if at least one folder has been deleted
653 &apos;&apos;&apos; False if an error occurred
654 &apos;&apos;&apos; An error also occurs if a FolderName using wildcard characters doesn&apos;t match any folders.
655 &apos;&apos;&apos; The method stops on the first error it encounters
656 &apos;&apos;&apos; No attempt is made to roll back or undo any changes made before an error occurs
657 &apos;&apos;&apos; Exceptions:
658 &apos;&apos;&apos; UNKNOWNFOLDERERROR FolderName does not exist
659 &apos;&apos;&apos; NOFILEMATCHERROR No folder matches FolderName containing wildcards
660 &apos;&apos;&apos; NOTAFOLDERERROR Argument is a file, not a folder
661 &apos;&apos;&apos; Example:
662 &apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
663 &apos;&apos;&apos; FSO.DeleteFolder(&quot;C:\Temp\*&quot;) &apos; Only folders are deleted, files in the parent folder are not
665 Dim bDelete As Boolean &apos; Return value
667 Const cstThisSub = &quot;FileSystem.DeleteFolder&quot;
668 Const cstSubArgs = &quot;FolderName&quot;
670 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
671 bDelete = False
673 Check:
674 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
675 If Not SF_Utils._ValidateFile(FolderName, &quot;FolderName&quot;, True) Then GoTo Finally
676 End If
678 Try:
679 bDelete = SF_FileSystem._Delete(&quot;DeleteFolder&quot;, FolderName)
681 Finally:
682 DeleteFolder = bDelete
683 SF_Utils._ExitFunction(cstThisSub)
684 Exit Function
685 Catch:
686 GoTo Finally
687 End Function &apos; ScriptForge.SF_FileSystem.DeleteFolder
689 REM -----------------------------------------------------------------------------
690 Public Function ExtensionFolder(Optional ByVal Extension As Variant) As String
691 &apos;&apos;&apos; Return the folder where the given extension is installed. The argument must
692 &apos;&apos;&apos; be in the list of extensions provided by the SF_Platform.Extensions property
693 &apos;&apos;&apos; Args:
694 &apos;&apos;&apos; Extension: a valid extension name
695 &apos;&apos;&apos; Returns:
696 &apos;&apos;&apos; The requested folder using the FileNaming notation
697 &apos;&apos;&apos; Example:
698 &apos;&apos;&apos; MsgBox FSO.ExtensionFolder(&quot;apso.python.script.organizer&quot;)
700 Dim sFolder As String &apos; Return value
701 Static vExtensions As Variant &apos; Cached list of existing extension names
702 Dim oPackage As Object &apos; /singletons/com.sun.star.deployment.PackageInformationProvider
703 Const cstThisSub = &quot;FileSystem.ExtensionFolder&quot;
704 Const cstSubArgs = &quot;Extension&quot;
706 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
707 sFolder = &quot;&quot;
709 Check:
710 If IsEmpty(vExtensions) Then vExtensions = SF_Platform.Extensions
711 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
712 If Not SF_Utils._Validate(Extension, &quot;Extension&quot;, V_STRING, vExtensions, True) Then GoTo Finally
713 End If
715 Try:
716 &apos; Search an individual folder
717 Set oPackage = SF_Utils._GetUnoService(&quot;PackageInformationProvider&quot;)
718 sFolder = oPackage.getPackageLocation(Extension)
720 Finally:
721 ExtensionFolder = SF_FileSystem._ConvertFromUrl(sFolder)
722 SF_Utils._ExitFunction(cstThisSub)
723 Exit Function
724 Catch:
725 GoTo Finally
726 End Function &apos; ScriptForge.SF_FileSystem.ExtensionFolder
728 REM -----------------------------------------------------------------------------
729 Public Function FileExists(Optional ByVal FileName As Variant) As Boolean
730 &apos;&apos;&apos; Return True if the given file exists
731 &apos;&apos;&apos; Args:
732 &apos;&apos;&apos; FileName: a string representing a file
733 &apos;&apos;&apos; Returns:
734 &apos;&apos;&apos; True if FileName is a valid File name and it exists
735 &apos;&apos;&apos; False otherwise including when FileName is a folder
736 &apos;&apos;&apos; Example:
737 &apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
738 &apos;&apos;&apos; If FSO.FileExists(&quot;C:\Notepad.exe&quot;) Then ...
740 Dim bExists As Boolean &apos; Return value
741 Dim oSfa As Object &apos; com.sun.star.ucb.SimpleFileAccess
743 Const cstThisSub = &quot;FileSystem.FileExists&quot;
744 Const cstSubArgs = &quot;FileName&quot;
746 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
747 bExists = False
749 Check:
750 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
751 If Not SF_Utils._ValidateFile(FileName, &quot;FileName&quot;) Then GoTo Finally
752 End If
753 FileName = SF_FileSystem._ConvertToUrl(FileName)
755 Try:
756 Set oSfa = SF_Utils._GetUnoService(&quot;FileAccess&quot;)
757 bExists = oSfa.exists(FileName) And Not oSfa.isFolder(FileName)
759 Finally:
760 FileExists = bExists
761 SF_Utils._ExitFunction(cstThisSub)
762 Exit Function
763 Catch:
764 GoTo Finally
765 End Function &apos; ScriptForge.SF_FileSystem.FileExists
767 REM -----------------------------------------------------------------------------
768 Public Function Files(Optional ByVal FolderName As Variant _
769 , Optional ByVal Filter As Variant _
770 , Optional ByVal IncludeSubfolders As Variant _
771 ) As Variant
772 &apos;&apos;&apos; Return an array of the FileNames stored in the given folder. The folder must exist
773 &apos;&apos;&apos; Subfolders may be optionally explored too.
774 &apos;&apos;&apos; If the number of files exceeds a reasonable amount (&gt; 1000 ?), the process time may become long.
775 &apos;&apos;&apos; Args:
776 &apos;&apos;&apos; FolderName: the folder to explore
777 &apos;&apos;&apos; Filter: contains wildcards (&quot;?&quot; and &quot;*&quot;) to limit the list to the relevant files (default = &quot;&quot;)
778 &apos;&apos;&apos; IncludeSubfolders: when True (default = False), subfolders are explored too.
779 &apos;&apos;&apos; Returns:
780 &apos;&apos;&apos; An array of strings, each entry is the FileName of an existing file
781 &apos;&apos;&apos; Exceptions:
782 &apos;&apos;&apos; UNKNOWNFOLDERERROR Folder does not exist
783 &apos;&apos;&apos; NOTAFOLDERERROR FolderName is a file, not a folder
784 &apos;&apos;&apos; Example:
785 &apos;&apos;&apos; Dim a As Variant
786 &apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
787 &apos;&apos;&apos; a = FSO.Files(&quot;C:\Windows\&quot;, IncludeSubfolders := True)
789 Dim vFiles As Variant &apos; Return value
790 Dim oSfa As Object &apos; com.sun.star.ucb.SimpleFileAccess
791 Dim sFilesColl As String &apos; cstSEPARATOR delimited string of list of files (FileNaming notation)
792 Dim i As Long
794 Const cstThisSub = &quot;FileSystem.Files&quot;
795 Const cstSubArgs = &quot;FolderName, [Filter=&quot;&quot;&quot;&quot;], [IncludeSubfolders=False]&quot;
797 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
798 vFiles = Array()
800 Check:
801 If IsMissing(Filter) Or IsEmpty(Filter) Then Filter = &quot;&quot;
802 If IsMissing(IncludeSubfolders) Or IsEmpty(IncludeSubfolders) Then IncludeSubfolders = False
803 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
804 If Not SF_Utils._ValidateFile(FolderName, &quot;FolderName&quot;) Then GoTo Finally
805 If Not SF_Utils._Validate(Filter, &quot;Filter&quot;, V_STRING) Then GoTo Finally
806 If Not SF_Utils._Validate(IncludeSubfolders, &quot;IncludeSubfolders&quot;, V_BOOLEAN) Then GoTo Finally
807 End If
808 If SF_FileSystem.FileExists(FolderName) Then GoTo CatchFile &apos; Must not be a file
809 If Not SF_FileSystem.FolderExists(FolderName) Then GoTo CatchFolder &apos; Folder must exist
811 Try:
812 sFilesColl = &quot;&quot;
813 Set oSfa = SF_Utils._GetUnoService(&quot;FileAccess&quot;)
814 SF_FileSystem._ScanFolder(cstFiles, sFilesColl, FolderName, oSfa, Filter, IncludeSubfolders)
816 If Len(sFilesColl) &gt; Len(cstSEPARATOR) Then vFiles() = Split(Mid(sFilesColl, Len(cstSEPARATOR) + 1), cstSEPARATOR)
818 Finally:
819 Files = vFiles
820 SF_Utils._ExitFunction(cstThisSub)
821 Exit Function
822 Catch:
823 GoTo Finally
824 CatchFile:
825 SF_Exception.RaiseFatal(NOTAFOLDERERROR, &quot;FolderName&quot;, FolderName)
826 GoTo Finally
827 CatchFolder:
828 SF_Exception.RaiseFatal(UNKNOWNFOLDERERROR, &quot;FolderName&quot;, FolderName)
829 GoTo Finally
830 End Function &apos; ScriptForge.SF_FileSystem.Files
832 REM -----------------------------------------------------------------------------
833 Public Function FolderExists(Optional ByVal FolderName As Variant) As Boolean
834 &apos;&apos;&apos; Return True if the given folder name exists
835 &apos;&apos;&apos; Args:
836 &apos;&apos;&apos; FolderName: a string representing a folder
837 &apos;&apos;&apos; Returns:
838 &apos;&apos;&apos; True if FolderName is a valid folder name and it exists
839 &apos;&apos;&apos; False otherwise including when FolderName is a file
840 &apos;&apos;&apos; Example:
841 &apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
842 &apos;&apos;&apos; If FSO.FolderExists(&quot;C:\&quot;) Then ...
844 Dim bExists As Boolean &apos; Return value
845 Dim oSfa As Object &apos; com.sun.star.ucb.SimpleFileAccess
847 Const cstThisSub = &quot;FileSystem.FolderExists&quot;
848 Const cstSubArgs = &quot;FolderName&quot;
850 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
851 bExists = False
853 Check:
854 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
855 If Not SF_Utils._ValidateFile(FolderName, &quot;FolderName&quot;) Then GoTo Finally
856 End If
857 FolderName = SF_FileSystem._ConvertToUrl(FolderName)
859 Try:
860 Set oSfa = SF_Utils._GetUnoService(&quot;FileAccess&quot;)
861 bExists = oSfa.isFolder(FolderName)
863 Finally:
864 FolderExists = bExists
865 SF_Utils._ExitFunction(cstThisSub)
866 Exit Function
867 Catch:
868 GoTo Finally
869 End Function &apos; ScriptForge.SF_FileSystem.FolderExists
871 REM -----------------------------------------------------------------------------
872 Public Function GetBaseName(Optional ByVal FileName As Variant) As String
873 &apos;&apos;&apos; Returns the BaseName part of the last component of a File- or FolderName, without its extension
874 &apos;&apos;&apos; The method does not check for the existence of the specified file or folder
875 &apos;&apos;&apos; Args:
876 &apos;&apos;&apos; FileName: Path and file name
877 &apos;&apos;&apos; Returns:
878 &apos;&apos;&apos; The BaseName of the given argument in native operating system format. May be empty
879 &apos;&apos;&apos; Example:
880 &apos;&apos;&apos; Dim a As String
881 &apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
882 &apos;&apos;&apos; a = FSO.GetBaseName(&quot;C:\Windows\Notepad.exe&quot;) returns Notepad
884 Dim sBase As String &apos; Return value
885 Dim sExt As String &apos; Extension
886 Dim sName As String &apos; Last component of FileName
887 Dim vName As Variant &apos; Array of trunks of sName
888 Const cstThisSub = &quot;FileSystem.GetBaseName&quot;
889 Const cstSubArgs = &quot;FileName&quot;
891 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
892 sBase = &quot;&quot;
894 Check:
895 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
896 If Not SF_Utils._ValidateFile(FileName, &quot;FileName&quot;) Then GoTo Finally
897 End If
899 Try:
900 sName = SF_FileSystem.GetName(FileName)
901 If Len(sName) &gt; 0 Then
902 If InStr(sName, &quot;.&quot;) &gt; 0 Then
903 vName = Split(sName, &quot;.&quot;)
904 sExt = vName(UBound(vName))
905 sBase = Left(sName, Len(sName) - Len(sExt) - 1)
906 Else
907 sBase = sName
908 End If
909 End If
911 Finally:
912 GetBaseName = sBase
913 SF_Utils._ExitFunction(cstThisSub)
914 Exit Function
915 Catch:
916 GoTo Finally
917 End Function &apos; ScriptForge.SF_FileSystem.GetBaseName
919 REM -----------------------------------------------------------------------------
920 Public Function GetExtension(Optional ByVal FileName As Variant) As String
921 &apos;&apos;&apos; Returns the extension part of a File- or FolderName, without the dot (.).
922 &apos;&apos;&apos; The method does not check for the existence of the specified file or folder
923 &apos;&apos;&apos; Args:
924 &apos;&apos;&apos; FileName: Path and file name
925 &apos;&apos;&apos; Returns:
926 &apos;&apos;&apos; The extension without a leading dot. May be empty
927 &apos;&apos;&apos; Example:
928 &apos;&apos;&apos; Dim a As String
929 &apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
930 &apos;&apos;&apos; a = FSO.GetExtension(&quot;C:\Windows\Notepad.exe&quot;) returns exe
932 Dim sExt As String &apos; Return value
933 Dim sName As String &apos; Last component of FileName
934 Dim vName As Variant &apos; Array of trunks of sName
935 Const cstThisSub = &quot;FileSystem.GetExtension&quot;
936 Const cstSubArgs = &quot;FileName&quot;
938 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
939 sExt = &quot;&quot;
941 Check:
942 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
943 If Not SF_Utils._ValidateFile(FileName, &quot;FileName&quot;) Then GoTo Finally
944 End If
946 Try:
947 sName = SF_FileSystem.GetName(FileName)
948 If Len(sName) &gt; 0 And InStr(sName, &quot;.&quot;) &gt; 0 Then
949 vName = Split(sName, &quot;.&quot;)
950 sExt = vName(UBound(vName))
951 End If
953 Finally:
954 GetExtension = sExt
955 SF_Utils._ExitFunction(cstThisSub)
956 Exit Function
957 Catch:
958 GoTo Finally
959 End Function &apos; ScriptForge.SF_FileSystem.GetExtension
961 REM -----------------------------------------------------------------------------
962 Public Function GetFileLen(Optional ByVal FileName As Variant) As Currency
963 &apos;&apos;&apos; Return file size in bytes with four decimals &apos;&apos;&apos;
964 &apos;&apos;&apos; Args:
965 &apos;&apos;&apos; FileName: a string representing a file
966 &apos;&apos;&apos; Returns:
967 &apos;&apos;&apos; File size if FileName exists
968 &apos;&apos;&apos; 0 when FileName belongs to a document&apos;s internal file systems.
969 &apos;&apos;&apos; Exceptions:
970 &apos;&apos;&apos; UNKNOWNFILEERROR The file does not exist or is a folder
971 &apos;&apos;&apos; Example:
972 &apos;&apos;&apos; Print SF_FileSystem.GetFileLen(&quot;C:\pagefile.sys&quot;)
974 Dim curSize As Currency &apos; Return value
975 Const cstPyHelper = &quot;$&quot; &amp; &quot;_SF_FileSystem__GetFilelen&quot;
976 Const cstThisSub = &quot;FileSystem.GetFileLen&quot;
977 Const cstSubArgs = &quot;FileName&quot;
979 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
980 curSize = 0
982 Check:
983 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
984 If Not SF_Utils._ValidateFile(FileName, &quot;FileName&quot;) Then GoTo Finally
985 End If
987 Try:
988 If SF_FileSystem.FileExists(FileName) Then
989 If SF_FileSystem._IsDocFileSystem(FileName) Then
990 curSize = 0
991 Else
992 With ScriptForge.SF_Session
993 curSize = .ExecutePythonScript(.SCRIPTISSHARED, _SF_.PythonHelper &amp; cstPyHelper _
994 , _ConvertFromUrl(FileName))
995 End With
996 End If
997 Else
998 GoTo CatchNotExists
999 End If
1001 Finally:
1002 GetFileLen = curSize
1003 SF_Utils._ExitFunction(cstThisSub)
1004 Exit Function
1005 Catch:
1006 GoTo Finally
1007 CatchNotExists:
1008 SF_Exception.RaiseFatal(UNKNOWNFILEERROR, &quot;FileName&quot;, FileName)
1009 GoTo Finally
1010 End Function &apos; ScriptForge.SF_FileSystem.GetFileLen
1012 REM -----------------------------------------------------------------------------
1013 Public Function GetFileModified(Optional ByVal FileName As Variant) As Variant
1014 &apos;&apos;&apos; Returns the last modified date for the given file
1015 &apos;&apos;&apos; The method is not supported for document&apos;s internal file systems.
1016 &apos;&apos;&apos; Args:
1017 &apos;&apos;&apos; FileName: a string representing an existing file
1018 &apos;&apos;&apos; Returns:
1019 &apos;&apos;&apos; The modification date and time as a Basic Date
1020 &apos;&apos;&apos; Exceptions:
1021 &apos;&apos;&apos; UNKNOWNFILEERROR The file does not exist or is a folder
1022 &apos;&apos;&apos; FILESYSTEMERROR The method is not applicable on document&apos;s file systems
1023 &apos;&apos;&apos; Example:
1024 &apos;&apos;&apos; Dim a As Date
1025 &apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
1026 &apos;&apos;&apos; a = FSO.GetFileModified(&quot;C:\Temp\myDoc.odt&quot;)
1028 Dim dModified As Date &apos; Return value
1029 Dim oModified As New com.sun.star.util.DateTime
1030 Dim oSfa As Object &apos; com.sun.star.ucb.SimpleFileAccess
1032 Const cstThisSub = &quot;FileSystem.GetFileModified&quot;
1033 Const cstSubArgs = &quot;FileName&quot;
1035 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
1036 dModified = 0
1038 Check:
1039 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
1040 If Not SF_Utils._ValidateFile(FileName, &quot;FileName&quot;) Then GoTo Finally
1041 End If
1042 If SF_FileSystem._IsDocFileSystem(FileName) Then GoTo CatchNotSupported
1044 Try:
1045 Set oSfa = SF_Utils._GetUnoService(&quot;FileAccess&quot;)
1046 If SF_FileSystem.FileExists(FileName) Then
1047 FileName = SF_FileSystem._ConvertToUrl(FileName)
1048 Set oModified = oSfa.getDateTimeModified(FileName)
1049 dModified = CDateFromUnoDateTime(oModified)
1050 Else
1051 GoTo CatchNotExists
1052 End If
1054 Finally:
1055 GetFileModified = dModified
1056 SF_Utils._ExitFunction(cstThisSub)
1057 Exit Function
1058 Catch:
1059 GoTo Finally
1060 CatchNotExists:
1061 SF_Exception.RaiseFatal(UNKNOWNFILEERROR, &quot;FileName&quot;, FileName)
1062 GoTo Finally
1063 CatchNotSupported:
1064 SF_Exception.RaiseFatal(FILESYSTEMERROR, &quot;FileName&quot;, Split(cstThisSub, &quot;.&quot;)(1), FileName)
1065 GoTo Finally
1066 End Function &apos; ScriptForge.SF_FileSystem.GetFileModified
1068 REM -----------------------------------------------------------------------------
1069 Public Function GetName(Optional ByVal FileName As Variant) As String
1070 &apos;&apos;&apos; Returns the last component of a File- or FolderName
1071 &apos;&apos;&apos; The method does not check for the existence of the specified file or folder
1072 &apos;&apos;&apos; Args:
1073 &apos;&apos;&apos; FileName: Path and file name
1074 &apos;&apos;&apos; Returns:
1075 &apos;&apos;&apos; The last component of the full file name in native operating system format
1076 &apos;&apos;&apos; Example:
1077 &apos;&apos;&apos; Dim a As String
1078 &apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
1079 &apos;&apos;&apos; a = FSO.GetName(&quot;C:\Windows\Notepad.exe&quot;) returns Notepad.exe
1081 Dim sName As String &apos; Return value
1082 Dim vFile As Variant &apos; Array of components
1083 Const cstThisSub = &quot;FileSystem.GetName&quot;
1084 Const cstSubArgs = &quot;FileName&quot;
1086 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
1087 sName = &quot;&quot;
1089 Check:
1090 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
1091 If Not SF_Utils._ValidateFile(FileName, &quot;FileName&quot;) Then GoTo Finally
1092 End If
1093 FileName = SF_FileSystem._ConvertToUrl(FileName)
1095 Try:
1096 If Len(FileName) &gt; 0 Then
1097 If Right(FileName, 1) = &quot;/&quot; Then FileName = Left(FileName, Len(FileName) - 1)
1098 vFile = Split(FileName, &quot;/&quot;)
1099 sName = ConvertFromUrl(vFile(UBound(vFile))) &apos; Always in SYS format
1100 End If
1102 Finally:
1103 GetName = sName
1104 SF_Utils._ExitFunction(cstThisSub)
1105 Exit Function
1106 Catch:
1107 GoTo Finally
1108 End Function &apos; ScriptForge.SF_FileSystem.GetName
1110 REM -----------------------------------------------------------------------------
1111 Public Function GetParentFolderName(Optional ByVal FileName As Variant) As String
1112 &apos;&apos;&apos; Returns a string containing the name of the parent folder of the last component in a specified File- or FolderName
1113 &apos;&apos;&apos; The method does not check for the existence of the specified file or folder
1114 &apos;&apos;&apos; Args:
1115 &apos;&apos;&apos; FileName: Path and file name
1116 &apos;&apos;&apos; Returns:
1117 &apos;&apos;&apos; A FolderName including its final path separator
1118 &apos;&apos;&apos; Example:
1119 &apos;&apos;&apos; Dim a As String
1120 &apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
1121 &apos;&apos;&apos; a = FSO.GetParentFolderName(&quot;C:\Windows\Notepad.exe&quot;) returns C:\Windows\
1123 Dim sFolder As String &apos; Return value
1124 Dim sName As String &apos; Last component of FileName
1125 Dim vFile As Variant &apos; Array of file components
1126 Const cstThisSub = &quot;FileSystem.GetParentFolderName&quot;
1127 Const cstSubArgs = &quot;FileName&quot;
1129 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
1130 sFolder = &quot;&quot;
1132 Check:
1133 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
1134 If Not SF_Utils._ValidateFile(FileName, &quot;FileName&quot;) Then GoTo Finally
1135 End If
1136 FileName = SF_FileSystem._ConvertToUrl(FileName)
1138 Try:
1139 If Right(FileName, 1) = &quot;/&quot; Then FileName = Left(FileName, Len(FileName) - 1)
1140 vFile = Split(FileName, &quot;/&quot;)
1141 If UBound(vFile) &gt;= 0 Then vFile(UBound(vFile)) = &quot;&quot;
1142 sFolder = Join(vFile, &quot;/&quot;)
1143 If sFolder = &quot;&quot; Or Right(sFolder, 1) &lt;&gt; &quot;/&quot; Then sFolder = sFolder &amp; &quot;/&quot;
1145 Finally:
1146 GetParentFolderName = SF_FileSystem._ConvertFromUrl(sFolder)
1147 SF_Utils._ExitFunction(cstThisSub)
1148 Exit Function
1149 Catch:
1150 GoTo Finally
1151 End Function &apos; ScriptForge.SF_FileSystem.GetParentFolderName
1153 REM -----------------------------------------------------------------------------
1154 Public Function GetProperty(Optional ByVal PropertyName As Variant) As Variant
1155 &apos;&apos;&apos; Return the actual value of the given property
1156 &apos;&apos;&apos; Args:
1157 &apos;&apos;&apos; PropertyName: the name of the property as a string
1158 &apos;&apos;&apos; Returns:
1159 &apos;&apos;&apos; The actual value of the property
1160 &apos;&apos;&apos; Exceptions
1161 &apos;&apos;&apos; ARGUMENTERROR The property does not exist
1163 Const cstThisSub = &quot;FileSystem.GetProperty&quot;
1164 Const cstSubArgs = &quot;PropertyName&quot;
1166 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
1167 GetProperty = Null
1169 Check:
1170 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
1171 If Not SF_Utils._Validate(PropertyName, &quot;PropertyName&quot;, V_STRING, Properties()) Then GoTo Catch
1172 End If
1174 Try:
1175 Select Case UCase(PropertyName)
1176 Case UCase(&quot;ConfigFolder&quot;) : GetProperty = ConfigFolder
1177 Case UCase(&quot;ExtensionsFolder&quot;) : GetProperty = ExtensionsFolder
1178 Case UCase(&quot;FileNaming&quot;) : GetProperty = FileNaming
1179 Case UCase(&quot;HomeFolder&quot;) : GetProperty = HomeFolder
1180 Case UCase(&quot;InstallFolder&quot;) : GetProperty = InstallFolder
1181 Case UCase(&quot;TemplatesFolder&quot;) : GetProperty = TemplatesFolder
1182 Case UCase(&quot;TemporaryFolder&quot;) : GetProperty = TemporaryFolder
1183 Case UCase(&quot;UserTemplatesFolder&quot;) : GetProperty = UserTemplatesFolder
1184 Case Else
1185 End Select
1187 Finally:
1188 SF_Utils._ExitFunction(cstThisSub)
1189 Exit Function
1190 Catch:
1191 GoTo Finally
1192 End Function &apos; ScriptForge.SF_FileSystem.GetProperty
1194 REM -----------------------------------------------------------------------------
1195 Public Function GetTempName(Optional ByVal Extension As Variant) As String
1196 &apos;&apos;&apos; Returns a randomly generated temporary file name that is useful for performing
1197 &apos;&apos;&apos; operations that require a temporary file : the method does not create any file
1198 &apos;&apos;&apos; Args:
1199 &apos;&apos;&apos; Returns:
1200 &apos;&apos;&apos; A FileName as a String that can be used f.i. with CreateTextFile()
1201 &apos;&apos;&apos; The FileName has as suffix the given extension.
1202 &apos;&apos;&apos; Example:
1203 &apos;&apos;&apos; Dim a As String
1204 &apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
1205 &apos;&apos;&apos; a = FSO.GetTempName(&quot;txt&quot;) &apos; /tmp/SF_123456.txt
1206 &apos;&apos;&apos; a = FSO.GetTempName() &apos; /tmp/SF_234567
1208 Dim sFile As String &apos; Return value
1209 Dim sExtension As String &apos; The given extension preceded by a dot
1210 Dim lRandom As Long &apos; Random integer
1212 Const cstThisSub = &quot;FileSystem.GetTempName&quot;
1213 Const cstSubArgs = &quot;&quot;
1215 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
1216 sFile = &quot;&quot;
1218 Check:
1219 If IsMissing(Extension) Or IsEmpty(Extension) Then Extension = &quot;&quot;
1220 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
1221 If Not SF_Utils._Validate(Extension, &quot;Extension&quot;, V_STRING) Then GoTo Catch
1222 End If
1224 Try:
1225 lRandom = SF_Session.ExecuteCalcFunction(&quot;RANDBETWEEN.NV&quot;, 1, 999999)
1226 If Len(Extension) &gt; 0 Then sExtension = &quot;.&quot; &amp; Extension Else sExtension = &quot;&quot;
1227 sFile = SF_FileSystem.TemporaryFolder &amp; &quot;SF_&quot; &amp; Right(&quot;000000&quot; &amp; lRandom, 6) &amp; sExtension
1229 Finally:
1230 GetTempName = SF_FileSystem._ConvertFromUrl(sFile)
1231 SF_Utils._ExitFunction(cstThisSub)
1232 Exit Function
1233 Catch:
1234 GoTo Finally
1235 End Function &apos; ScriptForge.SF_FileSystem.GetTempName
1237 REM -----------------------------------------------------------------------------
1238 Public Function HashFile(Optional ByVal FileName As Variant _
1239 , Optional ByVal Algorithm As Variant _
1240 ) As String
1241 &apos;&apos;&apos; Return an hexadecimal string representing a checksum of the given file
1242 &apos;&apos;&apos; Next algorithms are supported: MD5, SHA1, SHA224, SHA256, SHA384 and SHA512
1243 &apos;&apos;&apos; The method is not supported for document&apos;s internal file systems.
1244 &apos;&apos;&apos; Args:
1245 &apos;&apos;&apos; FileName: a string representing a file
1246 &apos;&apos;&apos; Algorithm: The hashing algorithm to use
1247 &apos;&apos;&apos; Returns:
1248 &apos;&apos;&apos; The requested checksum as a string. Hexadecimal digits are lower-cased
1249 &apos;&apos;&apos; A zero-length string when an error occurred
1250 &apos;&apos;&apos; Exceptions:
1251 &apos;&apos;&apos; UNKNOWNFILEERROR The file does not exist or is a folder
1252 &apos;&apos;&apos; FILESYSTEMERROR The method is not applicable on document&apos;s file systems
1253 &apos;&apos;&apos; Example:
1254 &apos;&apos;&apos; Print SF_FileSystem.HashFile(&quot;C:\pagefile.sys&quot;, &quot;MD5&quot;)
1256 Dim sHash As String &apos; Return value
1257 Const cstPyHelper = &quot;$&quot; &amp; &quot;_SF_FileSystem__HashFile&quot;
1258 Const cstThisSub = &quot;FileSystem.HashFile&quot;
1259 Const cstSubArgs = &quot;FileName, Algorithm=&quot;&quot;MD5&quot;&quot;|&quot;&quot;SHA1&quot;&quot;|&quot;&quot;SHA224&quot;&quot;|&quot;&quot;SHA256&quot;&quot;|&quot;&quot;SHA384&quot;&quot;|&quot;&quot;SHA512&quot;&quot;&quot;
1261 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
1262 sHash = &quot;&quot;
1264 Check:
1265 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
1266 If Not SF_Utils._ValidateFile(FileName, &quot;FileName&quot;) Then GoTo Finally
1267 If Not SF_Utils._Validate(Algorithm, &quot;Algorithm&quot;, V_STRING _
1268 , Array(&quot;MD5&quot;, &quot;SHA1&quot;, &quot;SHA224&quot;, &quot;SHA256&quot;, &quot;SHA384&quot;, &quot;SHA512&quot;)) Then GoTo Finally
1269 End If
1270 If SF_FileSystem._IsDocFileSystem(FileName) Then GoTo CatchNotSupported
1272 Try:
1273 If SF_FileSystem.FileExists(FileName) Then
1274 With ScriptForge.SF_Session
1275 sHash = .ExecutePythonScript(.SCRIPTISSHARED, _SF_.PythonHelper &amp; cstPyHelper _
1276 , _ConvertFromUrl(FileName), LCase(Algorithm))
1277 End With
1278 Else
1279 GoTo CatchNotExists
1280 End If
1282 Finally:
1283 HashFile = sHash
1284 SF_Utils._ExitFunction(cstThisSub)
1285 Exit Function
1286 Catch:
1287 GoTo Finally
1288 CatchNotExists:
1289 SF_Exception.RaiseFatal(UNKNOWNFILEERROR, &quot;FileName&quot;, FileName)
1290 GoTo Finally
1291 CatchNotSupported:
1292 SF_Exception.RaiseFatal(FILESYSTEMERROR, &quot;FileName&quot;, Split(cstThisSub, &quot;.&quot;)(1), FileName)
1293 GoTo Finally
1294 End Function &apos; ScriptForge.SF_FileSystem.HashFile
1296 REM -----------------------------------------------------------------------------
1297 Public Function Methods() As Variant
1298 &apos;&apos;&apos; Return the list or methods of the FileSystem service as an array
1300 Methods = Array(&quot;BuildPath&quot; _
1301 , &quot;CompareFiles&quot; _
1302 , &quot;CopyFile&quot; _
1303 , &quot;CopyFolder&quot; _
1304 , &quot;CreateFolder&quot; _
1305 , &quot;CreateTextFile&quot; _
1306 , &quot;DeleteFile&quot; _
1307 , &quot;DeleteFolder&quot; _
1308 , &quot;ExtensionFolder&quot; _
1309 , &quot;FileExists&quot; _
1310 , &quot;Files&quot; _
1311 , &quot;FolderExists&quot; _
1312 , &quot;GetBaseName&quot; _
1313 , &quot;GetExtension&quot; _
1314 , &quot;GetFileLen&quot; _
1315 , &quot;GetFileModified&quot; _
1316 , &quot;GetName&quot; _
1317 , &quot;GetParentFolderName&quot; _
1318 , &quot;GetTempName&quot; _
1319 , &quot;HashFile&quot; _
1320 , &quot;MoveFile&quot; _
1321 , &quot;MoveFolder&quot; _
1322 , &quot;Normalize&quot; _
1323 , &quot;OpenTextFile&quot; _
1324 , &quot;PickFile&quot; _
1325 , &quot;PickFolder&quot; _
1326 , &quot;SubFolders&quot; _
1329 End Function &apos; ScriptForge.SF_FileSystem.Methods
1331 REM -----------------------------------------------------------------------------
1332 Public Function MoveFile(Optional ByVal Source As Variant _
1333 , Optional ByVal Destination As Variant _
1334 ) As Boolean
1335 &apos;&apos;&apos; Moves one or more files from one location to another
1336 &apos;&apos;&apos; Args:
1337 &apos;&apos;&apos; Source: FileName or NamePattern which can include wildcard characters, for one or more files to be moved
1338 &apos;&apos;&apos; Destination: FileName where the single Source file is to be moved
1339 &apos;&apos;&apos; If Source and Destination have the same parent folder MoveFile amounts to renaming the Source
1340 &apos;&apos;&apos; or FolderName where the multiple files from Source are to be moved
1341 &apos;&apos;&apos; If FolderName does not exist, it is created
1342 &apos;&apos;&apos; Anyway, wildcard characters are not allowed in Destination
1343 &apos;&apos;&apos; Returns:
1344 &apos;&apos;&apos; True if at least one file has been moved
1345 &apos;&apos;&apos; False if an error occurred
1346 &apos;&apos;&apos; An error also occurs if a source using wildcard characters doesn&apos;t match any files.
1347 &apos;&apos;&apos; The method stops on the first error it encounters
1348 &apos;&apos;&apos; No attempt is made to roll back or undo any changes made before an error occurs
1349 &apos;&apos;&apos; Exceptions:
1350 &apos;&apos;&apos; UNKNOWNFILEERROR Source does not exist
1351 &apos;&apos;&apos; UNKNOWNFOLDERERROR Source folder or Destination folder does not exist
1352 &apos;&apos;&apos; NOFILEMATCHERROR No file matches Source containing wildcards
1353 &apos;&apos;&apos; NOTAFOLDERERROR Destination is a file, not a folder
1354 &apos;&apos;&apos; NOTAFILEERROR Destination is a folder, not a file
1355 &apos;&apos;&apos; OVERWRITEERROR Destination can not be overwritten
1356 &apos;&apos;&apos; Example:
1357 &apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
1358 &apos;&apos;&apos; FSO.MoveFile(&quot;C:\Temp1\*.*&quot;, &quot;C:\Temp2\&quot;) &apos; Only files are moved, subfolders are not
1360 Dim bMove As Boolean &apos; Return value
1362 Const cstThisSub = &quot;FileSystem.MoveFile&quot;
1363 Const cstSubArgs = &quot;Source, Destination&quot;
1365 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
1366 bMove = False
1368 Check:
1369 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
1370 If Not SF_Utils._ValidateFile(Source, &quot;Source&quot;, True) Then GoTo Finally
1371 If Not SF_Utils._ValidateFile(Destination, &quot;Destination&quot;, False) Then GoTo Finally
1372 End If
1374 Try:
1375 bMove = SF_FileSystem._CopyMove(&quot;MoveFile&quot;, Source, Destination, False)
1377 Finally:
1378 MoveFile = bMove
1379 SF_Utils._ExitFunction(cstThisSub)
1380 Exit Function
1381 Catch:
1382 GoTo Finally
1383 End Function &apos; ScriptForge.SF_FileSystem.MoveFile
1385 REM -----------------------------------------------------------------------------
1386 Public Function MoveFolder(Optional ByVal Source As Variant _
1387 , Optional ByVal Destination As Variant _
1388 ) As Boolean
1389 &apos;&apos;&apos; Moves one or more folders from one location to another
1390 &apos;&apos;&apos; Args:
1391 &apos;&apos;&apos; Source: FolderName or NamePattern which can include wildcard characters, for one or more folders to be moved
1392 &apos;&apos;&apos; Destination: FolderName where the single Source folder is to be moved
1393 &apos;&apos;&apos; FolderName must not exist
1394 &apos;&apos;&apos; or FolderName where the multiple folders from Source are to be moved
1395 &apos;&apos;&apos; If FolderName does not exist, it is created
1396 &apos;&apos;&apos; Anyway, wildcard characters are not allowed in Destination
1397 &apos;&apos;&apos; Returns:
1398 &apos;&apos;&apos; True if at least one folder has been moved
1399 &apos;&apos;&apos; False if an error occurred
1400 &apos;&apos;&apos; An error also occurs if a source using wildcard characters doesn&apos;t match any folders.
1401 &apos;&apos;&apos; The method stops on the first error it encounters
1402 &apos;&apos;&apos; No attempt is made to roll back or undo any changes made before an error occurs
1403 &apos;&apos;&apos; Exceptions:
1404 &apos;&apos;&apos; UNKNOWNFILEERROR Source does not exist
1405 &apos;&apos;&apos; UNKNOWNFOLDERERROR Source folder or Destination folder does not exist
1406 &apos;&apos;&apos; NOFILEMATCHERROR No file matches Source containing wildcards
1407 &apos;&apos;&apos; NOTAFOLDERERROR Destination is a file, not a folder
1408 &apos;&apos;&apos; OVERWRITEERROR Destination can not be overwritten
1409 &apos;&apos;&apos; Example:
1410 &apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
1411 &apos;&apos;&apos; FSO.MoveFolder(&quot;C:\Temp1\*&quot;, &quot;C:\Temp2\&quot;)
1413 Dim bMove As Boolean &apos; Return value
1415 Const cstThisSub = &quot;FileSystem.MoveFolder&quot;
1416 Const cstSubArgs = &quot;Source, Destination&quot;
1418 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
1419 bMove = False
1421 Check:
1422 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
1423 If Not SF_Utils._ValidateFile(Source, &quot;Source&quot;, True) Then GoTo Finally
1424 If Not SF_Utils._ValidateFile(Destination, &quot;Destination&quot;, False) Then GoTo Finally
1425 End If
1427 Try:
1428 bMove = SF_FileSystem._CopyMove(&quot;MoveFolder&quot;, Source, Destination, False)
1430 Finally:
1431 MoveFolder = bMove
1432 SF_Utils._ExitFunction(cstThisSub)
1433 Exit Function
1434 Catch:
1435 GoTo Finally
1436 End Function &apos; ScriptForge.SF_FileSystem.MoveFolder
1438 REM -----------------------------------------------------------------------------
1439 Public Function Normalize(Optional ByVal FileName As Variant) As String
1440 &apos;&apos;&apos; Normalize a pathname by collapsing redundant separators and up-level references
1441 &apos;&apos;&apos; so that A//B, A/B/, A/./B and A/foo/../B all become A/B.
1442 &apos;&apos;&apos; On Windows, it converts forward slashes to backward slashes.
1443 &apos;&apos;&apos; The method returns the input string when the file is from a document&apos;s internal file systems.
1444 &apos;&apos;&apos; Args:
1445 &apos;&apos;&apos; FileName: a string representing a file. The file may not exist.
1446 &apos;&apos;&apos; Returns:
1447 &apos;&apos;&apos; The normalized filename in filenaming notation
1448 &apos;&apos;&apos; Example:
1449 &apos;&apos;&apos; Print SF_FileSystem.Normalize(&quot;A/foo/../B/C/./D//E&quot;) &apos; A/B/C/D/E
1451 Dim sNorm As String &apos; Return value
1452 Const cstPyHelper = &quot;$&quot; &amp; &quot;_SF_FileSystem__Normalize&quot;
1453 Const cstThisSub = &quot;FileSystem.Normalize&quot;
1454 Const cstSubArgs = &quot;FileName&quot;
1456 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
1457 sNorm = &quot;&quot;
1459 Check:
1460 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
1461 If Not SF_Utils._ValidateFile(FileName, &quot;FileName&quot;) Then GoTo Finally
1462 End If
1464 Try:
1465 If SF_FileSystem._IsDocFileSystem(FileName) Then
1466 sNorm = FileName
1467 Else
1468 With ScriptForge.SF_Session
1469 sNorm = .ExecutePythonScript(.SCRIPTISSHARED, _SF_.PythonHelper &amp; cstPyHelper _
1470 , _ConvertFromUrl(FileName))
1471 &apos; The Python os.path expects and returns a file name in os notation
1472 If SF_FileSystem.FileNaming &lt;&gt; &quot;SYS&quot; Then sNorm = ConvertToUrl(sNorm)
1473 End With
1474 End If
1476 Finally:
1477 Normalize = sNorm
1478 SF_Utils._ExitFunction(cstThisSub)
1479 Exit Function
1480 Catch:
1481 GoTo Finally
1482 End Function &apos; ScriptForge.SF_FileSystem.Normalize
1484 REM -----------------------------------------------------------------------------
1485 Public Function OpenTextFile(Optional ByVal FileName As Variant _
1486 , Optional ByVal IOMode As Variant _
1487 , Optional ByVal Create As Variant _
1488 , Optional ByVal Encoding As Variant _
1489 ) As Object
1490 &apos;&apos;&apos; Opens a specified file and returns a TextStream object that can be used to read from, write to, or append to the file
1491 &apos;&apos;&apos; Args:
1492 &apos;&apos;&apos; FileName: Identifies the file to open
1493 &apos;&apos;&apos; IOMode: Indicates input/output mode. Can be one of three constants: ForReading, ForWriting, or ForAppending
1494 &apos;&apos;&apos; Create: Boolean value that indicates whether a new file can be created if the specified filename doesn&apos;t exist.
1495 &apos;&apos;&apos; The value is True if a new file and its parent folders may be created; False if they aren&apos;t created (default)
1496 &apos;&apos;&apos; Encoding: The character set that should be used
1497 &apos;&apos;&apos; Use one of the Names listed in https://www.iana.org/assignments/character-sets/character-sets.xhtml
1498 &apos;&apos;&apos; Note that LibreOffice does not implement all existing sets
1499 &apos;&apos;&apos; Default = UTF-8
1500 &apos;&apos;&apos; Returns:
1501 &apos;&apos;&apos; An instance of the SF_TextStream class representing the opened file or a Null object if an error occurred
1502 &apos;&apos;&apos; The method does not check if the file is really a text file
1503 &apos;&apos;&apos; It doesn&apos;t check either if the given encoding is implemented in LibreOffice nor if it is the right one
1504 &apos;&apos;&apos; Exceptions:
1505 &apos;&apos;&apos; UNKNOWNFILEERROR File does not exist
1506 &apos;&apos;&apos; Example:
1507 &apos;&apos;&apos; Dim myFile As Object
1508 &apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
1509 &apos;&apos;&apos; Set myFile = FSO.OpenTextFile(&quot;C:\Temp\ThisFile.txt&quot;, FSO.ForReading)
1510 &apos;&apos;&apos; If Not IsNull(myFile) Then &apos; ... Go ahead with reading text lines
1512 Dim oTextStream As Object &apos; Return value
1513 Dim bExists As Boolean &apos; When True, file to open does exist
1514 Dim bEmbeddedFile As Boolean &apos; When True, file to open is embedded in a document&apos;s internal file system
1515 Dim oSfa As Object &apos; com.sun.star.ucb.SimpleFileAccess
1516 Const cstThisSub = &quot;FileSystem.OpenTextFile&quot;
1517 Const cstSubArgs = &quot;FileName, [IOMode=1|2|8], [Create=False], [Encoding=&quot;&quot;UTF-8&quot;&quot;]&quot;
1519 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
1520 Set oTextStream = Nothing
1522 Check:
1523 With SF_FileSystem
1524 If IsMissing(IOMode) Or IsEmpty(IOMode) Then IOMode = cstForReading
1525 If IsMissing(Create) Or IsEmpty(Create) Then Create = False
1526 If IsMissing(Encoding) Or IsEmpty(Encoding) Then Encoding = &quot;UTF-8&quot;
1527 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
1528 If Not SF_Utils._ValidateFile(FileName, &quot;FileName&quot;) Then GoTo Finally
1529 If Not SF_Utils._Validate(IOMode, &quot;IOMode&quot;, V_NUMERIC _
1530 , Array(cstForReading, cstForWriting, cstForAppending)) _
1531 Then GoTo Finally
1532 If Not SF_Utils._Validate(Create, &quot;Create&quot;, V_BOOLEAN) Then GoTo Finally
1533 If Not SF_Utils._Validate(Encoding, &quot;Encoding&quot;, V_STRING) Then GoTo Finally
1534 End If
1536 bExists = .FileExists(FileName)
1537 Select Case IOMode
1538 Case ForReading : If Not bExists Then GoTo CatchNotExists
1539 Case Else : If Not bExists And Not Create Then GoTo CatchNotExists
1540 End Select
1542 If IOMode = ForAppending And Not bExists Then IOMode = ForWriting
1544 bEmbeddedFile = SF_FileSystem._IsDocFileSystem(FileName)
1545 End With
1547 Try:
1548 &apos; Create and initialize TextStream class instance
1549 Set oTextStream = New SF_TextStream
1550 With oTextStream
1551 .[Me] = oTextStream
1552 .[_Parent] = SF_FileSystem
1553 ._IsEmbeddedFile = bEmbeddedFile
1554 If bEmbeddedFile And (IOMode = cstForWriting Or IOMode = cstForAppending) Then
1555 &apos; Updates of an embedded file are done on a copy
1556 ._EmbeddedFileName = SF_FileSystem._ConvertToUrl(FileName)
1557 ._FileName = SF_FileSystem._ConvertToUrl(SF_FileSystem.GetTempName(SF_FileSystem.GetExtension(FileName)))
1558 &apos; Create the copy if relevant
1559 If bExists Then
1560 Set oSfa = SF_Utils._GetUnoService(&quot;FileAccess&quot;)
1561 oSfa.copy(._EmbeddedFileName, ._FileName)
1562 End If
1563 Else
1564 ._FileName = SF_FileSystem._ConvertToUrl(FileName)
1565 End If
1566 ._IOMode = IOMode
1567 ._Encoding = Encoding
1568 ._FileExists = bExists
1569 ._Initialize()
1570 End With
1572 Finally:
1573 Set OpenTextFile = oTextStream
1574 SF_Utils._ExitFunction(cstThisSub)
1575 Exit Function
1576 Catch:
1577 GoTo Finally
1578 CatchNotExists:
1579 SF_Exception.RaiseFatal(UNKNOWNFILEERROR, &quot;FileName&quot;, FileName)
1580 GoTo Finally
1581 End Function &apos; ScriptForge.SF_FileSystem.OpenTextFile
1583 REM -----------------------------------------------------------------------------
1584 Public Function PickFile(Optional ByVal DefaultFile As Variant _
1585 , Optional ByVal Mode As Variant _
1586 , Optional ByVal Filter As Variant _
1587 ) As String
1588 &apos;&apos;&apos; Returns the file selected with a FilePicker dialog box
1589 &apos;&apos;&apos; The mode, OPEN or SAVE, and the filter may be preset
1590 &apos;&apos;&apos; If mode = SAVE and the picked file exists, a warning message will be displayed
1591 &apos;&apos;&apos; Modified from Andrew Pitonyak&apos;s Base Macro Programming §10.4
1592 &apos;&apos;&apos; The method is not supported for document&apos;s internal file systems.
1593 &apos;&apos;&apos; Args:
1594 &apos;&apos;&apos; DefaultFile: Folder part: the FolderName from which to start. Default = the last selected folder
1595 &apos;&apos;&apos; File part: the default file to open or save
1596 &apos;&apos;&apos; Mode: &quot;OPEN&quot; (input file) or &quot;SAVE&quot; (output file)
1597 &apos;&apos;&apos; Filter: by default only files having the given suffix will be displayed. Default = all suffixes
1598 &apos;&apos;&apos; The filter combo box will contain the given suffix filter (if not &quot;*&quot;) and &quot;*.*&quot;
1599 &apos;&apos;&apos; Returns:
1600 &apos;&apos;&apos; The selected FileName in FileNaming format or &quot;&quot; if the dialog was cancelled
1601 &apos;&apos;&apos; Exceptions:
1602 &apos;&apos;&apos; FILESYSTEMERROR The method is not applicable on document&apos;s file systems
1603 &apos;&apos;&apos; Example:
1604 &apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
1605 &apos;&apos;&apos; FSO.PickFile(&quot;C:\&quot;, &quot;OPEN&quot;, &quot;txt&quot;) &apos; Only *.txt files are displayed
1607 Dim oFileDialog As Object &apos; com.sun.star.ui.dialogs.FilePicker
1608 Dim oFileAccess As object &apos; com.sun.star.ucb.SimpleFileAccess
1609 Dim oPath As Object &apos; com.sun.star.util.PathSettings
1610 Dim iAccept As Integer &apos; Result of dialog execution
1611 Dim sInitPath As String &apos; Current working directory
1612 Dim sBaseFile As String
1613 Dim iMode As Integer &apos; Numeric alias for SelectMode
1614 Dim sFile As String &apos; Return value
1616 Const cstThisSub = &quot;FileSystem.PickFile&quot;
1617 Const cstSubArgs = &quot;[DefaultFile=&quot;&quot;&quot;&quot;], [Mode=&quot;&quot;OPEN&quot;&quot;|&quot;&quot;SAVE&quot;&quot;],[Filter=&quot;&quot;&quot;&quot;]&quot;
1619 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
1620 sFile = &quot;&quot;
1622 Check:
1623 If IsMissing(DefaultFile) Or IsEmpty(DefaultFile) Then DefaultFile = &quot;&quot;
1624 If IsMissing(Mode) Or IsEmpty(Mode) Then Mode = &quot;OPEN&quot;
1625 If IsMissing(Filter) Or IsEmpty(Filter) Then Filter = &quot;&quot;
1626 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
1627 If Not SF_Utils._ValidateFile(DefaultFile, &quot;DefaultFile&quot;, , True) Then GoTo Finally
1628 If Not SF_Utils._Validate(Mode, &quot;Mode&quot;, V_STRING, Array(&quot;OPEN&quot;, &quot;SAVE&quot;)) Then GoTo Finally
1629 If Not SF_Utils._Validate(Filter, &quot;Filter&quot;, V_STRING) Then GoTo Finally
1630 End If
1631 If SF_FileSystem._IsDocFileSystem(DefaultFile) Then GoTo CatchNotSupported
1632 DefaultFile = SF_FileSystem._ConvertToUrl(DefaultFile)
1634 Try:
1635 &apos; Derive numeric equivalent of the Mode argument: https://api.libreoffice.org/docs/idl/ref/TemplateDescription_8idl.html
1636 With com.sun.star.ui.dialogs.TemplateDescription
1637 If UCase(Mode) = &quot;OPEN&quot; Then iMode = .FILEOPEN_SIMPLE Else iMode = .FILESAVE_AUTOEXTENSION
1638 End With
1640 &apos; Activate the filepicker dialog
1641 Set oFileDialog = SF_Utils._GetUNOService(&quot;FilePicker&quot;)
1642 With oFileDialog
1643 .Initialize(Array(iMode))
1645 &apos; Set filters
1646 If Len(Filter) &gt; 0 Then .appendFilter(&quot;*.&quot; &amp; Filter, &quot;*.&quot; &amp; Filter) &apos; Twice: required by API
1647 .appendFilter(&quot;*.*&quot;, &quot;*.*&quot;)
1648 If Len(Filter) &gt; 0 Then .setCurrentFilter(&quot;*.&quot; &amp; Filter) Else .setCurrentFilter(&quot;*.*&quot;)
1650 &apos; Set initial folder
1651 If Len(DefaultFile) = 0 Then &apos; TODO: SF_Session.WorkingFolder
1652 Set oPath = SF_Utils._GetUNOService(&quot;PathSettings&quot;)
1653 sInitPath = oPath.Work &apos; Probably My Documents
1654 Else
1655 sInitPath = SF_FileSystem._ParseUrl(ConvertToUrl(DefaultFile)).Path
1656 End If
1658 &apos; Set default values
1659 Set oFileAccess = SF_Utils._GetUNOService(&quot;FileAccess&quot;)
1660 If oFileAccess.exists(sInitPath) Then .SetDisplayDirectory(sInitPath)
1661 sBaseFile = SF_FileSystem.GetName(DefaultFile)
1662 .setDefaultName(sBaseFile)
1664 &apos; Get selected file
1665 iAccept = .Execute()
1666 If iAccept = com.sun.star.ui.dialogs.ExecutableDialogResults.OK Then sFile = .getSelectedFiles()(0)
1668 &apos; Do not reuse a FilePicker, side effects observed (a.o. TDF#154462)
1669 .dispose()
1671 End With
1673 Finally:
1674 PickFile = SF_FileSystem._ConvertFromUrl(sFile)
1675 SF_Utils._ExitFunction(cstThisSub)
1676 Exit Function
1677 Catch:
1678 GoTo Finally
1679 CatchNotSupported:
1680 SF_Exception.RaiseFatal(FILESYSTEMERROR, &quot;DefaultFile&quot;, Split(cstThisSub, &quot;.&quot;)(1), DefaultFile)
1681 GoTo Finally
1682 End Function &apos; ScriptForge.SF_FileSystem.PickFile
1684 REM -----------------------------------------------------------------------------
1685 Public Function PickFolder(Optional ByVal DefaultFolder As Variant _
1686 , Optional ByVal FreeText As Variant _
1687 ) As String
1688 &apos;&apos;&apos; Display a FolderPicker dialog box
1689 &apos;&apos;&apos; The method is not supported for document&apos;s internal file systems.
1690 &apos;&apos;&apos; Args:
1691 &apos;&apos;&apos; DefaultFolder: the FolderName from which to start. Default = the last selected folder
1692 &apos;&apos;&apos; FreeText: text to display in the dialog. Default = &quot;&quot;
1693 &apos;&apos;&apos; Returns:
1694 &apos;&apos;&apos; The selected FolderName in URL or operating system format
1695 &apos;&apos;&apos; The zero-length string if the dialog was cancelled
1696 &apos;&apos;&apos; Exceptions:
1697 &apos;&apos;&apos; FILESYSTEMERROR The method is not applicable on document&apos;s file systems
1698 &apos;&apos;&apos; Example:
1699 &apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
1700 &apos;&apos;&apos; FSO.PickFolder(&quot;C:\&quot;, &quot;Choose a folder or press Cancel&quot;)
1702 Dim oFolderDialog As Object &apos; com.sun.star.ui.dialogs.FolderPicker
1703 Dim iAccept As Integer &apos; Value returned by the dialog (OK, Cancel, ..)
1704 Dim sFolder As String &apos; Return value &apos;
1706 Const cstThisSub = &quot;FileSystem.PickFolder&quot;
1707 Const cstSubArgs = &quot;[DefaultFolder=&quot;&quot;&quot;&quot;], [FreeText=&quot;&quot;&quot;&quot;]&quot;
1709 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
1710 sFolder = &quot;&quot;
1712 Check:
1713 If IsMissing(DefaultFolder) Or IsEmpty(DefaultFolder) Then DefaultFolder = &quot;&quot;
1714 If IsMissing(FreeText) Or IsEmpty(FreeText) Then FreeText = &quot;&quot;
1715 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
1716 If Not SF_Utils._ValidateFile(DefaultFolder, &quot;DefaultFolder&quot;, , True) Then GoTo Finally
1717 If Not SF_Utils._Validate(FreeText, &quot;FreeText&quot;, V_STRING) Then GoTo Finally
1718 End If
1719 If SF_FileSystem._IsDocFileSystem(DefaultFolder) Then GoTo CatchNotSupported
1720 DefaultFolder = SF_FileSystem._ConvertToUrl(DefaultFolder)
1722 Try:
1723 Set oFolderDialog = SF_Utils._GetUNOService(&quot;FolderPicker&quot;)
1724 If Not IsNull(oFolderDialog) Then
1725 With oFolderDialog
1726 If Len(DefaultFolder) &gt; 0 Then .DisplayDirectory = ConvertToUrl(DefaultFolder)
1727 .Description = FreeText
1728 iAccept = .Execute()
1729 &apos; https://api.libreoffice.org/docs/idl/ref/ExecutableDialogResults_8idl.html
1730 If iAccept = com.sun.star.ui.dialogs.ExecutableDialogResults.OK Then
1731 .DisplayDirectory = .Directory &apos; Set the next default initial folder to the selected one
1732 sFolder = .Directory &amp; &quot;/&quot;
1733 End If
1734 End With
1735 End If
1737 Finally:
1738 PickFolder = SF_FileSystem._ConvertFromUrl(sFolder)
1739 SF_Utils._ExitFunction(cstThisSub)
1740 Exit Function
1741 Catch:
1742 GoTo Finally
1743 CatchNotSupported:
1744 SF_Exception.RaiseFatal(FILESYSTEMERROR, &quot;DefaultFolder&quot;, Split(cstThisSub, &quot;.&quot;)(1), DefaultFolder)
1745 GoTo Finally
1746 End Function &apos; ScriptForge.SF_FileSystem.PickFolder
1748 REM -----------------------------------------------------------------------------
1749 Public Function Properties() As Variant
1750 &apos;&apos;&apos; Return the list or properties of the FileSystem module as an array
1752 Properties = Array( _
1753 &quot;ConfigFolder&quot; _
1754 , &quot;ExtensionsFolder&quot; _
1755 , &quot;FileNaming&quot; _
1756 , &quot;HomeFolder&quot; _
1757 , &quot;InstallFolder&quot; _
1758 , &quot;TemplatesFolder&quot; _
1759 , &quot;TemporaryFolder&quot; _
1760 , &quot;UserTemplatesFolder&quot; _
1763 End Function &apos; ScriptForge.SF_FileSystem.Properties
1765 REM -----------------------------------------------------------------------------
1766 Public Function SetProperty(Optional ByVal PropertyName As Variant _
1767 , Optional ByRef Value As Variant _
1768 ) As Boolean
1769 &apos;&apos;&apos; Set a new value to the given property
1770 &apos;&apos;&apos; Args:
1771 &apos;&apos;&apos; PropertyName: the name of the property as a string
1772 &apos;&apos;&apos; Value: its new value
1773 &apos;&apos;&apos; Exceptions
1774 &apos;&apos;&apos; ARGUMENTERROR The property does not exist
1776 Const cstThisSub = &quot;FileSystem.SetProperty&quot;
1777 Const cstSubArgs = &quot;PropertyName, Value&quot;
1779 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
1780 SetProperty = False
1782 Check:
1783 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
1784 If Not SF_Utils._Validate(PropertyName, &quot;PropertyName&quot;, V_STRING, Properties()) Then GoTo Catch
1785 End If
1787 Try:
1788 Select Case UCase(PropertyName)
1789 Case UCase(&quot;FileNaming&quot;) : FileNaming = Value
1790 Case Else
1791 End Select
1793 Finally:
1794 SF_Utils._ExitFunction(cstThisSub)
1795 Exit Function
1796 Catch:
1797 GoTo Finally
1798 End Function &apos; ScriptForge.SF_FileSystem.SetProperty
1800 REM -----------------------------------------------------------------------------
1801 Public Function SubFolders(Optional ByVal FolderName As Variant _
1802 , Optional ByVal Filter As Variant _
1803 , Optional ByVal IncludeSubfolders As Variant _
1804 ) As Variant
1805 &apos;&apos;&apos; Return an array of the FolderNames stored in the given folder. The folder must exist,
1806 &apos;&apos;&apos; Subfolders may be optionally explored too.
1807 &apos;&apos;&apos; Args:
1808 &apos;&apos;&apos; FolderName: the folder to explore
1809 &apos;&apos;&apos; Filter: contains wildcards (&quot;?&quot; and &quot;*&quot;) to limit the list to the relevant folders (default = &quot;&quot;)
1810 &apos;&apos;&apos; IncludeSubfolders: when True (default = False), subfolders are explored too.
1811 &apos;&apos;&apos; Returns:
1812 &apos;&apos;&apos; An array of strings, each entry is the FolderName of an existing folder
1813 &apos;&apos;&apos; Exceptions:
1814 &apos;&apos;&apos; UNKNOWNFOLDERERROR Folder does not exist
1815 &apos;&apos;&apos; NOTAFOLDERERROR FolderName is a file, not a folder
1816 &apos;&apos;&apos; Example:
1817 &apos;&apos;&apos; Dim a As Variant
1818 &apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
1819 &apos;&apos;&apos; a = FSO.SubFolders(&quot;C:\Windows\&quot;, IncludeSubfolders := True)
1821 Dim vSubFolders As Variant &apos; Return value
1822 Dim oSfa As Object &apos; com.sun.star.ucb.SimpleFileAccess
1823 Dim sFoldersColl As String &apos; cstSEPARATOR delimited string of list of folders (FileNaming notation)
1824 Dim i As Long
1826 Const cstThisSub = &quot;FileSystem.SubFolders&quot;
1827 Const cstSubArgs = &quot;FolderName, [Filter=&quot;&quot;&quot;&quot;], [IncludeSubfolders=False]&quot;
1829 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
1830 vSubFolders = Array()
1832 Check:
1833 If IsMissing(Filter) Or IsEmpty(Filter) Then Filter = &quot;&quot;
1834 If IsMissing(IncludeSubfolders) Or IsEmpty(IncludeSubfolders) Then IncludeSubfolders = False
1835 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
1836 If Not SF_Utils._ValidateFile(FolderName, &quot;FolderName&quot;) Then GoTo Finally
1837 If Not SF_Utils._Validate(Filter, &quot;Filter&quot;, V_STRING) Then GoTo Finally
1838 If Not SF_Utils._Validate(IncludeSubfolders, &quot;IncludeSubfolders&quot;, V_BOOLEAN) Then GoTo Finally
1839 End If
1840 If SF_FileSystem.FileExists(FolderName) Then GoTo CatchFile &apos; Must not be a file
1841 If Not SF_FileSystem.FolderExists(FolderName) Then GoTo CatchFolder &apos; Top folder must exist
1843 Try:
1844 sFoldersColl = &quot;&quot;
1845 Set oSfa = SF_Utils._GetUnoService(&quot;FileAccess&quot;)
1846 SF_FileSystem._ScanFolder(cstFolders, sFoldersColl, FolderName, oSfa, Filter, IncludeSubfolders)
1848 If Len(sFoldersColl) &gt; Len(cstSEPARATOR) Then vSubFolders() = Split(Mid(sFoldersColl, Len(cstSEPARATOR) + 1), cstSEPARATOR)
1850 Finally:
1851 SubFolders = vSubFolders
1852 SF_Utils._ExitFunction(cstThisSub)
1853 Exit Function
1854 Catch:
1855 GoTo Finally
1856 CatchFile:
1857 SF_Exception.RaiseFatal(NOTAFOLDERERROR, &quot;FolderName&quot;, FolderName)
1858 GoTo Finally
1859 CatchFolder:
1860 SF_Exception.RaiseFatal(UNKNOWNFOLDERERROR, &quot;FolderName&quot;, FolderName)
1861 GoTo Finally
1862 End Function &apos; ScriptForge.SF_FileSystem.SubFolders
1864 REM =========================================================== PRIVATE FUNCTIONS
1866 REM -----------------------------------------------------------------------------
1867 Private Function _ConvertFromUrl(psFile) As String
1868 &apos;&apos;&apos; Execute the builtin ConvertFromUrl function only when relevant
1869 &apos;&apos;&apos; i.e. when FileNaming (how arguments and return values are provided) = &quot;SYS&quot;
1870 &apos;&apos;&apos; Called at the bottom of methods returning file names
1871 &apos;&apos;&apos; Remarks: psFile might contain wildcards
1872 &apos;&apos;&apos; Files from document&apos;s file systems are never converted
1874 Const cstQuestion = &quot;$QUESTION$&quot;, cstStar = &quot;$STAR$&quot; &apos; Special tokens to replace wildcards
1876 If SF_FileSystem.FileNaming = &quot;SYS&quot; And Not SF_FileSystem._IsDocFileSystem(psFile) Then
1877 _ConvertFromUrl = Replace(Replace( _
1878 ConvertFromUrl(Replace(Replace(psFile, &quot;?&quot;, cstQuestion), &quot;*&quot;, cstStar)) _
1879 , cstQuestion, &quot;?&quot;), cstStar, &quot;*&quot;)
1880 Else
1881 _ConvertFromUrl = psFile
1882 End If
1884 End Function &apos; ScriptForge.FileSystem._ConvertFromUrl
1886 REM -----------------------------------------------------------------------------
1887 Private Function _ConvertToUrl(psFile) As String
1888 &apos;&apos;&apos; Execute the builtin ConvertToUrl function only when relevant
1889 &apos;&apos;&apos; i.e. when FileNaming (how arguments and return values are provided) &lt;&gt; &quot;URL&quot;
1890 &apos;&apos;&apos; Called at the top of methods receiving file names as arguments
1891 &apos;&apos;&apos; Remarks: psFile might contain wildcards
1892 &apos;&apos;&apos; Files from document&apos;s file systems are never converted
1894 If SF_FileSystem.FileNaming = &quot;URL&quot; Or SF_FileSystem._IsDocFileSystem(psFile) Then
1895 _ConvertToUrl = psFile
1896 Else
1897 &apos; ConvertToUrl() encodes &quot;?&quot;
1898 _ConvertToUrl = Replace(ConvertToUrl(psFile), &quot;%3F&quot;, &quot;?&quot;)
1899 End If
1901 End Function &apos; ScriptForge.FileSystem._ConvertToUrl
1903 REM -----------------------------------------------------------------------------
1904 Private Function _CopyMove(psMethod As String _
1905 , psSource As String _
1906 , psDestination As String _
1907 , pbOverWrite As Boolean _
1908 ) As Boolean
1909 &apos;&apos;&apos; Checks the arguments and executes the given method
1910 &apos;&apos;&apos; Args:
1911 &apos;&apos;&apos; psMethod: CopyFile/CopyFolder or MoveFile/MoveFolder
1912 &apos;&apos;&apos; psSource: Either File/FolderName
1913 &apos;&apos;&apos; or NamePattern which can include wildcard characters, for one or more files/folders to be copied
1914 &apos;&apos;&apos; psDestination: FileName or FolderName for copy/move of a single file/folder
1915 &apos;&apos;&apos; Otherwise a destination FolderName. If it does not exist, it is created
1916 &apos;&apos;&apos; pbOverWrite: If True, files/folders may be overwritten
1917 &apos;&apos;&apos; Must be False for Move operations
1918 &apos;&apos;&apos; Next checks are done:
1919 &apos;&apos;&apos; With wildcards (multiple files/folders):
1920 &apos;&apos;&apos; - Parent folder of source must exist
1921 &apos;&apos;&apos; - Destination must not be a file
1922 &apos;&apos;&apos; - Parent folder of Destination must exist
1923 &apos;&apos;&apos; - If the Destination folder does not exist a new folder is created,
1924 &apos;&apos;&apos; - At least one file matches the wildcards expression
1925 &apos;&apos;&apos; - Destination files/folder must not exist if pbOverWrite = False
1926 &apos;&apos;&apos; - Destination files/folders must not have the read-only attribute set
1927 &apos;&apos;&apos; - Destination files must not be folders, destination folders must not be files
1928 &apos;&apos;&apos; Without wildcards (single file/folder):
1929 &apos;&apos;&apos; - Source file/folder must exist and be a file/folder
1930 &apos;&apos;&apos; - Parent folder of Destination must exist
1931 &apos;&apos;&apos; - Destination must not be an existing folder/file
1932 &apos;&apos;&apos; - Destination file/folder must not exist if pbOverWrite = False
1933 &apos;&apos;&apos; - Destination file must not have the read-only attribute set
1935 Dim bCopyMove As Boolean &apos; Return value
1936 Dim bCopy As Boolean &apos; True if Copy, False if Move
1937 Dim bFile As Boolean &apos; True if File, False if Folder
1938 Dim oSfa As Object &apos; com.sun.star.ucb.SimpleFileAccess
1939 Dim bWildCards As Boolean &apos; True if wildcards found in Source
1940 Dim bCreateFolder As Boolean &apos; True when the destination folder should be created
1941 Dim bDestExists As Boolean &apos; True if destination exists
1942 Dim sSourceUrl As String &apos; Alias for Source
1943 Dim sDestinationUrl As String &apos; Alias for Destination
1944 Dim sDestinationFile As String &apos; Destination FileName
1945 Dim sParentFolder As String &apos; Parent folder of Source
1946 Dim vFiles As Variant &apos; Array of candidates for copy/move
1947 Dim sFile As String &apos; Single file/folder
1948 Dim sName As String &apos; Name (last component) of file
1949 Dim i As Long
1951 &apos; Error handling left to calling routine
1952 bCopyMove = False
1953 bCopy = ( Left(psMethod, 4) = &quot;Copy&quot; )
1954 bFile = ( Right(psMethod, 4) = &quot;File&quot; )
1955 bWildCards = ( InStr(psSource, &quot;*&quot;) + InStr(psSource, &quot;?&quot;) + InStr(psSource, &quot;%3F&quot;) &gt; 0 ) &apos;ConvertToUrl() converts sometimes &quot;?&quot; to &quot;%3F&quot;
1956 bDestExists = False
1958 With SF_FileSystem
1960 Check:
1961 If bWildCards Then
1962 sParentFolder = .GetParentFolderName(psSource)
1963 If Not .FolderExists(sParentFolder) Then GoTo CatchNoMatch
1964 If .FileExists(psDestination) Then GoTo CatchFileNotFolder
1965 If Not .FolderExists(.GetParentFolderName(psDestination)) Then GoTo CatchDestFolderNotExists
1966 bCreateFolder = Not .FolderExists(psDestination)
1967 Else
1968 Select Case bFile
1969 Case True &apos; File
1970 If Not .FileExists(psSource) Then GoTo CatchFileNotExists
1971 If Not .FolderExists(.GetParentFolderName(psDestination)) Then GoTo CatchDestFolderNotExists
1972 If .FolderExists(psDestination) Then GoTo CatchFolderNotFile
1973 bDestExists = .FileExists(psDestination)
1974 If pbOverWrite = False And bDestExists = True Then GoTo CatchDestinationExists
1975 bCreateFolder = False
1976 Case False &apos; Folder
1977 If Not .FolderExists(psSource) Then GoTo CatchSourceFolderNotExists
1978 If Not .FolderExists(.GetParentFolderName(psDestination)) Then GoTo CatchDestFolderNotExists
1979 If .FileExists(psDestination) Then GoTo CatchFileNotFolder
1980 bDestExists = .FolderExists(psDestination)
1981 If pbOverWrite = False And bDestExists Then GoTo CatchDestinationExists
1982 bCreateFolder = Not bDestExists
1983 End Select
1984 End If
1986 Try:
1987 Set oSfa = SF_Utils._GetUnoService(&quot;FileAccess&quot;)
1988 If bWildCards Then
1989 If bFile Then vFiles = .Files(sParentFolder, .GetName(psSource)) Else vFiles = .SubFolders(sParentFolder, .GetName(psSource))
1990 If UBound(vFiles) &lt; 0 Then GoTo CatchNoMatch
1991 &apos; Go through the candidates
1992 If bCreateFolder Then .CreateFolder(psDestination)
1993 For i = 0 To UBound(vFiles)
1994 sFile = vFiles(i)
1995 sDestinationFile = .BuildPath(psDestination, .GetName(sFile))
1996 If bFile Then bDestExists = .FileExists(sDestinationFile) Else bDestExists = .FolderExists(sDestinationFile)
1997 If pbOverWrite = False Then
1998 If bDestExists Then GoTo CatchDestinationExists
1999 If .FolderExists(sDestinationFile) Then GoTo CatchDestinationExists
2000 End If
2001 sSourceUrl = ._ConvertToUrl(sFile)
2002 sDestinationUrl = ._ConvertToUrl(sDestinationFile)
2003 If bDestExists Then
2004 If oSfa.isReadOnly(sDestinationUrl) Then GoTo CatchDestinationReadOnly
2005 End If
2006 Select Case bCopy
2007 Case True : oSfa.copy(sSourceUrl, sDestinationUrl)
2008 Case False : oSfa.move(sSourceUrl, sDestinationUrl)
2009 End Select
2010 Next i
2011 Else
2012 sSourceUrl = ._ConvertToUrl(psSource)
2013 sDestinationUrl = ._ConvertToUrl(psDestination)
2014 If bDestExists Then
2015 If oSfa.isReadOnly(sDestinationUrl) Then GoTo CatchDestinationReadOnly
2016 End If
2017 If bCreateFolder Then .CreateFolder(psDestination)
2018 Select Case bCopy
2019 Case True : oSfa.copy(sSourceUrl, sDestinationUrl)
2020 Case False : oSfa.move(sSourceUrl, sDestinationUrl)
2021 End Select
2022 End If
2024 End With
2026 bCopyMove = True
2028 Finally:
2029 _CopyMove = bCopyMove
2030 Exit Function
2031 CatchFileNotExists:
2032 SF_Exception.RaiseFatal(UNKNOWNFILEERROR, &quot;Source&quot;, psSource)
2033 GoTo Finally
2034 CatchSourceFolderNotExists:
2035 SF_Exception.RaiseFatal(UNKNOWNFOLDERERROR, &quot;Source&quot;, psSource)
2036 GoTo Finally
2037 CatchDestFolderNotExists:
2038 SF_Exception.RaiseFatal(UNKNOWNFOLDERERROR, &quot;Destination&quot;, psDestination)
2039 GoTo Finally
2040 CatchFolderNotFile:
2041 SF_Exception.RaiseFatal(NOTAFILEERROR, &quot;Destination&quot;, psDestination)
2042 GoTo Finally
2043 CatchDestinationExists:
2044 SF_Exception.RaiseFatal(OVERWRITEERROR, &quot;Destination&quot;, psDestination)
2045 GoTo Finally
2046 CatchNoMatch:
2047 SF_Exception.RaiseFatal(NOFILEMATCHERROR, &quot;Source&quot;, psSource)
2048 GoTo Finally
2049 CatchFileNotFolder:
2050 SF_Exception.RaiseFatal(NOTAFOLDERERROR, &quot;Destination&quot;, psDestination)
2051 GoTo Finally
2052 CatchDestinationReadOnly:
2053 SF_Exception.RaiseFatal(READONLYERROR, &quot;Destination&quot;, Iif(bWildCards, sDestinationFile, psDestination))
2054 GoTo Finally
2055 End Function &apos; ScriptForge.SF_FileSystem._CopyMove
2057 REM -----------------------------------------------------------------------------
2058 Public Function _CountTextLines(ByVal psFileName As String _
2059 , Optional ByVal pbIncludeBlanks As Boolean _
2060 ) As Long
2061 &apos;&apos;&apos; Convenient function to count the number of lines in a textfile
2062 &apos;&apos;&apos; Args:
2063 &apos;&apos;&apos; psFileName: the file in FileNaming notation
2064 &apos;&apos;&apos; pbIncludeBlanks: if True (default), zero-length lines are included
2065 &apos;&apos;&apos; Returns:
2066 &apos;&apos;&apos; The number of lines, f.i. to ease array sizing. -1 if file reading error
2068 Dim lLines As Long &apos; Return value
2069 Dim oFile As Object &apos; File handler
2070 Dim sLine As String &apos; The last line read
2072 Try:
2073 lLines = 0
2074 If IsMissing(pbIncludeBlanks) Then pbIncludeBlanks = True
2075 Set oFile = SF_FileSystem.OpenTextFile(psFileName, ForReading)
2076 With oFile
2077 If Not IsNull(oFile) Then
2078 Do While Not .AtEndOfStream
2079 sLine = .ReadLine()
2080 lLines = lLines + Iif(Len(sLine) &gt; 0 Or pbIncludeBlanks, 1, 0)
2081 Loop
2082 End If
2083 .CloseFile()
2084 Set oFile = .Dispose()
2085 End With
2087 Finally:
2088 _CountTextLines = lLines
2089 Exit Function
2090 End Function &apos; ScriptForge.SF_FileSystem._CountTextLines
2092 REM -----------------------------------------------------------------------------
2093 Private Function _Delete(psMethod As String _
2094 , psFile As String _
2095 ) As Boolean
2096 &apos;&apos;&apos; Checks the argument and executes the given psMethod
2097 &apos;&apos;&apos; Args:
2098 &apos;&apos;&apos; psMethod: CopyFile/CopyFolder or MoveFile/MoveFolder
2099 &apos;&apos;&apos; psFile: Either File/FolderName
2100 &apos;&apos;&apos; or NamePattern which can include wildcard characters, for one or more files/folders to be deleted
2101 &apos;&apos;&apos; Next checks are done:
2102 &apos;&apos;&apos; With wildcards (multiple files/folders):
2103 &apos;&apos;&apos; - Parent folder of File must exist
2104 &apos;&apos;&apos; - At least one file matches the wildcards expression
2105 &apos;&apos;&apos; - Files or folders to delete must not have the read-only attribute set
2106 &apos;&apos;&apos; Without wildcards (single file/folder):
2107 &apos;&apos;&apos; - File/folder must exist and be a file/folder
2108 &apos;&apos;&apos; - A file or folder to delete must not have the read-only attribute set
2110 Dim bDelete As Boolean &apos; Return value
2111 Dim bFile As Boolean &apos; True if File, False if Folder
2112 Dim oSfa As Object &apos; com.sun.star.ucb.SimpleFileAccess
2113 Dim bWildCards As Boolean &apos; True if wildcards found in File
2114 Dim sFileUrl As String &apos; Alias for File
2115 Dim sParentFolder As String &apos; Parent folder of File
2116 Dim vFiles As Variant &apos; Array of candidates for deletion
2117 Dim sFile As String &apos; Single file/folder
2118 Dim sName As String &apos; Name (last component) of file
2119 Dim i As Long
2121 &apos; Error handling left to calling routine
2122 bDelete = False
2123 bFile = ( Right(psMethod, 4) = &quot;File&quot; )
2124 bWildCards = ( InStr(psFile, &quot;*&quot;) + InStr(psFile, &quot;?&quot;) + InStr(psFile, &quot;%3F&quot;) &gt; 0 ) &apos;ConvertToUrl() converts sometimes &quot;?&quot; to &quot;%3F&quot;
2126 With SF_FileSystem
2128 Check:
2129 If bWildCards Then
2130 sParentFolder = .GetParentFolderName(psFile)
2131 If Not .FolderExists(sParentFolder) Then GoTo CatchNoMatch
2132 Else
2133 Select Case bFile
2134 Case True &apos; File
2135 If .FolderExists(psFile) Then GoTo CatchFolderNotFile
2136 If Not .FileExists(psFile) Then GoTo CatchFileNotExists
2137 Case False &apos; Folder
2138 If .FileExists(psFile) Then GoTo CatchFileNotFolder
2139 If Not .FolderExists(psFile) Then GoTo CatchFolderNotExists
2140 End Select
2141 End If
2143 Try:
2144 Set oSfa = SF_Utils._GetUnoService(&quot;FileAccess&quot;)
2145 If bWildCards Then
2146 If bFile Then vFiles = .Files(sParentFolder) Else vFiles = .SubFolders(sParentFolder)
2147 &apos; Select candidates
2148 For i = 0 To UBound(vFiles)
2149 If Not SF_String.IsLike(.GetName(vFiles(i)), .GetName(psFile)) Then vFiles(i) = &quot;&quot;
2150 Next i
2151 vFiles = SF_Array.TrimArray(vFiles)
2152 If UBound(vFiles) &lt; 0 Then GoTo CatchNoMatch
2153 &apos; Go through the candidates
2154 For i = 0 To UBound(vFiles)
2155 sFile = vFiles(i)
2156 sFileUrl = ._ConvertToUrl(sFile)
2157 If oSfa.isReadOnly(sFileUrl) Then GoTo CatchReadOnly
2158 oSfa.kill(sFileUrl)
2159 Next i
2160 Else
2161 sFileUrl = ._ConvertToUrl(psFile)
2162 If oSfa.isReadOnly(sFileUrl) Then GoTo CatchReadOnly
2163 oSfa.kill(sFileUrl)
2164 End If
2166 End With
2168 bDelete = True
2170 Finally:
2171 _Delete = bDelete
2172 Exit Function
2173 CatchFolderNotExists:
2174 SF_Exception.RaiseFatal(UNKNOWNFOLDERERROR, &quot;FolderName&quot;, psFile)
2175 GoTo Finally
2176 CatchFileNotExists:
2177 SF_Exception.RaiseFatal(UNKNOWNFILEERROR, &quot;FileName&quot;, psFile)
2178 GoTo Finally
2179 CatchFolderNotFile:
2180 SF_Exception.RaiseFatal(NOTAFILEERROR, &quot;FileName&quot;, psFile)
2181 GoTo Finally
2182 CatchNoMatch:
2183 SF_Exception.RaiseFatal(NOFILEMATCHERROR, Iif(bFile, &quot;FileName&quot;, &quot;FolderName&quot;), psFile)
2184 GoTo Finally
2185 CatchFileNotFolder:
2186 SF_Exception.RaiseFatal(NOTAFOLDERERROR, &quot;FolderName&quot;, psFile)
2187 GoTo Finally
2188 CatchReadOnly:
2189 SF_Exception.RaiseFatal(READONLYERROR, Iif(bFile, &quot;FileName&quot;, &quot;FolderName&quot;), Iif(bWildCards, sFile, psFile))
2190 GoTo Finally
2191 End Function &apos; ScriptForge.SF_FileSystem._Delete
2193 REM -----------------------------------------------------------------------------
2194 Private Function _GetConfigFolder(ByVal psFolder As String) As String
2195 &apos;&apos;&apos; Returns one of next configuration folders: see https://api.libreoffice.org/docs/idl/ref/servicecom_1_1sun_1_1star_1_1util_1_1PathSubstitution.html
2196 &apos;&apos;&apos; inst =&gt; Installation path of LibreOffice
2197 &apos;&apos;&apos; prog =&gt; Program path of LibreOffice
2198 &apos;&apos;&apos; user =&gt; The user installation/config directory
2199 &apos;&apos;&apos; work =&gt; The work directory of the user. Under Windows this would be the &quot;MyDocuments&quot; subdirectory. Under Unix this would be the home-directory
2200 &apos;&apos;&apos; home =&gt; The home directory of the user. Under Unix this would be the home- directory.
2201 &apos;&apos;&apos; Under Windows this would be the CSIDL_PERSONAL directory, for example &quot;Documents and Settings\&lt;username&gt;\Documents&quot;
2202 &apos;&apos;&apos; temp =&gt; The current temporary directory
2204 Dim oSubst As Object &apos; com.sun.star.util.PathSubstitution
2205 Dim sConfig As String &apos; Return value
2207 sConfig = &quot;&quot;
2208 Set oSubst = SF_Utils._GetUNOService(&quot;PathSubstitution&quot;)
2209 If Not IsNull(oSubst) Then sConfig = oSubst.getSubstituteVariableValue(&quot;$(&quot; &amp; psFolder &amp; &quot;)&quot;) &amp; &quot;/&quot;
2211 _GetConfigFolder = SF_FileSystem._ConvertFromUrl(sConfig)
2213 End Function &apos; ScriptForge.FileSystem._GetConfigFolder
2215 REM -----------------------------------------------------------------------------
2216 Public Function _IsDocFileSystem(psFile As String) As Boolean
2217 &apos;&apos;&apos; Returns True when the argument designates a document&apos;s internal file system
2219 _IsDocFileSystem = SF_String.StartsWith(psFile, DOCFILESYSTEM, CaseSensitive := True)
2221 End Function &apos; ScriptForge.SF_FileSystem._IsDocFileSystem
2223 REM -----------------------------------------------------------------------------
2224 Private Sub _ScanFolder(ByVal piTarget As Integer _
2225 , ByRef psItemsColl As String _
2226 , ByVal psFolderName As String _
2227 , ByRef poSfa As Object _
2228 , ByVal psFilter As String _
2229 , ByVal pbIncludeSubFolders As Boolean _
2231 &apos;&apos;&apos; Scan a folder and, when requested, its subfolders recursively.
2232 &apos;&apos;&apos; The psItemsColl in-out argument concatenates, depending on the target,
2233 &apos;&apos;&apos; either all files or all folders found.
2234 &apos;&apos;&apos; The Sub calls itself recursively when relevant.
2235 &apos;&apos;&apos; Args:
2236 &apos;&apos;&apos; piTarget: 1 when caller routine = Files(), 2 when caller routine = SubFolders()
2237 &apos;&apos;&apos; It determines the type of items to collect: files or folders
2238 &apos;&apos;&apos; psItemsColl: the current and future list of folders or files (FileNaming format) separated with cstSEPARATOR
2239 &apos;&apos;&apos; psFolderName: the folder to scan (FileNaming format)
2240 &apos;&apos;&apos; poSfa: com.sun.star.ucb.SimpleFileAccess
2241 &apos;&apos;&apos; psFilter: contains wildcards (&quot;?&quot; and &quot;*&quot;) to limit the list to the relevant folders or files.
2242 &apos;&apos;&apos; Zero-length string when not applicable.
2243 &apos;&apos;&apos; pbIncludeSubfolders: when True, subfolders are explored too.
2245 Dim vSubFolders As Variant &apos; Array of subfolders 1st level in URL notation
2246 Dim vFiles As Variant &apos; Array of files present in psFolderName in FileNaming notation
2247 Dim lFiles As Long &apos; Number of files found passing the filter
2248 Dim sFolderName As String &apos; URL alias for psFolderName
2249 Dim sItem As String &apos; Single folder or single file in FileNaming notation
2250 Dim sItemName As String &apos; Base name of sItem
2251 Dim bFolder As Boolean &apos; When True, the considered string points to a folder, not a file
2252 Dim bFilter As Boolean &apos; When True, no filter or the filter is passed
2253 Dim i As Long
2255 Check:
2256 On Local Error Goto catch
2258 Try:
2259 With poSfa
2261 &apos; Get SubFolders, initialize files list
2262 sFolderName = SF_FileSystem._ConvertToUrl(psFolderName)
2263 vSubFolders = .getFolderContents(sFolderName, True)
2264 If UBound(vSubFolders) &lt; 0 Then Exit Sub
2265 vFiles = Array()
2266 If piTarget = cstFiles Then
2267 lFiles = 0
2268 ReDim vFiles(0 To UBound(vSubFolders))
2269 End If
2271 &apos; List includes files: remove them or adjust notations of folders
2272 &apos; When piTarget = cstFiles, the list of files is stored in the vFiles() array
2273 For i = 0 To UBound(vSubFolders)
2274 sItem = SF_FileSystem._ConvertFromUrl(vSubFolders(i))
2275 bFolder = .isFolder(vSubFolders(i))
2276 Select Case piTarget
2277 Case cstFiles
2278 If bFolder Then
2279 vSubFolders(i) = sItem &amp; &quot;/&quot;
2280 Else
2281 &apos; Build list of files passing the filter
2282 bFilter = ( Len(psFilter) = 0 )
2283 If Not bFilter Then
2284 sItemName = SF_FileSystem.GetName(sItem)
2285 bFilter = SF_String.IsLike(sItemName, psFilter)
2286 End If
2287 If bFilter Then &apos; Copy files from folders + files list
2288 vFiles(lFiles) = sItem
2289 lFiles = lFiles + 1
2290 End If
2291 vSubFolders(i) = &quot;&quot; &apos; Keep folders only
2292 End If
2293 Case cstFolders
2294 If bFolder Then vSubFolders(i) = sItem &amp; &quot;/&quot; Else vSubFolders(i) = &quot;&quot;
2295 &apos; Reduce list to those passing the filter
2296 If Len(psFilter) &gt; 0 And Len(vSubFolders(i)) &gt; 0 Then
2297 sItemName = SF_FileSystem.GetName(sItem)
2298 If Not SF_String.IsLike(sItemName, psFilter) Then vSubFolders(i) = &quot;&quot;
2299 End If
2300 End Select
2301 Next i
2302 vSubFolders = SF_Array.TrimArray(vSubFolders)
2304 &apos; Store the list of either files or subfolders in the global collection
2305 Select Case piTarget
2306 Case cstFiles
2307 If lFiles &gt; 0 Then
2308 ReDim Preserve vFiles(0 To lFiles - 1)
2309 psItemsColl = psItemsColl &amp; cstSEPARATOR &amp; Join(vFiles, cstSEPARATOR)
2310 End If
2311 Case cstFolders
2312 If UBound(vSubFolders) &gt;= 0 Then psItemsColl = psItemsColl &amp; cstSEPARATOR &amp; Join(vSubFolders, cstSEPARATOR)
2313 End Select
2315 &apos; Scan each subfolder when relevant
2316 If pbIncludeSubfolders Then
2317 For i = 0 To UBound(vSubFolders)
2318 _ScanFolder(piTarget, psItemsColl, vSubFolders(i), poSfa, psFilter, True)
2319 Next i
2320 End If
2322 End With
2324 Finally:
2325 Exit Sub
2326 Catch:
2327 SF_Exception.Clear()
2328 psItemsColl = &quot;&quot;
2329 GoTo Finally
2330 End Sub &apos; ScriptForge.SF_FileSystem._ScanFolder
2332 REM -----------------------------------------------------------------------------
2333 Public Function _ParseUrl(psUrl As String) As Object
2334 &apos;&apos;&apos; Returns a com.sun.star.util.URL structure based on the argument
2336 Dim oParse As Object &apos; com.sun.star.util.URLTransformer
2337 Dim bParsed As Boolean &apos; True if parsing is successful
2338 Dim oUrl As New com.sun.star.util.URL &apos; Return value
2340 oUrl.Complete = psUrl
2341 Set oParse = SF_Utils._GetUNOService(&quot;URLTransformer&quot;)
2342 bParsed = oParse.parseStrict(oUrl, &quot;&quot;)
2343 If bParsed Then oUrl.Path = ConvertToUrl(oUrl.Path)
2345 Set _ParseUrl = oUrl
2347 End Function &apos; ScriptForge.SF_FileSystem._ParseUrl
2349 REM -----------------------------------------------------------------------------
2350 Public Function _SFInstallFolder() As String
2351 &apos;&apos;&apos; Returns the installation folder of the ScriptForge library
2352 &apos;&apos;&apos; Either:
2353 &apos;&apos;&apos; - The library is present in [My Macros &amp; Dialogs]
2354 &apos;&apos;&apos; ($config)/basic/ScriptForge
2355 &apos;&apos;&apos; - The library is present in [LibreOffice Macros &amp; Dialogs]
2356 &apos;&apos;&apos; ($install)/share/basic/ScriptForge
2358 Dim sFolder As String &apos; Folder
2360 _SFInstallFolder = &quot;&quot;
2362 sFolder = BuildPath(ConfigFolder, &quot;basic/ScriptForge&quot;)
2363 If Not FolderExists(sFolder) Then
2364 sFolder = BuildPath(InstallFolder, &quot;share/basic/ScriptForge&quot;)
2365 If Not FolderExists(sFolder) Then Exit Function
2366 End If
2368 _SFInstallFolder = _ConvertFromUrl(sFolder)
2370 End Function &apos; ScriptForge.SF_FileSystem._SFInstallFolder
2372 REM ============================================ END OF SCRIPTFORGE.SF_FileSystem
2373 </script:module>