calc: on editing invalidation of view with different zoom is wrong
[LibreOffice.git] / wizards / source / scriptforge / SF_FileSystem.xba
blobd81465dbff13cf501700392a9f55ba0ed684ef1b
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;URL&quot; (default) 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; Service invocation example:
41 &apos;&apos;&apos; Dim FSO As Variant
42 &apos;&apos;&apos; Set FSO = CreateScriptService(&quot;FileSystem&quot;)
43 &apos;&apos;&apos;
44 &apos;&apos;&apos; Detailed user documentation:
45 &apos;&apos;&apos; https://help.libreoffice.org/latest/en-US/text/sbasic/shared/03/sf_filesystem.html?DbPAR=BASIC
46 &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;
48 REM ================================================================== EXCEPTIONS
50 Const UNKNOWNFILEERROR = &quot;UNKNOWNFILEERROR&quot; &apos; Source file does not exist
51 Const UNKNOWNFOLDERERROR = &quot;UNKNOWNFOLDERERROR&quot; &apos; Source folder or Destination folder does not exist
52 Const NOTAFILEERROR = &quot;NOTAFILEERROR&quot; &apos; Destination is a folder, not a file
53 Const NOTAFOLDERERROR = &quot;NOTAFOLDERERROR&quot; &apos; Destination is a file, not a folder
54 Const OVERWRITEERROR = &quot;OVERWRITEERROR&quot; &apos; Destination can not be overwritten
55 Const READONLYERROR = &quot;READONLYERROR&quot; &apos; Destination has its read-only attribute set
56 Const NOFILEMATCHERROR = &quot;NOFILEMATCHFOUND&quot; &apos; No file matches Source containing wildcards
57 Const FOLDERCREATIONERROR = &quot;FOLDERCREATIONERROR&quot; &apos; FolderName is an existing folder or file
59 REM ============================================================ MODULE CONSTANTS
61 &apos;&apos;&apos; TextStream open modes
62 Const cstForReading = 1
63 Const cstForWriting = 2
64 Const cstForAppending = 8
66 REM ===================================================== CONSTRUCTOR/DESTRUCTOR
68 REM -----------------------------------------------------------------------------
69 Public Function Dispose() As Variant
70 Set Dispose = Nothing
71 End Function &apos; ScriptForge.SF_FileSystem Explicit destructor
73 REM ================================================================== PROPERTIES
75 REM -----------------------------------------------------------------------------
76 Property Get ConfigFolder() As String
77 &apos;&apos;&apos; Return the configuration folder of LibreOffice
79 Const cstThisSub = &quot;FileSystem.getConfigFolder&quot;
81 SF_Utils._EnterFunction(cstThisSub)
82 ConfigFolder = SF_FileSystem._GetConfigFolder(&quot;user&quot;)
83 SF_Utils._ExitFunction(cstThisSub)
85 End Property &apos; ScriptForge.SF_FileSystem.ConfigFolder
87 REM -----------------------------------------------------------------------------
88 Property Get ExtensionsFolder() As String
89 &apos;&apos;&apos; Return the folder containing the extensions installed for the current user
91 Dim oMacro As Object &apos; /singletons/com.sun.star.util.theMacroExpander
92 Const cstThisSub = &quot;FileSystem.getExtensionsFolder&quot;
94 SF_Utils._EnterFunction(cstThisSub)
95 Set oMacro = SF_Utils._GetUNOService(&quot;MacroExpander&quot;)
96 ExtensionsFolder = SF_FileSystem._ConvertFromUrl(oMacro.ExpandMacros(&quot;$UNO_USER_PACKAGES_CACHE&quot;) &amp; &quot;/&quot;)
97 SF_Utils._ExitFunction(cstThisSub)
99 End Property &apos; ScriptForge.SF_FileSystem.ExtensionsFolder
101 REM -----------------------------------------------------------------------------
102 Property Get FileNaming() As Variant
103 &apos;&apos;&apos; Return the current files and folder notation, either &quot;ANY&quot;, &quot;URL&quot; or &quot;SYS&quot;
104 &apos;&apos;&apos; &quot;ANY&quot;: methods receive either URL or native file names, but always return URL file names
105 &apos;&apos;&apos; &quot;URL&quot;: methods expect URL arguments and return URL strings (when relevant)
106 &apos;&apos;&apos; &quot;SYS&quot;: idem but operating system notation
108 Const cstThisSub = &quot;FileSystem.getFileNaming&quot;
109 SF_Utils._EnterFunction(cstThisSub)
110 FileNaming = _SF_.FileSystemNaming
111 SF_Utils._ExitFunction(cstThisSub)
113 End Property &apos; ScriptForge.SF_FileSystem.FileNaming (get)
115 REM -----------------------------------------------------------------------------
116 Property Let FileNaming(ByVal pvNotation As Variant)
117 &apos;&apos;&apos; Set the files and folders notation: &quot;ANY&quot;, &quot;URL&quot; or &quot;SYS&quot;
119 Const cstThisSub = &quot;FileSystem.setFileNaming&quot;
120 SF_Utils._EnterFunction(cstThisSub)
121 If VarType(pvNotation) = V_STRING Then
122 Select Case UCase(pvNotation)
123 Case &quot;ANY&quot;, &quot;URL&quot;, &quot;SYS&quot; : _SF_.FileSystemNaming = UCase(pvNotation)
124 Case Else &apos; Unchanged
125 End Select
126 End If
127 SF_Utils._ExitFunction(cstThisSub)
129 End Property &apos; ScriptForge.SF_FileSystem.FileNaming (let)
131 REM -----------------------------------------------------------------------------
132 Property Get ForAppending As Integer
133 &apos;&apos;&apos; Convenient constant (see documentation)
134 ForAppending = cstForAppending
135 End Property &apos; ScriptForge.SF_FileSystem.ForAppending
137 REM -----------------------------------------------------------------------------
138 Property Get ForReading As Integer
139 &apos;&apos;&apos; Convenient constant (see documentation)
140 ForReading = cstForReading
141 End Property &apos; ScriptForge.SF_FileSystem.ForReading
143 REM -----------------------------------------------------------------------------
144 Property Get ForWriting As Integer
145 &apos;&apos;&apos; Convenient constant (see documentation)
146 ForWriting = cstForWriting
147 End Property &apos; ScriptForge.SF_FileSystem.ForWriting
149 REM -----------------------------------------------------------------------------
150 Property Get HomeFolder() As String
151 &apos;&apos;&apos; Return the user home folder
153 Const cstThisSub = &quot;FileSystem.getHomeFolder&quot;
155 SF_Utils._EnterFunction(cstThisSub)
156 HomeFolder = SF_FileSystem._GetConfigFolder(&quot;home&quot;)
157 SF_Utils._ExitFunction(cstThisSub)
159 End Property &apos; ScriptForge.SF_FileSystem.HomeFolder
161 REM -----------------------------------------------------------------------------
162 Property Get InstallFolder() As String
163 &apos;&apos;&apos; Return the installation folder of LibreOffice
165 Const cstThisSub = &quot;FileSystem.getInstallFolder&quot;
167 SF_Utils._EnterFunction(cstThisSub)
168 InstallFolder = SF_FileSystem._GetConfigFolder(&quot;inst&quot;)
169 SF_Utils._ExitFunction(cstThisSub)
171 End Property &apos; ScriptForge.SF_FileSystem.InstallFolder
173 REM -----------------------------------------------------------------------------
174 Property Get ObjectType As String
175 &apos;&apos;&apos; Only to enable object representation
176 ObjectType = &quot;SF_FileSystem&quot;
177 End Property &apos; ScriptForge.SF_FileSystem.ObjectType
179 REM -----------------------------------------------------------------------------
180 Property Get ServiceName As String
181 &apos;&apos;&apos; Internal use
182 ServiceName = &quot;ScriptForge.FileSystem&quot;
183 End Property &apos; ScriptForge.SF_FileSystem.ServiceName
185 REM -----------------------------------------------------------------------------
186 Property Get TemplatesFolder() As String
187 &apos;&apos;&apos; Return the folder defined in the LibreOffice paths options as intended for templates files
189 Dim sPath As String &apos; Template property of com.sun.star.util.PathSettings
190 Const cstThisSub = &quot;FileSystem.getTemplatesFolder&quot;
192 SF_Utils._EnterFunction(cstThisSub)
193 sPath = SF_Utils._GetUNOService(&quot;PathSettings&quot;).Template
194 TemplatesFolder = SF_FileSystem._ConvertFromUrl(Split(sPath, &quot;;&quot;)(0) &amp; &quot;/&quot;)
195 SF_Utils._ExitFunction(cstThisSub)
197 End Property &apos; ScriptForge.SF_FileSystem.TemplatesFolder
199 REM -----------------------------------------------------------------------------
200 Property Get TemporaryFolder() As String
201 &apos;&apos;&apos; Return the folder defined in the LibreOffice paths options as intended for temporary files
203 Const cstThisSub = &quot;FileSystem.getTemporaryFolder&quot;
205 SF_Utils._EnterFunction(cstThisSub)
206 TemporaryFolder = SF_FileSystem._GetConfigFolder(&quot;temp&quot;)
207 SF_Utils._ExitFunction(cstThisSub)
209 End Property &apos; ScriptForge.SF_FileSystem.TemporaryFolder
211 REM -----------------------------------------------------------------------------
212 Property Get UserTemplatesFolder() As String
213 &apos;&apos;&apos; Return the folder defined in the LibreOffice paths options as intended for User templates files
215 Dim sPath As String &apos; Template_writable property of com.sun.star.util.PathSettings
216 Const cstThisSub = &quot;FileSystem.getUserTemplatesFolder&quot;
218 SF_Utils._EnterFunction(cstThisSub)
219 sPath = SF_Utils._GetUNOService(&quot;PathSettings&quot;).Template_writable
220 UserTemplatesFolder = SF_FileSystem._ConvertFromUrl(sPath &amp; &quot;/&quot;)
221 SF_Utils._ExitFunction(cstThisSub)
223 End Property &apos; ScriptForge.SF_FileSystem.UserTemplatesFolder
225 REM ===================================================================== METHODS
227 REM -----------------------------------------------------------------------------
228 Public Function BuildPath(Optional ByVal FolderName As Variant _
229 , Optional ByVal Name As Variant _
230 ) As String
231 &apos;&apos;&apos; Combines a folder path and the name of a file and returns the combination with a valid path separator
232 &apos;&apos;&apos; Inserts an additional path separator between the foldername and the name, only if necessary
233 &apos;&apos;&apos; Args:
234 &apos;&apos;&apos; FolderName: Path with which Name is combined. Path need not specify an existing folder
235 &apos;&apos;&apos; Name: To be appended to the existing path.
236 &apos;&apos;&apos; Returns:
237 &apos;&apos;&apos; The path concatenated with the file name after insertion of a path separator, if necessary
238 &apos;&apos;&apos; Example:
239 &apos;&apos;&apos; Dim a As String
240 &apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
241 &apos;&apos;&apos; a = FSO.BuildPath(&quot;C:\Windows&quot;, &quot;Notepad.exe&quot;) returns C:\Windows\Notepad.exe
243 Dim sBuild As String &apos; Return value
244 Dim sFile As String &apos; Alias for Name
245 Const cstFileProtocol = &quot;file:///&quot;
246 Const cstThisSub = &quot;FileSystem.BuildPath&quot;
247 Const cstSubArgs = &quot;FolderName, Name&quot;
249 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
250 sBuild = &quot;&quot;
252 Check:
253 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
254 If Not SF_Utils._ValidateFile(FolderName, &quot;FolderName&quot;) Then GoTo Finally
255 If Not SF_Utils._Validate(Name, &quot;Name&quot;, V_STRING) Then GoTo Finally
256 End If
257 FolderName = SF_FileSystem._ConvertToUrl(FolderName)
259 Try:
260 &apos; Add separator if necessary. FolderName is now in URL notation
261 If Len(FolderName) &gt; 0 Then
262 If Right(FolderName, 1) &lt;&gt; &quot;/&quot; Then sBuild = FolderName &amp; &quot;/&quot; Else sBuild = FolderName
263 Else
264 sBuild = cstFileProtocol
265 End If
266 &apos; Encode the file name
267 sFile = ConvertToUrl(Name)
268 &apos; Some file names produce http://file.name.suffix/
269 If Left(sFile, 7) = &quot;http://&quot; Then sFile = cstFileProtocol &amp; Mid(sFile, 8, Len(sFile) - 8)
270 &apos; Combine both parts
271 If Left(sFile, Len(cstFileProtocol)) = cstFileProtocol Then sBuild = sBuild &amp; Mid(sFile, Len(cstFileProtocol) + 1) Else sBuild = sBuild &amp; sFile
273 Finally:
274 BuildPath = SF_FileSystem._ConvertFromUrl(sBuild)
275 SF_Utils._ExitFunction(cstThisSub)
276 Exit Function
277 Catch:
278 GoTo Finally
279 End Function &apos; ScriptForge.SF_FileSystem.BuildPath
281 REM -----------------------------------------------------------------------------
282 Public Function CompareFiles(Optional ByVal FileName1 As Variant _
283 , Optional ByVal FileName2 As Variant _
284 , Optional ByVal CompareContents As Variant _
286 &apos;&apos;&apos; Compare 2 files and return True if they seem identical
287 &apos;&apos;&apos; The comparison may be based on the file attributes, like modification time,
288 &apos;&apos;&apos; or on their contents.
289 &apos;&apos;&apos; Args:
290 &apos;&apos;&apos; FileName1: The 1st file to compare
291 &apos;&apos;&apos; FileName2: The 2nd file to compare
292 &apos;&apos;&apos; CompareContents: When True, the contents of the files are compared. Default = False
293 &apos;&apos;&apos; Returns:
294 &apos;&apos;&apos; True when the files seem identical
295 &apos;&apos;&apos; Exceptions:
296 &apos;&apos;&apos; UNKNOWNFILEERROR One of the files does not exist
297 &apos;&apos;&apos; Example:
298 &apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
299 &apos;&apos;&apos; MsgBox FSO.CompareFiles(&quot;C:\myFile1.txt&quot;, &quot;C:\myFile2.txt&quot;, CompareContents := True)
301 Dim bCompare As Boolean &apos; Return value
302 Dim sFile As String &apos; Alias of FileName1 and 2
303 Dim iFile As Integer &apos; 1 or 2
304 Const cstPyHelper = &quot;$&quot; &amp; &quot;_SF_FileSystem__CompareFiles&quot;
306 Const cstThisSub = &quot;FileSystem.CompareFiles&quot;
307 Const cstSubArgs = &quot;FileName1, FileName2, [CompareContents=False]&quot;
309 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
310 bCompare = False
312 Check:
313 If IsMissing(CompareContents) Or IsEmpty(CompareContents) Then CompareContents = False
314 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
315 If Not SF_Utils._ValidateFile(FileName1, &quot;FileName1&quot;, False) Then GoTo Finally
316 If Not SF_Utils._ValidateFile(FileName2, &quot;FileName2&quot;, False) Then GoTo Finally
317 If Not SF_Utils._Validate(CompareContents, &quot;CompareContents&quot;, V_BOOLEAN) Then GoTo Finally
318 End If
319 &apos; Do the files exist ? Otherwise raise error
320 sFile = FileName1 : iFile = 1
321 If Not SF_FileSystem.FileExists(sFile) Then GoTo CatchNotExists
322 sFile = FileName2 : iFile = 2
323 If Not SF_FileSystem.FileExists(sFile) Then GoTo CatchNotExists
325 Try:
326 With ScriptForge.SF_Session
327 bCompare = .ExecutePythonScript(.SCRIPTISSHARED, _SF_.PythonHelper &amp; cstPyHelper _
328 , _ConvertFromUrl(FileName1) _
329 , _ConvertFromUrl(FileName2) _
330 , CompareContents)
331 End With
333 Finally:
334 CompareFiles = bCompare
335 SF_Utils._ExitFunction(cstThisSub)
336 Exit Function
337 Catch:
338 GoTo Finally
339 CatchNotExists:
340 SF_Exception.RaiseFatal(UNKNOWNFILEERROR, &quot;FileName&quot; &amp; iFile, sFile)
341 GoTo Finally
342 End Function &apos; ScriptForge.SF_FileSystem.CompareFiles
344 REM -----------------------------------------------------------------------------
345 Public Function CopyFile(Optional ByVal Source As Variant _
346 , Optional ByVal Destination As Variant _
347 , Optional ByVal Overwrite As Variant _
348 ) As Boolean
349 &apos;&apos;&apos; Copies one or more files from one location to another
350 &apos;&apos;&apos; Args:
351 &apos;&apos;&apos; Source: FileName or NamePattern which can include wildcard characters, for one or more files to be copied
352 &apos;&apos;&apos; Destination: FileName where the single Source file is to be copied
353 &apos;&apos;&apos; or FolderName where the multiple files from Source are to be copied
354 &apos;&apos;&apos; If FolderName does not exist, it is created
355 &apos;&apos;&apos; Anyway, wildcard characters are not allowed in Destination
356 &apos;&apos;&apos; Overwrite: If True (default), files may be overwritten
357 &apos;&apos;&apos; CopyFile will fail if Destination has the read-only attribute set, regardless of the value of Overwrite.
358 &apos;&apos;&apos; Returns:
359 &apos;&apos;&apos; True if at least one file has been copied
360 &apos;&apos;&apos; False if an error occurred
361 &apos;&apos;&apos; An error also occurs if a source using wildcard characters doesn&apos;t match any files.
362 &apos;&apos;&apos; The method stops on the first error it encounters
363 &apos;&apos;&apos; No attempt is made to roll back or undo any changes made before an error occurs
364 &apos;&apos;&apos; Exceptions:
365 &apos;&apos;&apos; UNKNOWNFILEERROR Source does not exist
366 &apos;&apos;&apos; UNKNOWNFOLDERERROR Source folder or Destination folder does not exist
367 &apos;&apos;&apos; NOFILEMATCHERROR No file matches Source containing wildcards
368 &apos;&apos;&apos; NOTAFOLDERERROR Destination is a file, not a folder
369 &apos;&apos;&apos; NOTAFILEERROR Destination is a folder, not a file
370 &apos;&apos;&apos; OVERWRITEERROR Destination can not be overwritten
371 &apos;&apos;&apos; READONLYERROR Destination has its read-only attribute set
372 &apos;&apos;&apos; Example:
373 &apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
374 &apos;&apos;&apos; FSO.CopyFile(&quot;C:\Windows\*.*&quot;, &quot;C:\Temp\&quot;, Overwrite := False) &apos; Only files are copied, subfolders are not
376 Dim bCopy As Boolean &apos; Return value
378 Const cstThisSub = &quot;FileSystem.CopyFile&quot;
379 Const cstSubArgs = &quot;Source, Destination, [Overwrite=True]&quot;
381 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
382 bCopy = False
384 Check:
385 If IsMissing(Overwrite) Or IsEmpty(Overwrite) Then Overwrite = True
386 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
387 If Not SF_Utils._ValidateFile(Source, &quot;Source&quot;, True) Then GoTo Finally
388 If Not SF_Utils._ValidateFile(Destination, &quot;Destination&quot;, False) Then GoTo Finally
389 If Not SF_Utils._Validate(Overwrite, &quot;Overwrite&quot;, V_BOOLEAN) Then GoTo Finally
390 End If
392 Try:
393 bCopy = SF_FileSystem._CopyMove(&quot;CopyFile&quot;, Source, Destination, Overwrite)
395 Finally:
396 CopyFile = bCopy
397 SF_Utils._ExitFunction(cstThisSub)
398 Exit Function
399 Catch:
400 GoTo Finally
401 End Function &apos; ScriptForge.SF_FileSystem.CopyFile
403 REM -----------------------------------------------------------------------------
404 Public Function CopyFolder(Optional ByVal Source As Variant _
405 , Optional ByVal Destination As Variant _
406 , Optional ByVal Overwrite As Variant _
407 ) As Boolean
408 &apos;&apos;&apos; Copies one or more folders from one location to another
409 &apos;&apos;&apos; Args:
410 &apos;&apos;&apos; Source: FolderName or NamePattern which can include wildcard characters, for one or more folders to be copied
411 &apos;&apos;&apos; Destination: FolderName where the single Source folder is to be copied
412 &apos;&apos;&apos; or FolderName where the multiple folders from Source are to be copied
413 &apos;&apos;&apos; If FolderName does not exist, it is created
414 &apos;&apos;&apos; Anyway, wildcard characters are not allowed in Destination
415 &apos;&apos;&apos; Overwrite: If True (default), folders and their content may be overwritten
416 &apos;&apos;&apos; CopyFile will fail if Destination has the read-only attribute set, regardless of the value of Overwrite.
417 &apos;&apos;&apos; Returns:
418 &apos;&apos;&apos; True if at least one folder has been copied
419 &apos;&apos;&apos; False if an error occurred
420 &apos;&apos;&apos; An error also occurs if a source using wildcard characters doesn&apos;t match any folders.
421 &apos;&apos;&apos; The method stops on the first error it encounters
422 &apos;&apos;&apos; No attempt is made to roll back or undo any changes made before an error occurs
423 &apos;&apos;&apos; Exceptions:
424 &apos;&apos;&apos; UNKNOWNFILEERROR Source does not exist
425 &apos;&apos;&apos; UNKNOWNFOLDERERROR Source folder or Destination folder does not exist
426 &apos;&apos;&apos; NOFILEMATCHERROR No file matches Source containing wildcards
427 &apos;&apos;&apos; NOTAFOLDERERROR Destination is a file, not a folder
428 &apos;&apos;&apos; OVERWRITEERROR Destination can not be overwritten
429 &apos;&apos;&apos; READONLYERROR Destination has its read-only attribute set
430 &apos;&apos;&apos; Example:
431 &apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
432 &apos;&apos;&apos; FSO.CopyFolder(&quot;C:\Windows\*&quot;, &quot;C:\Temp\&quot;, Overwrite := False)
434 Dim bCopy As Boolean &apos; Return value
436 Const cstThisSub = &quot;FileSystem.CopyFolder&quot;
437 Const cstSubArgs = &quot;Source, Destination, [Overwrite=True]&quot;
439 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
440 bCopy = False
442 Check:
443 If IsMissing(Overwrite) Or IsEmpty(Overwrite) Then Overwrite = True
444 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
445 If Not SF_Utils._ValidateFile(Source, &quot;Source&quot;, True) Then GoTo Finally
446 If Not SF_Utils._ValidateFile(Destination, &quot;Destination&quot;, False) Then GoTo Finally
447 If Not SF_Utils._Validate(Overwrite, &quot;Overwrite&quot;, V_BOOLEAN) Then GoTo Finally
448 End If
450 Try:
451 bCopy = SF_FileSystem._CopyMove(&quot;CopyFolder&quot;, Source, Destination, Overwrite)
453 Finally:
454 CopyFolder = bCopy
455 SF_Utils._ExitFunction(cstThisSub)
456 Exit Function
457 Catch:
458 GoTo Finally
459 End Function &apos; ScriptForge.SF_FileSystem.CopyFolder
461 REM -----------------------------------------------------------------------------
462 Public Function CreateFolder(Optional ByVal FolderName As Variant) As Boolean
463 &apos;&apos;&apos; Return True if the given folder name could be created successfully
464 &apos;&apos;&apos; The parent folder does not need to exist beforehand
465 &apos;&apos;&apos; Args:
466 &apos;&apos;&apos; FolderName: a string representing the folder to create. It must not exist
467 &apos;&apos;&apos; Returns:
468 &apos;&apos;&apos; True if FolderName is a valid folder name, does not exist and creation was successful
469 &apos;&apos;&apos; False otherwise including when FolderName is a file
470 &apos;&apos;&apos; Exceptions:
471 &apos;&apos;&apos; FOLDERCREATIONERROR FolderName is an existing folder or file
472 &apos;&apos;&apos; Example:
473 &apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
474 &apos;&apos;&apos; FSO.CreateFolder(&quot;C:\NewFolder\&quot;)
476 Dim bCreate As Boolean &apos; Return value
477 Dim oSfa As Object &apos; com.sun.star.ucb.SimpleFileAccess
479 Const cstThisSub = &quot;FileSystem.CreateFolder&quot;
480 Const cstSubArgs = &quot;FolderName&quot;
482 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
483 bCreate = False
485 Check:
486 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
487 If Not SF_Utils._ValidateFile(FolderName, &quot;FolderName&quot;) Then GoTo Finally
488 End If
490 Try:
491 Set oSfa = SF_Utils._GetUnoService(&quot;FileAccess&quot;)
492 If SF_FileSystem.FolderExists(FolderName) Then GoTo CatchExists
493 If SF_FileSystem.FileExists(FolderName) Then GoTo CatchExists
494 oSfa.createFolder(SF_FileSystem._ConvertToUrl(FolderName))
495 bCreate = True
497 Finally:
498 CreateFolder = bCreate
499 SF_Utils._ExitFunction(cstThisSub)
500 Exit Function
501 Catch:
502 GoTo Finally
503 CatchExists:
504 SF_Exception.RaiseFatal(FOLDERCREATIONERROR, &quot;FolderName&quot;, FolderName)
505 GoTo Finally
506 End Function &apos; ScriptForge.SF_FileSystem.CreateFolder
508 REM -----------------------------------------------------------------------------
509 Public Function CreateTextFile(Optional ByVal FileName As Variant _
510 , Optional ByVal Overwrite As Variant _
511 , Optional ByVal Encoding As Variant _
512 ) As Object
513 &apos;&apos;&apos; Creates a specified file and returns a TextStream object that can be used to write to the file
514 &apos;&apos;&apos; Args:
515 &apos;&apos;&apos; FileName: Identifies the file to create
516 &apos;&apos;&apos; Overwrite: Boolean value that indicates if an existing file can be overwritten (default = True)
517 &apos;&apos;&apos; Encoding: The character set that should be used
518 &apos;&apos;&apos; Use one of the Names listed in https://www.iana.org/assignments/character-sets/character-sets.xhtml
519 &apos;&apos;&apos; Note that LibreOffice does not implement all existing sets
520 &apos;&apos;&apos; Default = UTF-8
521 &apos;&apos;&apos; Returns:
522 &apos;&apos;&apos; An instance of the SF_TextStream class representing the opened file or a Null object if an error occurred
523 &apos;&apos;&apos; It doesn&apos;t check either if the given encoding is implemented in LibreOffice
524 &apos;&apos;&apos; Exceptions:
525 &apos;&apos;&apos; OVERWRITEERROR File exists, creation impossible
526 &apos;&apos;&apos; Example:
527 &apos;&apos;&apos; Dim myFile As Object
528 &apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
529 &apos;&apos;&apos; Set myFile = FSO.CreateTextFile(&quot;C:\Temp\ThisFile.txt&quot;, Overwrite := True)
531 Dim oTextStream As Object &apos; Return value
532 Const cstThisSub = &quot;FileSystem.CreateTextFile&quot;
533 Const cstSubArgs = &quot;FileName, [Overwrite=True], [Encoding=&quot;&quot;UTF-8&quot;&quot;]&quot;
535 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
536 Set oTextStream = Nothing
538 Check:
539 If IsMissing(Overwrite) Or IsEmpty(Overwrite) Then Overwrite = True
540 If IsMissing(Encoding) Or IsEmpty(Encoding) Then Encoding = &quot;UTF-8&quot;
541 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
542 If Not SF_Utils._ValidateFile(FileName, &quot;FileName&quot;) Then GoTo Finally
543 If Not SF_Utils._Validate(Overwrite, &quot;Overwrite&quot;, V_BOOLEAN) Then GoTo Finally
544 If Not SF_Utils._Validate(Encoding, &quot;Encoding&quot;, V_STRING) Then GoTo Finally
545 End If
547 With SF_FileSystem
548 If .FileExists(FileName) Then
549 If Overwrite Then .DeleteFile(FileName) Else GoTo CatchOverWrite
550 End If
552 Try:
553 Set oTextStream = .OpenTextFile(FileName, .ForWriting, Create := True, Encoding := Encoding)
554 End With
556 Finally:
557 Set CreateTextFile = oTextStream
558 SF_Utils._ExitFunction(cstThisSub)
559 Exit Function
560 Catch:
561 GoTo Finally
562 CatchOverWrite:
563 SF_Exception.RaiseFatal(OVERWRITEERROR, &quot;FileName&quot;, FileName)
564 GoTo Finally
565 End Function &apos; ScriptForge.SF_FileSystem.CreateTextFile
567 REM -----------------------------------------------------------------------------
568 Public Function DeleteFile(Optional ByVal FileName As Variant) As Boolean
569 &apos;&apos;&apos; Deletes one or more files
570 &apos;&apos;&apos; Args:
571 &apos;&apos;&apos; FileName: FileName or NamePattern which can include wildcard characters, for one or more files to be deleted
572 &apos;&apos;&apos; Returns:
573 &apos;&apos;&apos; True if at least one file has been deleted
574 &apos;&apos;&apos; False if an error occurred
575 &apos;&apos;&apos; An error also occurs if a FileName using wildcard characters doesn&apos;t match any files.
576 &apos;&apos;&apos; The method stops on the first error it encounters
577 &apos;&apos;&apos; No attempt is made to roll back or undo any changes made before an error occurs
578 &apos;&apos;&apos; Exceptions:
579 &apos;&apos;&apos; UNKNOWNFILEERROR FileName does not exist
580 &apos;&apos;&apos; NOFILEMATCHERROR No file matches FileName containing wildcards
581 &apos;&apos;&apos; NOTAFILEERROR Argument is a folder, not a file
582 &apos;&apos;&apos; Example:
583 &apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
584 &apos;&apos;&apos; FSO.DeleteFile(&quot;C:\Temp\*.*&quot;) &apos; Only files are deleted, subfolders are not
586 Dim bDelete As Boolean &apos; Return value
588 Const cstThisSub = &quot;FileSystem.DeleteFile&quot;
589 Const cstSubArgs = &quot;FileName&quot;
591 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
592 bDelete = False
594 Check:
595 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
596 If Not SF_Utils._ValidateFile(FileName, &quot;FileName&quot;, True) Then GoTo Finally
597 End If
599 Try:
600 bDelete = SF_FileSystem._Delete(&quot;DeleteFile&quot;, FileName)
602 Finally:
603 DeleteFile = bDelete
604 SF_Utils._ExitFunction(cstThisSub)
605 Exit Function
606 Catch:
607 GoTo Finally
608 End Function &apos; ScriptForge.SF_FileSystem.DeleteFile
610 REM -----------------------------------------------------------------------------
611 Public Function DeleteFolder(Optional ByVal FolderName As Variant) As Boolean
612 &apos;&apos;&apos; Deletes one or more Folders
613 &apos;&apos;&apos; Args:
614 &apos;&apos;&apos; FolderName: FolderName or NamePattern which can include wildcard characters, for one or more Folders to be deleted
615 &apos;&apos;&apos; Returns:
616 &apos;&apos;&apos; True if at least one folder has been deleted
617 &apos;&apos;&apos; False if an error occurred
618 &apos;&apos;&apos; An error also occurs if a FolderName using wildcard characters doesn&apos;t match any folders.
619 &apos;&apos;&apos; The method stops on the first error it encounters
620 &apos;&apos;&apos; No attempt is made to roll back or undo any changes made before an error occurs
621 &apos;&apos;&apos; Exceptions:
622 &apos;&apos;&apos; UNKNOWNFOLDERERROR FolderName does not exist
623 &apos;&apos;&apos; NOFILEMATCHERROR No folder matches FolderName containing wildcards
624 &apos;&apos;&apos; NOTAFOLDERERROR Argument is a file, not a folder
625 &apos;&apos;&apos; Example:
626 &apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
627 &apos;&apos;&apos; FSO.DeleteFolder(&quot;C:\Temp\*&quot;) &apos; Only folders are deleted, files in the parent folder are not
629 Dim bDelete As Boolean &apos; Return value
631 Const cstThisSub = &quot;FileSystem.DeleteFolder&quot;
632 Const cstSubArgs = &quot;FolderName&quot;
634 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
635 bDelete = False
637 Check:
638 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
639 If Not SF_Utils._ValidateFile(FolderName, &quot;FolderName&quot;, True) Then GoTo Finally
640 End If
642 Try:
643 bDelete = SF_FileSystem._Delete(&quot;DeleteFolder&quot;, FolderName)
645 Finally:
646 DeleteFolder = bDelete
647 SF_Utils._ExitFunction(cstThisSub)
648 Exit Function
649 Catch:
650 GoTo Finally
651 End Function &apos; ScriptForge.SF_FileSystem.DeleteFolder
653 REM -----------------------------------------------------------------------------
654 Public Function ExtensionFolder(Optional ByVal Extension As Variant) As String
655 &apos;&apos;&apos; Return the folder where the given extension is installed. The argument must
656 &apos;&apos;&apos; be in the list of extensions provided by the SF_Platform.Extensions property
657 &apos;&apos;&apos; Args:
658 &apos;&apos;&apos; Extension: a valid extension name
659 &apos;&apos;&apos; Returns:
660 &apos;&apos;&apos; The requested folder using the FileNaming notation
661 &apos;&apos;&apos; Example:
662 &apos;&apos;&apos; MsgBox FSO.ExtensionFolder(&quot;apso.python.script.organizer&quot;)
664 Dim sFolder As String &apos; Return value
665 Static vExtensions As Variant &apos; Cached list of existing extension names
666 Dim oPackage As Object &apos; /singletons/com.sun.star.deployment.PackageInformationProvider
667 Const cstThisSub = &quot;FileSystem.ExtensionFolder&quot;
668 Const cstSubArgs = &quot;Extension&quot;
670 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
671 sFolder = &quot;&quot;
673 Check:
674 If IsEmpty(vExtensions) Then vExtensions = SF_Platform.Extensions
675 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
676 If Not SF_Utils._Validate(Extension, &quot;Extension&quot;, V_STRING, vExtensions) Then GoTo Finally
677 End If
679 Try:
680 &apos; Search an individual folder
681 Set oPackage = SF_Utils._GetUnoService(&quot;PackageInformationProvider&quot;)
682 sFolder = oPackage.getPackageLocation(Extension)
684 Finally:
685 ExtensionFolder = SF_FileSystem._ConvertFromUrl(sFolder)
686 SF_Utils._ExitFunction(cstThisSub)
687 Exit Function
688 Catch:
689 GoTo Finally
690 End Function &apos; ScriptForge.SF_FileSystem.ExtensionFolder
692 REM -----------------------------------------------------------------------------
693 Public Function FileExists(Optional ByVal FileName As Variant) As Boolean
694 &apos;&apos;&apos; Return True if the given file exists
695 &apos;&apos;&apos; Args:
696 &apos;&apos;&apos; FileName: a string representing a file
697 &apos;&apos;&apos; Returns:
698 &apos;&apos;&apos; True if FileName is a valid File name and it exists
699 &apos;&apos;&apos; False otherwise including when FileName is a folder
700 &apos;&apos;&apos; Example:
701 &apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
702 &apos;&apos;&apos; If FSO.FileExists(&quot;C:\Notepad.exe&quot;) Then ...
704 Dim bExists As Boolean &apos; Return value
705 Dim oSfa As Object &apos; com.sun.star.ucb.SimpleFileAccess
707 Const cstThisSub = &quot;FileSystem.FileExists&quot;
708 Const cstSubArgs = &quot;FileName&quot;
710 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
711 bExists = False
713 Check:
714 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
715 If Not SF_Utils._ValidateFile(FileName, &quot;FileName&quot;) Then GoTo Finally
716 End If
717 FileName = SF_FileSystem._ConvertToUrl(FileName)
719 Try:
720 Set oSfa = SF_Utils._GetUnoService(&quot;FileAccess&quot;)
721 bExists = oSfa.exists(FileName) And Not oSfa.isFolder(FileName)
723 Finally:
724 FileExists = bExists
725 SF_Utils._ExitFunction(cstThisSub)
726 Exit Function
727 Catch:
728 GoTo Finally
729 End Function &apos; ScriptForge.SF_FileSystem.FileExists
731 REM -----------------------------------------------------------------------------
732 Public Function Files(Optional ByVal FolderName As Variant _
733 , Optional ByVal Filter As Variant _
734 ) As Variant
735 &apos;&apos;&apos; Return an array of the FileNames stored in the given folder. The folder must exist
736 &apos;&apos;&apos; Args:
737 &apos;&apos;&apos; FolderName: the folder to explore
738 &apos;&apos;&apos; Filter: contains wildcards (&quot;?&quot; and &quot;*&quot;) to limit the list to the relevant files (default = &quot;&quot;)
739 &apos;&apos;&apos; Returns:
740 &apos;&apos;&apos; An array of strings, each entry is the FileName of an existing file
741 &apos;&apos;&apos; Exceptions:
742 &apos;&apos;&apos; UNKNOWNFOLDERERROR Folder does not exist
743 &apos;&apos;&apos; NOTAFOLDERERROR FolderName is a file, not a folder
744 &apos;&apos;&apos; Example:
745 &apos;&apos;&apos; Dim a As Variant
746 &apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
747 &apos;&apos;&apos; a = FSO.Files(&quot;C:\Windows\&quot;)
749 Dim vFiles As Variant &apos; Return value
750 Dim oSfa As Object &apos; com.sun.star.ucb.SimpleFileAccess
751 Dim sFolderName As String &apos; URL lias for FolderName
752 Dim sFile As String &apos; Single file
753 Dim i As Long
755 Const cstThisSub = &quot;FileSystem.Files&quot;
756 Const cstSubArgs = &quot;FolderName, [Filter=&quot;&quot;&quot;&quot;]&quot;
758 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
759 vFiles = Array()
761 Check:
762 If IsMissing(Filter) Or IsEmpty(Filter) Then Filter = &quot;&quot;
763 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
764 If Not SF_Utils._ValidateFile(FolderName, &quot;FolderName&quot;) Then GoTo Finally
765 If Not SF_Utils._Validate(Filter, &quot;Filter&quot;, V_STRING) Then GoTo Finally
766 End If
767 sFolderName = SF_FileSystem._ConvertToUrl(FolderName)
768 If SF_FileSystem.FileExists(FolderName) Then GoTo CatchFile &apos; Must not be a file
769 If Not SF_FileSystem.FolderExists(FolderName) Then GoTo CatchFolder &apos; Folder must exist
771 Try:
772 &apos; Get files
773 Set oSfa = SF_Utils._GetUnoService(&quot;FileAccess&quot;)
774 vFiles = oSfa.getFolderContents(sFolderName, False)
775 &apos; Adjust notations
776 For i = 0 To UBound(vFiles)
777 sFile = SF_FileSystem._ConvertFromUrl(vFiles(i))
778 vFiles(i) = sFile
779 Next i
780 &apos; Reduce list to those passing the filter
781 If Len(Filter) &gt; 0 Then
782 For i = 0 To UBound(vFiles)
783 sFile = SF_FileSystem.GetName(vFiles(i))
784 If Not SF_String.IsLike(sFile, Filter) Then vFiles(i) = &quot;&quot;
785 Next i
786 vFiles = Sf_Array.TrimArray(vFiles)
787 End If
789 Finally:
790 Files = vFiles
791 SF_Utils._ExitFunction(cstThisSub)
792 Exit Function
793 Catch:
794 GoTo Finally
795 CatchFile:
796 SF_Exception.RaiseFatal(NOTAFOLDERERROR, &quot;FolderName&quot;, FolderName)
797 GoTo Finally
798 CatchFolder:
799 SF_Exception.RaiseFatal(UNKNOWNFOLDERERROR, &quot;FolderName&quot;, FolderName)
800 GoTo Finally
801 End Function &apos; ScriptForge.SF_FileSystem.Files
803 REM -----------------------------------------------------------------------------
804 Public Function FolderExists(Optional ByVal FolderName As Variant) As Boolean
805 &apos;&apos;&apos; Return True if the given folder name exists
806 &apos;&apos;&apos; Args:
807 &apos;&apos;&apos; FolderName: a string representing a folder
808 &apos;&apos;&apos; Returns:
809 &apos;&apos;&apos; True if FolderName is a valid folder name and it exists
810 &apos;&apos;&apos; False otherwise including when FolderName is a file
811 &apos;&apos;&apos; Example:
812 &apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
813 &apos;&apos;&apos; If FSO.FolderExists(&quot;C:\&quot;) Then ...
815 Dim bExists As Boolean &apos; Return value
816 Dim oSfa As Object &apos; com.sun.star.ucb.SimpleFileAccess
818 Const cstThisSub = &quot;FileSystem.FolderExists&quot;
819 Const cstSubArgs = &quot;FolderName&quot;
821 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
822 bExists = False
824 Check:
825 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
826 If Not SF_Utils._ValidateFile(FolderName, &quot;FolderName&quot;) Then GoTo Finally
827 End If
828 FolderName = SF_FileSystem._ConvertToUrl(FolderName)
830 Try:
831 Set oSfa = SF_Utils._GetUnoService(&quot;FileAccess&quot;)
832 bExists = oSfa.isFolder(FolderName)
834 Finally:
835 FolderExists = bExists
836 SF_Utils._ExitFunction(cstThisSub)
837 Exit Function
838 Catch:
839 GoTo Finally
840 End Function &apos; ScriptForge.SF_FileSystem.FolderExists
842 REM -----------------------------------------------------------------------------
843 Public Function GetBaseName(Optional ByVal FileName As Variant) As String
844 &apos;&apos;&apos; Returns the BaseName part of the last component of a File- or FolderName, without its extension
845 &apos;&apos;&apos; The method does not check for the existence of the specified file or folder
846 &apos;&apos;&apos; Args:
847 &apos;&apos;&apos; FileName: Path and file name
848 &apos;&apos;&apos; Returns:
849 &apos;&apos;&apos; The BaseName of the given argument in native operating system format. May be empty
850 &apos;&apos;&apos; Example:
851 &apos;&apos;&apos; Dim a As String
852 &apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
853 &apos;&apos;&apos; a = FSO.GetBaseName(&quot;C:\Windows\Notepad.exe&quot;) returns Notepad
855 Dim sBase As String &apos; Return value
856 Dim sExt As String &apos; Extension
857 Dim sName As String &apos; Last component of FileName
858 Dim vName As Variant &apos; Array of trunks of sName
859 Const cstThisSub = &quot;FileSystem.GetBaseName&quot;
860 Const cstSubArgs = &quot;FileName&quot;
862 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
863 sBase = &quot;&quot;
865 Check:
866 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
867 If Not SF_Utils._ValidateFile(FileName, &quot;FileName&quot;) Then GoTo Finally
868 End If
870 Try:
871 sName = SF_FileSystem.GetName(FileName)
872 If Len(sName) &gt; 0 Then
873 If InStr(sName, &quot;.&quot;) &gt; 0 Then
874 vName = Split(sName, &quot;.&quot;)
875 sExt = vName(UBound(vName))
876 sBase = Left(sName, Len(sName) - Len(sExt) - 1)
877 Else
878 sBase = sName
879 End If
880 End If
882 Finally:
883 GetBaseName = sBase
884 SF_Utils._ExitFunction(cstThisSub)
885 Exit Function
886 Catch:
887 GoTo Finally
888 End Function &apos; ScriptForge.SF_FileSystem.GetBaseName
890 REM -----------------------------------------------------------------------------
891 Public Function GetExtension(Optional ByVal FileName As Variant) As String
892 &apos;&apos;&apos; Returns the extension part of a File- or FolderName, without the dot (.).
893 &apos;&apos;&apos; The method does not check for the existence of the specified file or folder
894 &apos;&apos;&apos; Args:
895 &apos;&apos;&apos; FileName: Path and file name
896 &apos;&apos;&apos; Returns:
897 &apos;&apos;&apos; The extension without a leading dot. May be empty
898 &apos;&apos;&apos; Example:
899 &apos;&apos;&apos; Dim a As String
900 &apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
901 &apos;&apos;&apos; a = FSO.GetExtension(&quot;C:\Windows\Notepad.exe&quot;) returns exe
903 Dim sExt As String &apos; Return value
904 Dim sName As String &apos; Last component of FileName
905 Dim vName As Variant &apos; Array of trunks of sName
906 Const cstThisSub = &quot;FileSystem.GetExtension&quot;
907 Const cstSubArgs = &quot;FileName&quot;
909 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
910 sExt = &quot;&quot;
912 Check:
913 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
914 If Not SF_Utils._ValidateFile(FileName, &quot;FileName&quot;) Then GoTo Finally
915 End If
917 Try:
918 sName = SF_FileSystem.GetName(FileName)
919 If Len(sName) &gt; 0 And InStr(sName, &quot;.&quot;) &gt; 0 Then
920 vName = Split(sName, &quot;.&quot;)
921 sExt = vName(UBound(vName))
922 End If
924 Finally:
925 GetExtension = sExt
926 SF_Utils._ExitFunction(cstThisSub)
927 Exit Function
928 Catch:
929 GoTo Finally
930 End Function &apos; ScriptForge.SF_FileSystem.GetExtension
932 REM -----------------------------------------------------------------------------
933 Public Function GetFileLen(Optional ByVal FileName As Variant) As Currency
934 &apos;&apos;&apos; Return file size in bytes with four decimals &apos;&apos;&apos;
935 &apos;&apos;&apos; Args:
936 &apos;&apos;&apos; FileName: a string representing a file
937 &apos;&apos;&apos; Returns:
938 &apos;&apos;&apos; File size if FileName exists
939 &apos;&apos;&apos; Exceptions:
940 &apos;&apos;&apos; UNKNOWNFILEERROR The file does not exist of is a folder
941 &apos;&apos;&apos; Example:
942 &apos;&apos;&apos; Print SF_FileSystem.GetFileLen(&quot;C:\pagefile.sys&quot;)
944 Dim curSize As Currency &apos; Return value
945 Const cstPyHelper = &quot;$&quot; &amp; &quot;_SF_FileSystem__GetFilelen&quot;
946 Const cstThisSub = &quot;FileSystem.GetFileLen&quot;
947 Const cstSubArgs = &quot;FileName&quot;
949 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
950 curSize = 0
952 Check:
953 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
954 If Not SF_Utils._ValidateFile(FileName, &quot;FileName&quot;) Then GoTo Finally
955 End If
957 Try:
958 If SF_FileSystem.FileExists(FileName) Then
959 With ScriptForge.SF_Session
960 curSize = .ExecutePythonScript(.SCRIPTISSHARED, _SF_.PythonHelper &amp; cstPyHelper _
961 , _ConvertFromUrl(FileName))
962 End With
963 Else
964 GoTo CatchNotExists
965 End If
967 Finally:
968 GetFileLen = curSize
969 SF_Utils._ExitFunction(cstThisSub)
970 Exit Function
971 Catch:
972 GoTo Finally
973 CatchNotExists:
974 SF_Exception.RaiseFatal(UNKNOWNFILEERROR, &quot;FileName&quot;, FileName)
975 GoTo Finally
976 End Function &apos; ScriptForge.SF_FileSystem.GetFileLen
978 REM -----------------------------------------------------------------------------
979 Public Function GetFileModified(Optional ByVal FileName As Variant) As Variant
980 &apos;&apos;&apos; Returns the last modified date for the given file
981 &apos;&apos;&apos; Args:
982 &apos;&apos;&apos; FileName: a string representing an existing file
983 &apos;&apos;&apos; Returns:
984 &apos;&apos;&apos; The modification date and time as a Basic Date
985 &apos;&apos;&apos; Exceptions:
986 &apos;&apos;&apos; UNKNOWNFILEERROR The file does not exist of is a folder
987 &apos;&apos;&apos; Example:
988 &apos;&apos;&apos; Dim a As Date
989 &apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
990 &apos;&apos;&apos; a = FSO.GetFileModified(&quot;C:\Temp\myDoc.odt&quot;)
992 Dim dModified As Date &apos; Return value
993 Dim oModified As New com.sun.star.util.DateTime
994 Dim oSfa As Object &apos; com.sun.star.ucb.SimpleFileAccess
996 Const cstThisSub = &quot;FileSystem.GetFileModified&quot;
997 Const cstSubArgs = &quot;FileName&quot;
999 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
1000 dModified = 0
1002 Check:
1003 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
1004 If Not SF_Utils._ValidateFile(FileName, &quot;FileName&quot;) Then GoTo Finally
1005 End If
1007 Try:
1008 Set oSfa = SF_Utils._GetUnoService(&quot;FileAccess&quot;)
1009 If SF_FileSystem.FileExists(FileName) Then
1010 FileName = SF_FileSystem._ConvertToUrl(FileName)
1011 Set oModified = oSfa.getDateTimeModified(FileName)
1012 dModified = CDateFromUnoDateTime(oModified)
1013 Else
1014 GoTo CatchNotExists
1015 End If
1017 Finally:
1018 GetFileModified = dModified
1019 SF_Utils._ExitFunction(cstThisSub)
1020 Exit Function
1021 Catch:
1022 GoTo Finally
1023 CatchNotExists:
1024 SF_Exception.RaiseFatal(UNKNOWNFILEERROR, &quot;FileName&quot;, FileName)
1025 GoTo Finally
1026 End Function &apos; ScriptForge.SF_FileSystem.GetFileModified
1028 REM -----------------------------------------------------------------------------
1029 Public Function GetName(Optional ByVal FileName As Variant) As String
1030 &apos;&apos;&apos; Returns the last component of a File- or FolderName
1031 &apos;&apos;&apos; The method does not check for the existence of the specified file or folder
1032 &apos;&apos;&apos; Args:
1033 &apos;&apos;&apos; FileName: Path and file name
1034 &apos;&apos;&apos; Returns:
1035 &apos;&apos;&apos; The last component of the full file name in native operating system format
1036 &apos;&apos;&apos; Example:
1037 &apos;&apos;&apos; Dim a As String
1038 &apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
1039 &apos;&apos;&apos; a = FSO.GetName(&quot;C:\Windows\Notepad.exe&quot;) returns Notepad.exe
1041 Dim sName As String &apos; Return value
1042 Dim vFile As Variant &apos; Array of components
1043 Const cstThisSub = &quot;FileSystem.GetName&quot;
1044 Const cstSubArgs = &quot;FileName&quot;
1046 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
1047 sName = &quot;&quot;
1049 Check:
1050 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
1051 If Not SF_Utils._ValidateFile(FileName, &quot;FileName&quot;) Then GoTo Finally
1052 End If
1053 FileName = SF_FileSystem._ConvertToUrl(FileName)
1055 Try:
1056 If Len(FileName) &gt; 0 Then
1057 If Right(FileName, 1) = &quot;/&quot; Then FileName = Left(FileName, Len(FileName) - 1)
1058 vFile = Split(FileName, &quot;/&quot;)
1059 sName = ConvertFromUrl(vFile(UBound(vFile))) &apos; Always in SYS format
1060 End If
1062 Finally:
1063 GetName = sName
1064 SF_Utils._ExitFunction(cstThisSub)
1065 Exit Function
1066 Catch:
1067 GoTo Finally
1068 End Function &apos; ScriptForge.SF_FileSystem.GetName
1070 REM -----------------------------------------------------------------------------
1071 Public Function GetParentFolderName(Optional ByVal FileName As Variant) As String
1072 &apos;&apos;&apos; Returns a string containing the name of the parent folder of the last component in a specified File- or FolderName
1073 &apos;&apos;&apos; The method does not check for the existence of the specified file or folder
1074 &apos;&apos;&apos; Args:
1075 &apos;&apos;&apos; FileName: Path and file name
1076 &apos;&apos;&apos; Returns:
1077 &apos;&apos;&apos; A FolderName including its final path separator
1078 &apos;&apos;&apos; Example:
1079 &apos;&apos;&apos; Dim a As String
1080 &apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
1081 &apos;&apos;&apos; a = FSO.GetParentFolderName(&quot;C:\Windows\Notepad.exe&quot;) returns C:\Windows\
1083 Dim sFolder As String &apos; Return value
1084 Dim sName As String &apos; Last component of FileName
1085 Dim vFile As Variant &apos; Array of file components
1086 Const cstThisSub = &quot;FileSystem.GetParentFolderName&quot;
1087 Const cstSubArgs = &quot;FileName&quot;
1089 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
1090 sFolder = &quot;&quot;
1092 Check:
1093 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
1094 If Not SF_Utils._ValidateFile(FileName, &quot;FileName&quot;) Then GoTo Finally
1095 End If
1096 FileName = SF_FileSystem._ConvertToUrl(FileName)
1098 Try:
1099 If Right(FileName, 1) = &quot;/&quot; Then FileName = Left(FileName, Len(FileName) - 1)
1100 vFile = Split(FileName, &quot;/&quot;)
1101 If UBound(vFile) &gt;= 0 Then vFile(UBound(vFile)) = &quot;&quot;
1102 sFolder = Join(vFile, &quot;/&quot;)
1103 If sFolder = &quot;&quot; Or Right(sFolder, 1) &lt;&gt; &quot;/&quot; Then sFolder = sFolder &amp; &quot;/&quot;
1105 Finally:
1106 GetParentFolderName = SF_FileSystem._ConvertFromUrl(sFolder)
1107 SF_Utils._ExitFunction(cstThisSub)
1108 Exit Function
1109 Catch:
1110 GoTo Finally
1111 End Function &apos; ScriptForge.SF_FileSystem.GetParentFolderName
1113 REM -----------------------------------------------------------------------------
1114 Public Function GetProperty(Optional ByVal PropertyName As Variant) As Variant
1115 &apos;&apos;&apos; Return the actual value of the given property
1116 &apos;&apos;&apos; Args:
1117 &apos;&apos;&apos; PropertyName: the name of the property as a string
1118 &apos;&apos;&apos; Returns:
1119 &apos;&apos;&apos; The actual value of the property
1120 &apos;&apos;&apos; Exceptions
1121 &apos;&apos;&apos; ARGUMENTERROR The property does not exist
1123 Const cstThisSub = &quot;FileSystem.GetProperty&quot;
1124 Const cstSubArgs = &quot;PropertyName&quot;
1126 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
1127 GetProperty = Null
1129 Check:
1130 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
1131 If Not SF_Utils._Validate(PropertyName, &quot;PropertyName&quot;, V_STRING, Properties()) Then GoTo Catch
1132 End If
1134 Try:
1135 Select Case UCase(PropertyName)
1136 Case UCase(&quot;ConfigFolder&quot;) : GetProperty = ConfigFolder
1137 Case UCase(&quot;ExtensionsFolder&quot;) : GetProperty = ExtensionsFolder
1138 Case UCase(&quot;FileNaming&quot;) : GetProperty = FileNaming
1139 Case UCase(&quot;HomeFolder&quot;) : GetProperty = HomeFolder
1140 Case UCase(&quot;InstallFolder&quot;) : GetProperty = InstallFolder
1141 Case UCase(&quot;TemplatesFolder&quot;) : GetProperty = TemplatesFolder
1142 Case UCase(&quot;TemporaryFolder&quot;) : GetProperty = TemporaryFolder
1143 Case UCase(&quot;UserTemplatesFolder&quot;) : GetProperty = UserTemplatesFolder
1144 Case Else
1145 End Select
1147 Finally:
1148 SF_Utils._ExitFunction(cstThisSub)
1149 Exit Function
1150 Catch:
1151 GoTo Finally
1152 End Function &apos; ScriptForge.SF_FileSystem.GetProperty
1154 REM -----------------------------------------------------------------------------
1155 Public Function GetTempName() As String
1156 &apos;&apos;&apos; Returns a randomly generated temporary file name that is useful for performing
1157 &apos;&apos;&apos; operations that require a temporary file : the method does not create any file
1158 &apos;&apos;&apos; Args:
1159 &apos;&apos;&apos; Returns:
1160 &apos;&apos;&apos; A FileName as a String that can be used f.i. with CreateTextFile()
1161 &apos;&apos;&apos; The FileName does not have any suffix
1162 &apos;&apos;&apos; Example:
1163 &apos;&apos;&apos; Dim a As String
1164 &apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
1165 &apos;&apos;&apos; a = FSO.GetTempName() &amp; &quot;.txt&quot;
1167 Dim sFile As String &apos; Return value
1168 Dim sTempDir As String &apos; The path to a temporary folder
1169 Dim lRandom As Long &apos; Random integer
1171 Const cstThisSub = &quot;FileSystem.GetTempName&quot;
1172 Const cstSubArgs = &quot;&quot;
1174 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
1175 sFile = &quot;&quot;
1177 Check:
1178 SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
1180 Try:
1181 lRandom = SF_Session.ExecuteCalcFunction(&quot;RANDBETWEEN.NV&quot;, 1, 999999)
1182 sFile = SF_FileSystem.TemporaryFolder &amp; &quot;SF_&quot; &amp; Right(&quot;000000&quot; &amp; lRandom, 6)
1184 Finally:
1185 GetTempName = SF_FileSystem._ConvertFromUrl(sFile)
1186 SF_Utils._ExitFunction(cstThisSub)
1187 Exit Function
1188 Catch:
1189 GoTo Finally
1190 End Function &apos; ScriptForge.SF_FileSystem.GetTempName
1192 REM -----------------------------------------------------------------------------
1193 Public Function HashFile(Optional ByVal FileName As Variant _
1194 , Optional ByVal Algorithm As Variant _
1195 ) As String
1196 &apos;&apos;&apos; Return an hexadecimal string representing a checksum of the given file
1197 &apos;&apos;&apos; Next algorithms are supported: MD5, SHA1, SHA224, SHA256, SHA384 and SHA512
1198 &apos;&apos;&apos; Args:
1199 &apos;&apos;&apos; FileName: a string representing a file
1200 &apos;&apos;&apos; Algorithm: The hashing algorithm to use
1201 &apos;&apos;&apos; Returns:
1202 &apos;&apos;&apos; The requested checksum as a string. Hexadecimal digits are lower-cased
1203 &apos;&apos;&apos; A zero-length string when an error occurred
1204 &apos;&apos;&apos; Exceptions:
1205 &apos;&apos;&apos; UNKNOWNFILEERROR The file does not exist of is a folder
1206 &apos;&apos;&apos; Example:
1207 &apos;&apos;&apos; Print SF_FileSystem.HashFile(&quot;C:\pagefile.sys&quot;, &quot;MD5&quot;)
1209 Dim sHash As String &apos; Return value
1210 Const cstPyHelper = &quot;$&quot; &amp; &quot;_SF_FileSystem__HashFile&quot;
1211 Const cstThisSub = &quot;FileSystem.HashFile&quot;
1212 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;
1214 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
1215 sHash = &quot;&quot;
1217 Check:
1218 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
1219 If Not SF_Utils._ValidateFile(FileName, &quot;FileName&quot;) Then GoTo Finally
1220 If Not SF_Utils._Validate(Algorithm, &quot;Algorithm&quot;, V_STRING _
1221 , Array(&quot;MD5&quot;, &quot;SHA1&quot;, &quot;SHA224&quot;, &quot;SHA256&quot;, &quot;SHA384&quot;, &quot;SHA512&quot;)) Then GoTo Finally
1222 End If
1224 Try:
1225 If SF_FileSystem.FileExists(FileName) Then
1226 With ScriptForge.SF_Session
1227 sHash = .ExecutePythonScript(.SCRIPTISSHARED, _SF_.PythonHelper &amp; cstPyHelper _
1228 , _ConvertFromUrl(FileName), LCase(Algorithm))
1229 End With
1230 Else
1231 GoTo CatchNotExists
1232 End If
1234 Finally:
1235 HashFile = sHash
1236 SF_Utils._ExitFunction(cstThisSub)
1237 Exit Function
1238 Catch:
1239 GoTo Finally
1240 CatchNotExists:
1241 SF_Exception.RaiseFatal(UNKNOWNFILEERROR, &quot;FileName&quot;, FileName)
1242 GoTo Finally
1243 End Function &apos; ScriptForge.SF_FileSystem.HashFile
1245 REM -----------------------------------------------------------------------------
1246 Public Function Methods() As Variant
1247 &apos;&apos;&apos; Return the list or methods of the FileSystem service as an array
1249 Methods = Array(&quot;BuildPath&quot; _
1250 , &quot;CompareFiles&quot; _
1251 , &quot;CopyFile&quot; _
1252 , &quot;CopyFolder&quot; _
1253 , &quot;CreateFolder&quot; _
1254 , &quot;CreateTextFile&quot; _
1255 , &quot;DeleteFile&quot; _
1256 , &quot;DeleteFolder&quot; _
1257 , &quot;ExtensionFolder&quot; _
1258 , &quot;FileExists&quot; _
1259 , &quot;Files&quot; _
1260 , &quot;FolderExists&quot; _
1261 , &quot;GetBaseName&quot; _
1262 , &quot;GetExtension&quot; _
1263 , &quot;GetFileLen&quot; _
1264 , &quot;GetFileModified&quot; _
1265 , &quot;GetName&quot; _
1266 , &quot;GetParentFolderName&quot; _
1267 , &quot;GetTempName&quot; _
1268 , &quot;HashFile&quot; _
1269 , &quot;MoveFile&quot; _
1270 , &quot;MoveFolder&quot; _
1271 , &quot;Normalize&quot; _
1272 , &quot;OpenTextFile&quot; _
1273 , &quot;PickFile&quot; _
1274 , &quot;PickFolder&quot; _
1275 , &quot;SubFolders&quot; _
1278 End Function &apos; ScriptForge.SF_FileSystem.Methods
1280 REM -----------------------------------------------------------------------------
1281 Public Function MoveFile(Optional ByVal Source As Variant _
1282 , Optional ByVal Destination As Variant _
1283 ) As Boolean
1284 &apos;&apos;&apos; Moves one or more files from one location to another
1285 &apos;&apos;&apos; Args:
1286 &apos;&apos;&apos; Source: FileName or NamePattern which can include wildcard characters, for one or more files to be moved
1287 &apos;&apos;&apos; Destination: FileName where the single Source file is to be moved
1288 &apos;&apos;&apos; If Source and Destination have the same parent folder MoveFile amounts to renaming the Source
1289 &apos;&apos;&apos; or FolderName where the multiple files from Source are to be moved
1290 &apos;&apos;&apos; If FolderName does not exist, it is created
1291 &apos;&apos;&apos; Anyway, wildcard characters are not allowed in Destination
1292 &apos;&apos;&apos; Returns:
1293 &apos;&apos;&apos; True if at least one file has been moved
1294 &apos;&apos;&apos; False if an error occurred
1295 &apos;&apos;&apos; An error also occurs if a source using wildcard characters doesn&apos;t match any files.
1296 &apos;&apos;&apos; The method stops on the first error it encounters
1297 &apos;&apos;&apos; No attempt is made to roll back or undo any changes made before an error occurs
1298 &apos;&apos;&apos; Exceptions:
1299 &apos;&apos;&apos; UNKNOWNFILEERROR Source does not exist
1300 &apos;&apos;&apos; UNKNOWNFOLDERERROR Source folder or Destination folder does not exist
1301 &apos;&apos;&apos; NOFILEMATCHERROR No file matches Source containing wildcards
1302 &apos;&apos;&apos; NOTAFOLDERERROR Destination is a file, not a folder
1303 &apos;&apos;&apos; NOTAFILEERROR Destination is a folder, not a file
1304 &apos;&apos;&apos; OVERWRITEERROR Destination can not be overwritten
1305 &apos;&apos;&apos; Example:
1306 &apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
1307 &apos;&apos;&apos; FSO.MoveFile(&quot;C:\Temp1\*.*&quot;, &quot;C:\Temp2\&quot;) &apos; Only files are moved, subfolders are not
1309 Dim bMove As Boolean &apos; Return value
1311 Const cstThisSub = &quot;FileSystem.MoveFile&quot;
1312 Const cstSubArgs = &quot;Source, Destination&quot;
1314 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
1315 bMove = False
1317 Check:
1318 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
1319 If Not SF_Utils._ValidateFile(Source, &quot;Source&quot;, True) Then GoTo Finally
1320 If Not SF_Utils._ValidateFile(Destination, &quot;Destination&quot;, False) Then GoTo Finally
1321 End If
1323 Try:
1324 bMove = SF_FileSystem._CopyMove(&quot;MoveFile&quot;, Source, Destination, False)
1326 Finally:
1327 MoveFile = bMove
1328 SF_Utils._ExitFunction(cstThisSub)
1329 Exit Function
1330 Catch:
1331 GoTo Finally
1332 End Function &apos; ScriptForge.SF_FileSystem.MoveFile
1334 REM -----------------------------------------------------------------------------
1335 Public Function MoveFolder(Optional ByVal Source As Variant _
1336 , Optional ByVal Destination As Variant _
1337 ) As Boolean
1338 &apos;&apos;&apos; Moves one or more folders from one location to another
1339 &apos;&apos;&apos; Args:
1340 &apos;&apos;&apos; Source: FolderName or NamePattern which can include wildcard characters, for one or more folders to be moved
1341 &apos;&apos;&apos; Destination: FolderName where the single Source folder is to be moved
1342 &apos;&apos;&apos; FolderName must not exist
1343 &apos;&apos;&apos; or FolderName where the multiple folders from Source are to be moved
1344 &apos;&apos;&apos; If FolderName does not exist, it is created
1345 &apos;&apos;&apos; Anyway, wildcard characters are not allowed in Destination
1346 &apos;&apos;&apos; Returns:
1347 &apos;&apos;&apos; True if at least one folder has been moved
1348 &apos;&apos;&apos; False if an error occurred
1349 &apos;&apos;&apos; An error also occurs if a source using wildcard characters doesn&apos;t match any folders.
1350 &apos;&apos;&apos; The method stops on the first error it encounters
1351 &apos;&apos;&apos; No attempt is made to roll back or undo any changes made before an error occurs
1352 &apos;&apos;&apos; Exceptions:
1353 &apos;&apos;&apos; UNKNOWNFILEERROR Source does not exist
1354 &apos;&apos;&apos; UNKNOWNFOLDERERROR Source folder or Destination folder does not exist
1355 &apos;&apos;&apos; NOFILEMATCHERROR No file matches Source containing wildcards
1356 &apos;&apos;&apos; NOTAFOLDERERROR Destination is a file, not a folder
1357 &apos;&apos;&apos; OVERWRITEERROR Destination can not be overwritten
1358 &apos;&apos;&apos; Example:
1359 &apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
1360 &apos;&apos;&apos; FSO.MoveFolder(&quot;C:\Temp1\*&quot;, &quot;C:\Temp2\&quot;)
1362 Dim bMove As Boolean &apos; Return value
1364 Const cstThisSub = &quot;FileSystem.MoveFolder&quot;
1365 Const cstSubArgs = &quot;Source, Destination&quot;
1367 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
1368 bMove = False
1370 Check:
1371 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
1372 If Not SF_Utils._ValidateFile(Source, &quot;Source&quot;, True) Then GoTo Finally
1373 If Not SF_Utils._ValidateFile(Destination, &quot;Destination&quot;, False) Then GoTo Finally
1374 End If
1376 Try:
1377 bMove = SF_FileSystem._CopyMove(&quot;MoveFolder&quot;, Source, Destination, False)
1379 Finally:
1380 MoveFolder = bMove
1381 SF_Utils._ExitFunction(cstThisSub)
1382 Exit Function
1383 Catch:
1384 GoTo Finally
1385 End Function &apos; ScriptForge.SF_FileSystem.MoveFolder
1387 REM -----------------------------------------------------------------------------
1388 Public Function Normalize(Optional ByVal FileName As Variant) As String
1389 &apos;&apos;&apos; Normalize a pathname by collapsing redundant separators and up-level references
1390 &apos;&apos;&apos; so that A//B, A/B/, A/./B and A/foo/../B all become A/B.
1391 &apos;&apos;&apos; On Windows, it converts forward slashes to backward slashes.
1392 &apos;&apos;&apos; Args:
1393 &apos;&apos;&apos; FileName: a string representing a file. The file may not exist.
1394 &apos;&apos;&apos; Returns:
1395 &apos;&apos;&apos; The normalized filename in filenaming notation
1396 &apos;&apos;&apos; Example:
1397 &apos;&apos;&apos; Print SF_FileSystem.Normalize(&quot;A/foo/../B/C/./D//E&quot;) &apos; A/B/C/D/E
1399 Dim sNorm As String &apos; Return value
1400 Const cstPyHelper = &quot;$&quot; &amp; &quot;_SF_FileSystem__Normalize&quot;
1401 Const cstThisSub = &quot;FileSystem.Normalize&quot;
1402 Const cstSubArgs = &quot;FileName&quot;
1404 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
1405 sNorm = &quot;&quot;
1407 Check:
1408 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
1409 If Not SF_Utils._ValidateFile(FileName, &quot;FileName&quot;) Then GoTo Finally
1410 End If
1412 Try:
1413 With ScriptForge.SF_Session
1414 sNorm = .ExecutePythonScript(.SCRIPTISSHARED, _SF_.PythonHelper &amp; cstPyHelper _
1415 , _ConvertFromUrl(FileName))
1416 &apos; The Python os.path expects and returns a file name in os notation
1417 If SF_FileSystem.FileNaming &lt;&gt; &quot;SYS&quot; Then sNorm = ConvertToUrl(sNorm)
1418 End With
1420 Finally:
1421 Normalize = sNorm
1422 SF_Utils._ExitFunction(cstThisSub)
1423 Exit Function
1424 Catch:
1425 GoTo Finally
1426 End Function &apos; ScriptForge.SF_FileSystem.Normalize
1428 REM -----------------------------------------------------------------------------
1429 Public Function OpenTextFile(Optional ByVal FileName As Variant _
1430 , Optional ByVal IOMode As Variant _
1431 , Optional ByVal Create As Variant _
1432 , Optional ByVal Encoding As Variant _
1433 ) As Object
1434 &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
1435 &apos;&apos;&apos; Args:
1436 &apos;&apos;&apos; FileName: Identifies the file to open
1437 &apos;&apos;&apos; IOMode: Indicates input/output mode. Can be one of three constants: ForReading, ForWriting, or ForAppending
1438 &apos;&apos;&apos; Create: Boolean value that indicates whether a new file can be created if the specified filename doesn&apos;t exist.
1439 &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)
1440 &apos;&apos;&apos; Encoding: The character set that should be used
1441 &apos;&apos;&apos; Use one of the Names listed in https://www.iana.org/assignments/character-sets/character-sets.xhtml
1442 &apos;&apos;&apos; Note that LibreOffice does not implement all existing sets
1443 &apos;&apos;&apos; Default = UTF-8
1444 &apos;&apos;&apos; Returns:
1445 &apos;&apos;&apos; An instance of the SF_TextStream class representing the opened file or a Null object if an error occurred
1446 &apos;&apos;&apos; The method does not check if the file is really a text file
1447 &apos;&apos;&apos; It doesn&apos;t check either if the given encoding is implemented in LibreOffice nor if it is the right one
1448 &apos;&apos;&apos; Exceptions:
1449 &apos;&apos;&apos; UNKNOWNFILEERROR File does not exist
1450 &apos;&apos;&apos; Example:
1451 &apos;&apos;&apos; Dim myFile As Object
1452 &apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
1453 &apos;&apos;&apos; Set myFile = FSO.OpenTextFile(&quot;C:\Temp\ThisFile.txt&quot;, FSO.ForReading)
1454 &apos;&apos;&apos; If Not IsNull(myFile) Then &apos; ... Go ahead with reading text lines
1456 Dim oTextStream As Object &apos; Return value
1457 Dim bExists As Boolean &apos; File to open does exist
1458 Const cstThisSub = &quot;FileSystem.OpenTextFile&quot;
1459 Const cstSubArgs = &quot;FileName, [IOMode=1], [Create=False], [Encoding=&quot;&quot;UTF-8&quot;&quot;]&quot;
1461 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
1462 Set oTextStream = Nothing
1464 Check:
1465 With SF_FileSystem
1466 If IsMissing(IOMode) Or IsEmpty(IOMode) Then IOMode = ForReading
1467 If IsMissing(Create) Or IsEmpty(Create) Then Create = False
1468 If IsMissing(Encoding) Or IsEmpty(Encoding) Then Encoding = &quot;UTF-8&quot;
1469 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
1470 If Not SF_Utils._ValidateFile(FileName, &quot;FileName&quot;) Then GoTo Finally
1471 If Not SF_Utils._Validate(IOMode, &quot;IOMode&quot;, V_NUMERIC _
1472 , Array(ForReading, ForWriting, ForAppending)) _
1473 Then GoTo Finally
1474 If Not SF_Utils._Validate(Create, &quot;Create&quot;, V_BOOLEAN) Then GoTo Finally
1475 If Not SF_Utils._Validate(Encoding, &quot;Encoding&quot;, V_STRING) Then GoTo Finally
1476 End If
1478 bExists = .FileExists(FileName)
1479 Select Case IOMode
1480 Case ForReading : If Not bExists Then GoTo CatchNotExists
1481 Case Else : If Not bExists And Not Create Then GoTo CatchNotExists
1482 End Select
1484 If IOMode = ForAppending And Not bExists Then IOMode = ForWriting
1485 End With
1487 Try:
1488 &apos; Create and initialize TextStream class instance
1489 Set oTextStream = New SF_TextStream
1490 With oTextStream
1491 .[Me] = oTextStream
1492 .[_Parent] = SF_FileSystem
1493 ._FileName = SF_FileSystem._ConvertToUrl(FileName)
1494 ._IOMode = IOMode
1495 ._Encoding = Encoding
1496 ._FileExists = bExists
1497 ._Initialize()
1498 End With
1500 Finally:
1501 Set OpenTextFile = oTextStream
1502 SF_Utils._ExitFunction(cstThisSub)
1503 Exit Function
1504 Catch:
1505 GoTo Finally
1506 CatchNotExists:
1507 SF_Exception.RaiseFatal(UNKNOWNFILEERROR, &quot;FileName&quot;, FileName)
1508 GoTo Finally
1509 End Function &apos; ScriptForge.SF_FileSystem.OpenTextFile
1511 REM -----------------------------------------------------------------------------
1512 Public Function PickFile(Optional ByVal DefaultFile As Variant _
1513 , Optional ByVal Mode As Variant _
1514 , Optional ByVal Filter As Variant _
1515 ) As String
1516 &apos;&apos;&apos; Returns the file selected with a FilePicker dialog box
1517 &apos;&apos;&apos; The mode, OPEN or SAVE, and the filter may be preset
1518 &apos;&apos;&apos; If mode = SAVE and the picked file exists, a warning message will be displayed
1519 &apos;&apos;&apos; Modified from Andrew Pitonyak&apos;s Base Macro Programming §10.4
1520 &apos;&apos;&apos; Args:
1521 &apos;&apos;&apos; DefaultFile: Folder part: the FolderName from which to start. Default = the last selected folder
1522 &apos;&apos;&apos; File part: the default file to open or save
1523 &apos;&apos;&apos; Mode: &quot;OPEN&quot; (input file) or &quot;SAVE&quot; (output file)
1524 &apos;&apos;&apos; Filter: by default only files having the given suffix will be displayed. Default = all suffixes
1525 &apos;&apos;&apos; The filter combo box will contain the given SuffixFilter (if not &quot;*&quot;) and &quot;*.*&quot;
1526 &apos;&apos;&apos; Returns:
1527 &apos;&apos;&apos; The selected FileName in URL format or &quot;&quot; if the dialog was cancelled
1528 &apos;&apos;&apos; Example:
1529 &apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
1530 &apos;&apos;&apos; FSO.PickFile(&quot;C:\&quot;, &quot;OPEN&quot;, &quot;txt&quot;) &apos; Only *.txt files are displayed
1532 Dim oFileDialog As Object &apos; com.sun.star.ui.dialogs.FilePicker
1533 Dim oFileAccess As object &apos; com.sun.star.ucb.SimpleFileAccess
1534 Dim oPath As Object &apos; com.sun.star.util.PathSettings
1535 Dim iAccept As Integer &apos; Result of dialog execution
1536 Dim sInitPath As String &apos; Current working directory
1537 Dim sBaseFile As String
1538 Dim iMode As Integer &apos; Numeric alias for SelectMode
1539 Dim sFile As String &apos; Return value
1541 Const cstThisSub = &quot;FileSystem.PickFile&quot;
1542 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;
1544 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
1545 sFile = &quot;&quot;
1547 Check:
1548 If IsMissing(DefaultFile) Or IsEmpty(DefaultFile) Then DefaultFile = &quot;&quot;
1549 If IsMissing(Mode) Or IsEmpty(Mode) Then Mode = &quot;OPEN&quot;
1550 If IsMissing(Filter) Or IsEmpty(Filter) Then Filter = &quot;&quot;
1551 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
1552 If Not SF_Utils._ValidateFile(DefaultFile, &quot;DefaultFile&quot;, , True) Then GoTo Finally
1553 If Not SF_Utils._Validate(Mode, &quot;Mode&quot;, V_STRING, Array(&quot;OPEN&quot;, &quot;SAVE&quot;)) Then GoTo Finally
1554 If Not SF_Utils._Validate(Filter, &quot;Filter&quot;, V_STRING) Then GoTo Finally
1555 End If
1556 DefaultFile = SF_FileSystem._ConvertToUrl(DefaultFile)
1558 Try:
1559 &apos; Derive numeric equivalent of the Mode argument: https://api.libreoffice.org/docs/idl/ref/TemplateDescription_8idl.html
1560 With com.sun.star.ui.dialogs.TemplateDescription
1561 If Mode = &quot;OPEN&quot; Then iMode = .FILEOPEN_SIMPLE Else iMode = .FILESAVE_AUTOEXTENSION
1562 End With
1564 &apos; Activate the filepicker dialog
1565 Set oFileDialog = SF_Utils._GetUNOService(&quot;FilePicker&quot;)
1566 With oFileDialog
1567 .Initialize(Array(iMode))
1569 &apos; Set filters
1570 If Len(Filter) &gt; 0 Then .appendFilter(&quot;*.&quot; &amp; Filter, &quot;*.&quot; &amp; Filter) &apos; Twice: required by API
1571 .appendFilter(&quot;*.*&quot;, &quot;*.*&quot;)
1572 If Len(Filter) &gt; 0 Then .setCurrentFilter(&quot;*.&quot; &amp; Filter) Else .setCurrentFilter(&quot;*.*&quot;)
1574 &apos; Set initial folder
1575 If Len(DefaultFile) = 0 Then &apos; TODO: SF_Session.WorkingFolder
1576 Set oPath = SF_Utils._GetUNOService(&quot;PathSettings&quot;)
1577 sInitPath = oPath.Work &apos; Probably My Documents
1578 Else
1579 sInitPath = SF_FileSystem._ParseUrl(ConvertToUrl(DefaultFile)).Path
1580 End If
1582 &apos; Set default values
1583 Set oFileAccess = SF_Utils._GetUNOService(&quot;FileAccess&quot;)
1584 If oFileAccess.exists(sInitPath) Then .SetDisplayDirectory(sInitPath)
1585 sBaseFile = SF_FileSystem.GetName(DefaultFile)
1586 .setDefaultName(sBaseFile)
1588 &apos; Get selected file
1589 iAccept = .Execute()
1590 If iAccept = com.sun.star.ui.dialogs.ExecutableDialogResults.OK Then sFile = .getSelectedFiles()(0)
1592 &apos; Do not reuse a FilePicker, side effects observed (a.o. TDF#154462)
1593 .dispose()
1594 End With
1596 Finally:
1597 PickFile = SF_FileSystem._ConvertFromUrl(sFile)
1598 SF_Utils._ExitFunction(cstThisSub)
1599 Exit Function
1600 Catch:
1601 GoTo Finally
1602 End Function &apos; ScriptForge.SF_FileSystem.PickFile
1604 REM -----------------------------------------------------------------------------
1605 Public Function PickFolder(Optional ByVal DefaultFolder As Variant _
1606 , Optional ByVal FreeText As Variant _
1607 ) As String
1608 &apos;&apos;&apos; Display a FolderPicker dialog box
1609 &apos;&apos;&apos; Args:
1610 &apos;&apos;&apos; DefaultFolder: the FolderName from which to start. Default = the last selected folder
1611 &apos;&apos;&apos; FreeText: text to display in the dialog. Default = &quot;&quot;
1612 &apos;&apos;&apos; Returns:
1613 &apos;&apos;&apos; The selected FolderName in URL or operating system format
1614 &apos;&apos;&apos; The zero-length string if the dialog was cancelled
1615 &apos;&apos;&apos; Example:
1616 &apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
1617 &apos;&apos;&apos; FSO.PickFolder(&quot;C:\&quot;, &quot;Choose a folder or press Cancel&quot;)
1619 Dim oFolderDialog As Object &apos; com.sun.star.ui.dialogs.FolderPicker
1620 Dim iAccept As Integer &apos; Value returned by the dialog (OK, Cancel, ..)
1621 Dim sFolder As String &apos; Return value &apos;
1623 Const cstThisSub = &quot;FileSystem.PickFolder&quot;
1624 Const cstSubArgs = &quot;[DefaultFolder=&quot;&quot;&quot;&quot;], [FreeText=&quot;&quot;&quot;&quot;]&quot;
1626 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
1627 sFolder = &quot;&quot;
1629 Check:
1630 If IsMissing(DefaultFolder) Or IsEmpty(DefaultFolder) Then DefaultFolder = &quot;&quot;
1631 If IsMissing(FreeText) Or IsEmpty(FreeText) Then FreeText = &quot;&quot;
1632 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
1633 If Not SF_Utils._ValidateFile(DefaultFolder, &quot;DefaultFolder&quot;, , True) Then GoTo Finally
1634 If Not SF_Utils._Validate(FreeText, &quot;FreeText&quot;, V_STRING) Then GoTo Finally
1635 End If
1636 DefaultFolder = SF_FileSystem._ConvertToUrl(DefaultFolder)
1638 Try:
1639 Set oFolderDialog = SF_Utils._GetUNOService(&quot;FolderPicker&quot;)
1640 If Not IsNull(oFolderDialog) Then
1641 With oFolderDialog
1642 If Len(DefaultFolder) &gt; 0 Then .DisplayDirectory = ConvertToUrl(DefaultFolder)
1643 .Description = FreeText
1644 iAccept = .Execute()
1645 &apos; https://api.libreoffice.org/docs/idl/ref/ExecutableDialogResults_8idl.html
1646 If iAccept = com.sun.star.ui.dialogs.ExecutableDialogResults.OK Then
1647 .DisplayDirectory = .Directory &apos; Set the next default initial folder to the selected one
1648 sFolder = .Directory &amp; &quot;/&quot;
1649 End If
1650 End With
1651 End If
1653 Finally:
1654 PickFolder = SF_FileSystem._ConvertFromUrl(sFolder)
1655 SF_Utils._ExitFunction(cstThisSub)
1656 Exit Function
1657 Catch:
1658 GoTo Finally
1659 End Function &apos; ScriptForge.SF_FileSystem.PickFolder
1661 REM -----------------------------------------------------------------------------
1662 Public Function Properties() As Variant
1663 &apos;&apos;&apos; Return the list or properties of the FileSystem module as an array
1665 Properties = Array( _
1666 &quot;ConfigFolder&quot; _
1667 , &quot;ExtensionsFolder&quot; _
1668 , &quot;FileNaming&quot; _
1669 , &quot;HomeFolder&quot; _
1670 , &quot;InstallFolder&quot; _
1671 , &quot;TemplatesFolder&quot; _
1672 , &quot;TemporaryFolder&quot; _
1673 , &quot;UserTemplatesFolder&quot; _
1676 End Function &apos; ScriptForge.SF_FileSystem.Properties
1678 REM -----------------------------------------------------------------------------
1679 Public Function SetProperty(Optional ByVal PropertyName As Variant _
1680 , Optional ByRef Value As Variant _
1681 ) As Boolean
1682 &apos;&apos;&apos; Set a new value to the given property
1683 &apos;&apos;&apos; Args:
1684 &apos;&apos;&apos; PropertyName: the name of the property as a string
1685 &apos;&apos;&apos; Value: its new value
1686 &apos;&apos;&apos; Exceptions
1687 &apos;&apos;&apos; ARGUMENTERROR The property does not exist
1689 Const cstThisSub = &quot;FileSystem.SetProperty&quot;
1690 Const cstSubArgs = &quot;PropertyName, Value&quot;
1692 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
1693 SetProperty = False
1695 Check:
1696 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
1697 If Not SF_Utils._Validate(PropertyName, &quot;PropertyName&quot;, V_STRING, Properties()) Then GoTo Catch
1698 End If
1700 Try:
1701 Select Case UCase(PropertyName)
1702 Case UCase(&quot;FileNaming&quot;) : FileNaming = Value
1703 Case Else
1704 End Select
1706 Finally:
1707 SF_Utils._ExitFunction(cstThisSub)
1708 Exit Function
1709 Catch:
1710 GoTo Finally
1711 End Function &apos; ScriptForge.SF_FileSystem.SetProperty
1713 REM -----------------------------------------------------------------------------
1714 Public Function SubFolders(Optional ByVal FolderName As Variant _
1715 , Optional ByVal Filter As Variant _
1716 ) As Variant
1717 &apos;&apos;&apos; Return an array of the FolderNames stored in the given folder. The folder must exist
1718 &apos;&apos;&apos; Args:
1719 &apos;&apos;&apos; FolderName: the folder to explore
1720 &apos;&apos;&apos; Filter: contains wildcards (&quot;?&quot; and &quot;*&quot;) to limit the list to the relevant folders (default = &quot;&quot;)
1721 &apos;&apos;&apos; Returns:
1722 &apos;&apos;&apos; An array of strings, each entry is the FolderName of an existing folder
1723 &apos;&apos;&apos; Exceptions:
1724 &apos;&apos;&apos; UNKNOWNFOLDERERROR Folder does not exist
1725 &apos;&apos;&apos; NOTAFOLDERERROR FolderName is a file, not a folder
1726 &apos;&apos;&apos; Example:
1727 &apos;&apos;&apos; Dim a As Variant
1728 &apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
1729 &apos;&apos;&apos; a = FSO.SubFolders(&quot;C:\Windows\&quot;)
1731 Dim vSubFolders As Variant &apos; Return value
1732 Dim oSfa As Object &apos; com.sun.star.ucb.SimpleFileAccess
1733 Dim sFolderName As String &apos; URL lias for FolderName
1734 Dim sFolder As String &apos; Single folder
1735 Dim i As Long
1737 Const cstThisSub = &quot;FileSystem.SubFolders&quot;
1738 Const cstSubArgs = &quot;FolderName, [Filter=&quot;&quot;&quot;&quot;]&quot;
1740 If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
1741 vSubFolders = Array()
1743 Check:
1744 If IsMissing(Filter) Or IsEmpty(Filter) Then Filter = &quot;&quot;
1745 If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
1746 If Not SF_Utils._ValidateFile(FolderName, &quot;FolderName&quot;) Then GoTo Finally
1747 If Not SF_Utils._Validate(Filter, &quot;Filter&quot;, V_STRING) Then GoTo Finally
1748 End If
1749 sFolderName = SF_FileSystem._ConvertToUrl(FolderName)
1750 If SF_FileSystem.FileExists(FolderName) Then GoTo CatchFile &apos; Must not be a file
1751 If Not SF_FileSystem.FolderExists(FolderName) Then GoTo CatchFolder &apos; Folder must exist
1753 Try:
1754 &apos; Get SubFolders
1755 Set oSfa = SF_Utils._GetUnoService(&quot;FileAccess&quot;)
1756 vSubFolders = oSfa.getFolderContents(sFolderName, True)
1757 &apos; List includes files; remove them or adjust notations of folders
1758 For i = 0 To UBound(vSubFolders)
1759 sFolder = SF_FileSystem._ConvertFromUrl(vSubFolders(i) &amp; &quot;/&quot;)
1760 If SF_FileSystem.FileExists(sFolder) Then vSubFolders(i) = &quot;&quot; Else vSubFolders(i) = sFolder
1761 &apos; Reduce list to those passing the filter
1762 If Len(Filter) &gt; 0 And Len(vSubFolders(i)) &gt; 0 Then
1763 sFolder = SF_FileSystem.GetName(vSubFolders(i))
1764 If Not SF_String.IsLike(sFolder, Filter) Then vSubFolders(i) = &quot;&quot;
1765 End If
1766 Next i
1767 vSubFolders = SF_Array.TrimArray(vSubFolders)
1769 Finally:
1770 SubFolders = vSubFolders
1771 SF_Utils._ExitFunction(cstThisSub)
1772 Exit Function
1773 Catch:
1774 GoTo Finally
1775 CatchFile:
1776 SF_Exception.RaiseFatal(NOTAFOLDERERROR, &quot;FolderName&quot;, FolderName)
1777 GoTo Finally
1778 CatchFolder:
1779 SF_Exception.RaiseFatal(UNKNOWNFOLDERERROR, &quot;FolderName&quot;, FolderName)
1780 GoTo Finally
1781 End Function &apos; ScriptForge.SF_FileSystem.SubFolders
1783 REM =========================================================== PRIVATE FUNCTIONS
1785 REM -----------------------------------------------------------------------------
1786 Private Function _ConvertFromUrl(psFile) As String
1787 &apos;&apos;&apos; Execute the builtin ConvertFromUrl function only when relevant
1788 &apos;&apos;&apos; i.e. when FileNaming (how arguments and return values are provided) = &quot;SYS&quot;
1789 &apos;&apos;&apos; Called at the bottom of methods returning file names
1790 &apos;&apos;&apos; Remark: psFile might contain wildcards
1792 Const cstQuestion = &quot;$QUESTION$&quot;, cstStar = &quot;$STAR$&quot; &apos; Special tokens to replace wildcards
1794 If SF_FileSystem.FileNaming = &quot;SYS&quot; Then
1795 _ConvertFromUrl = Replace(Replace( _
1796 ConvertFromUrl(Replace(Replace(psFile, &quot;?&quot;, cstQuestion), &quot;*&quot;, cstStar)) _
1797 , cstQuestion, &quot;?&quot;), cstStar, &quot;*&quot;)
1798 Else
1799 _ConvertFromUrl = psFile
1800 End If
1802 End Function &apos; ScriptForge.FileSystem._ConvertFromUrl
1804 REM -----------------------------------------------------------------------------
1805 Private Function _ConvertToUrl(psFile) As String
1806 &apos;&apos;&apos; Execute the builtin ConvertToUrl function only when relevant
1807 &apos;&apos;&apos; i.e. when FileNaming (how arguments and return values are provided) &lt;&gt; &quot;URL&quot;
1808 &apos;&apos;&apos; Called at the top of methods receiving file names as arguments
1809 &apos;&apos;&apos; Remark: psFile might contain wildcards
1811 If SF_FileSystem.FileNaming = &quot;URL&quot; Then
1812 _ConvertToUrl = psFile
1813 Else
1814 &apos; ConvertToUrl encodes &quot;?&quot;
1815 _ConvertToUrl = Replace(ConvertToUrl(psFile), &quot;%3F&quot;, &quot;?&quot;)
1816 End If
1818 End Function &apos; ScriptForge.FileSystem._ConvertToUrl
1820 REM -----------------------------------------------------------------------------
1821 Private Function _CopyMove(psMethod As String _
1822 , psSource As String _
1823 , psDestination As String _
1824 , pbOverWrite As Boolean _
1825 ) As Boolean
1826 &apos;&apos;&apos; Checks the arguments and executes the given method
1827 &apos;&apos;&apos; Args:
1828 &apos;&apos;&apos; psMethod: CopyFile/CopyFolder or MoveFile/MoveFolder
1829 &apos;&apos;&apos; psSource: Either File/FolderName
1830 &apos;&apos;&apos; or NamePattern which can include wildcard characters, for one or more files/folders to be copied
1831 &apos;&apos;&apos; psDestination: FileName or FolderName for copy/move of a single file/folder
1832 &apos;&apos;&apos; Otherwise a destination FolderName. If it does not exist, it is created
1833 &apos;&apos;&apos; pbOverWrite: If True, files/folders may be overwritten
1834 &apos;&apos;&apos; Must be False for Move operations
1835 &apos;&apos;&apos; Next checks are done:
1836 &apos;&apos;&apos; With wildcards (multiple files/folders):
1837 &apos;&apos;&apos; - Parent folder of source must exist
1838 &apos;&apos;&apos; - Destination must not be a file
1839 &apos;&apos;&apos; - Parent folder of Destination must exist
1840 &apos;&apos;&apos; - If the Destination folder does not exist a new folder is created,
1841 &apos;&apos;&apos; - At least one file matches the wildcards expression
1842 &apos;&apos;&apos; - Destination files/folder must not exist if pbOverWrite = False
1843 &apos;&apos;&apos; - Destination files/folders must not have the read-only attribute set
1844 &apos;&apos;&apos; - Destination files must not be folders, destination folders must not be files
1845 &apos;&apos;&apos; Without wildcards (single file/folder):
1846 &apos;&apos;&apos; - Source file/folder must exist and be a file/folder
1847 &apos;&apos;&apos; - Parent folder of Destination must exist
1848 &apos;&apos;&apos; - Destination must not be an existing folder/file
1849 &apos;&apos;&apos; - Destination file/folder must not exist if pbOverWrite = False
1850 &apos;&apos;&apos; - Destination file must not have the read-only attribute set
1852 Dim bCopyMove As Boolean &apos; Return value
1853 Dim bCopy As Boolean &apos; True if Copy, False if Move
1854 Dim bFile As Boolean &apos; True if File, False if Folder
1855 Dim oSfa As Object &apos; com.sun.star.ucb.SimpleFileAccess
1856 Dim bWildCards As Boolean &apos; True if wildcards found in Source
1857 Dim bCreateFolder As Boolean &apos; True when the destination folder should be created
1858 Dim bDestExists As Boolean &apos; True if destination exists
1859 Dim sSourceUrl As String &apos; Alias for Source
1860 Dim sDestinationUrl As String &apos; Alias for Destination
1861 Dim sDestinationFile As String &apos; Destination FileName
1862 Dim sParentFolder As String &apos; Parent folder of Source
1863 Dim vFiles As Variant &apos; Array of candidates for copy/move
1864 Dim sFile As String &apos; Single file/folder
1865 Dim sName As String &apos; Name (last component) of file
1866 Dim i As Long
1868 &apos; Error handling left to calling routine
1869 bCopyMove = False
1870 bCopy = ( Left(psMethod, 4) = &quot;Copy&quot; )
1871 bFile = ( Right(psMethod, 4) = &quot;File&quot; )
1872 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;
1873 bDestExists = False
1875 With SF_FileSystem
1877 Check:
1878 If bWildCards Then
1879 sParentFolder = .GetParentFolderName(psSource)
1880 If Not .FolderExists(sParentFolder) Then GoTo CatchNoMatch
1881 If .FileExists(psDestination) Then GoTo CatchFileNotFolder
1882 If Not .FolderExists(.GetParentFolderName(psDestination)) Then GoTo CatchDestFolderNotExists
1883 bCreateFolder = Not .FolderExists(psDestination)
1884 Else
1885 Select Case bFile
1886 Case True &apos; File
1887 If Not .FileExists(psSource) Then GoTo CatchFileNotExists
1888 If Not .FolderExists(.GetParentFolderName(psDestination)) Then GoTo CatchSourceFolderNotExists
1889 If .FolderExists(psDestination) Then GoTo CatchFolderNotFile
1890 bDestExists = .FileExists(psDestination)
1891 If pbOverWrite = False And bDestExists = True Then GoTo CatchDestinationExists
1892 bCreateFolder = False
1893 Case False &apos; Folder
1894 If Not .FolderExists(psSource) Then GoTo CatchSourceFolderNotExists
1895 If Not .FolderExists(.GetParentFolderName(psDestination)) Then GoTo CatchDestFolderNotExists
1896 If .FileExists(psDestination) Then GoTo CatchFileNotFolder
1897 bDestExists = .FolderExists(psDestination)
1898 If pbOverWrite = False And bDestExists Then GoTo CatchDestinationExists
1899 bCreateFolder = Not bDestExists
1900 End Select
1901 End If
1903 Try:
1904 Set oSfa = SF_Utils._GetUnoService(&quot;FileAccess&quot;)
1905 If bWildCards Then
1906 If bFile Then vFiles = .Files(sParentFolder, .GetName(psSource)) Else vFiles = .SubFolders(sParentFolder, .GetName(psSource))
1907 If UBound(vFiles) &lt; 0 Then GoTo CatchNoMatch
1908 &apos; Go through the candidates
1909 If bCreateFolder Then .CreateFolder(psDestination)
1910 For i = 0 To UBound(vFiles)
1911 sFile = vFiles(i)
1912 sDestinationFile = .BuildPath(psDestination, .GetName(sFile))
1913 If bFile Then bDestExists = .FileExists(sDestinationFile) Else bDestExists = .FolderExists(sDestinationFile)
1914 If pbOverWrite = False Then
1915 If bDestExists Then GoTo CatchDestinationExists
1916 If .FolderExists(sDestinationFile) Then GoTo CatchDestinationExists
1917 End If
1918 sSourceUrl = ._ConvertToUrl(sFile)
1919 sDestinationUrl = ._ConvertToUrl(sDestinationFile)
1920 If bDestExists Then
1921 If oSfa.isReadOnly(sDestinationUrl) Then GoTo CatchDestinationReadOnly
1922 End If
1923 Select Case bCopy
1924 Case True : oSfa.copy(sSourceUrl, sDestinationUrl)
1925 Case False : oSfa.move(sSourceUrl, sDestinationUrl)
1926 End Select
1927 Next i
1928 Else
1929 sSourceUrl = ._ConvertToUrl(psSource)
1930 sDestinationUrl = ._ConvertToUrl(psDestination)
1931 If bDestExists Then
1932 If oSfa.isReadOnly(sDestinationUrl) Then GoTo CatchDestinationReadOnly
1933 End If
1934 If bCreateFolder Then .CreateFolder(psDestination)
1935 Select Case bCopy
1936 Case True : oSfa.copy(sSourceUrl, sDestinationUrl)
1937 Case False : oSfa.move(sSourceUrl, sDestinationUrl)
1938 End Select
1939 End If
1941 End With
1943 bCopyMove = True
1945 Finally:
1946 _CopyMove = bCopyMove
1947 Exit Function
1948 CatchFileNotExists:
1949 SF_Exception.RaiseFatal(UNKNOWNFILEERROR, &quot;Source&quot;, psSource)
1950 GoTo Finally
1951 CatchSourceFolderNotExists:
1952 SF_Exception.RaiseFatal(UNKNOWNFOLDERERROR, &quot;Source&quot;, psSource)
1953 GoTo Finally
1954 CatchDestFolderNotExists:
1955 SF_Exception.RaiseFatal(UNKNOWNFOLDERERROR, &quot;Destination&quot;, psDestination)
1956 GoTo Finally
1957 CatchFolderNotFile:
1958 SF_Exception.RaiseFatal(NOTAFILEERROR, &quot;Destination&quot;, psDestination)
1959 GoTo Finally
1960 CatchDestinationExists:
1961 SF_Exception.RaiseFatal(OVERWRITEERROR, &quot;Destination&quot;, psDestination)
1962 GoTo Finally
1963 CatchNoMatch:
1964 SF_Exception.RaiseFatal(NOFILEMATCHERROR, &quot;Source&quot;, psSource)
1965 GoTo Finally
1966 CatchFileNotFolder:
1967 SF_Exception.RaiseFatal(NOTAFOLDERERROR, &quot;Destination&quot;, psDestination)
1968 GoTo Finally
1969 CatchDestinationReadOnly:
1970 SF_Exception.RaiseFatal(READONLYERROR, &quot;Destination&quot;, Iif(bWildCards, sDestinationFile, psDestination))
1971 GoTo Finally
1972 End Function &apos; ScriptForge.SF_FileSystem._CopyMove
1974 REM -----------------------------------------------------------------------------
1975 Public Function _CountTextLines(ByVal psFileName As String _
1976 , Optional ByVal pbIncludeBlanks As Boolean _
1977 ) As Long
1978 &apos;&apos;&apos; Convenient function to count the number of lines in a textfile
1979 &apos;&apos;&apos; Args:
1980 &apos;&apos;&apos; psFileName: the file in FileNaming notation
1981 &apos;&apos;&apos; pbIncludeBlanks: if True (default), zero-length lines are included
1982 &apos;&apos;&apos; Returns:
1983 &apos;&apos;&apos; The number of lines, f.i. to ease array sizing. -1 if file reading error
1985 Dim lLines As Long &apos; Return value
1986 Dim oFile As Object &apos; File handler
1987 Dim sLine As String &apos; The last line read
1989 Try:
1990 lLines = 0
1991 If IsMissing(pbIncludeBlanks) Then pbIncludeBlanks = True
1992 Set oFile = SF_FileSystem.OpenTextFile(psFileName, ForReading)
1993 With oFile
1994 If Not IsNull(oFile) Then
1995 Do While Not .AtEndOfStream
1996 sLine = .ReadLine()
1997 lLines = lLines + Iif(Len(sLine) &gt; 0 Or pbIncludeBlanks, 1, 0)
1998 Loop
1999 End If
2000 .CloseFile()
2001 Set oFile = .Dispose()
2002 End With
2004 Finally:
2005 _CountTextLines = lLines
2006 Exit Function
2007 End Function &apos; ScriptForge.SF_FileSystem._CountTextLines
2009 REM -----------------------------------------------------------------------------
2010 Private Function _Delete(psMethod As String _
2011 , psFile As String _
2012 ) As Boolean
2013 &apos;&apos;&apos; Checks the argument and executes the given psMethod
2014 &apos;&apos;&apos; Args:
2015 &apos;&apos;&apos; psMethod: CopyFile/CopyFolder or MoveFile/MoveFolder
2016 &apos;&apos;&apos; psFile: Either File/FolderName
2017 &apos;&apos;&apos; or NamePattern which can include wildcard characters, for one or more files/folders to be deleted
2018 &apos;&apos;&apos; Next checks are done:
2019 &apos;&apos;&apos; With wildcards (multiple files/folders):
2020 &apos;&apos;&apos; - Parent folder of File must exist
2021 &apos;&apos;&apos; - At least one file matches the wildcards expression
2022 &apos;&apos;&apos; - Files or folders to delete must not have the read-only attribute set
2023 &apos;&apos;&apos; Without wildcards (single file/folder):
2024 &apos;&apos;&apos; - File/folder must exist and be a file/folder
2025 &apos;&apos;&apos; - A file or folder to delete must not have the read-only attribute set
2027 Dim bDelete As Boolean &apos; Return value
2028 Dim bFile As Boolean &apos; True if File, False if Folder
2029 Dim oSfa As Object &apos; com.sun.star.ucb.SimpleFileAccess
2030 Dim bWildCards As Boolean &apos; True if wildcards found in File
2031 Dim sFileUrl As String &apos; Alias for File
2032 Dim sParentFolder As String &apos; Parent folder of File
2033 Dim vFiles As Variant &apos; Array of candidates for deletion
2034 Dim sFile As String &apos; Single file/folder
2035 Dim sName As String &apos; Name (last component) of file
2036 Dim i As Long
2038 &apos; Error handling left to calling routine
2039 bDelete = False
2040 bFile = ( Right(psMethod, 4) = &quot;File&quot; )
2041 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;
2043 With SF_FileSystem
2045 Check:
2046 If bWildCards Then
2047 sParentFolder = .GetParentFolderName(psFile)
2048 If Not .FolderExists(sParentFolder) Then GoTo CatchNoMatch
2049 Else
2050 Select Case bFile
2051 Case True &apos; File
2052 If .FolderExists(psFile) Then GoTo CatchFolderNotFile
2053 If Not .FileExists(psFile) Then GoTo CatchFileNotExists
2054 Case False &apos; Folder
2055 If .FileExists(psFile) Then GoTo CatchFileNotFolder
2056 If Not .FolderExists(psFile) Then GoTo CatchFolderNotExists
2057 End Select
2058 End If
2060 Try:
2061 Set oSfa = SF_Utils._GetUnoService(&quot;FileAccess&quot;)
2062 If bWildCards Then
2063 If bFile Then vFiles = .Files(sParentFolder) Else vFiles = .SubFolders(sParentFolder)
2064 &apos; Select candidates
2065 For i = 0 To UBound(vFiles)
2066 If Not SF_String.IsLike(.GetName(vFiles(i)), .GetName(psFile)) Then vFiles(i) = &quot;&quot;
2067 Next i
2068 vFiles = SF_Array.TrimArray(vFiles)
2069 If UBound(vFiles) &lt; 0 Then GoTo CatchNoMatch
2070 &apos; Go through the candidates
2071 For i = 0 To UBound(vFiles)
2072 sFile = vFiles(i)
2073 sFileUrl = ._ConvertToUrl(sFile)
2074 If oSfa.isReadOnly(sFileUrl) Then GoTo CatchReadOnly
2075 oSfa.kill(sFileUrl)
2076 Next i
2077 Else
2078 sFileUrl = ._ConvertToUrl(psFile)
2079 If oSfa.isReadOnly(sFileUrl) Then GoTo CatchReadOnly
2080 oSfa.kill(sFileUrl)
2081 End If
2083 End With
2085 bDelete = True
2087 Finally:
2088 _Delete = bDelete
2089 Exit Function
2090 CatchFolderNotExists:
2091 SF_Exception.RaiseFatal(UNKNOWNFOLDERERROR, &quot;FolderName&quot;, psFile)
2092 GoTo Finally
2093 CatchFileNotExists:
2094 SF_Exception.RaiseFatal(UNKNOWNFILEERROR, &quot;FileName&quot;, psFile)
2095 GoTo Finally
2096 CatchFolderNotFile:
2097 SF_Exception.RaiseFatal(NOTAFILEERROR, &quot;FileName&quot;, psFile)
2098 GoTo Finally
2099 CatchNoMatch:
2100 SF_Exception.RaiseFatal(NOFILEMATCHERROR, Iif(bFile, &quot;FileName&quot;, &quot;FolderName&quot;), psFile)
2101 GoTo Finally
2102 CatchFileNotFolder:
2103 SF_Exception.RaiseFatal(NOTAFOLDERERROR, &quot;FolderName&quot;, psFile)
2104 GoTo Finally
2105 CatchReadOnly:
2106 SF_Exception.RaiseFatal(READONLYERROR, Iif(bFile, &quot;FileName&quot;, &quot;FolderName&quot;), Iif(bWildCards, sFile, psFile))
2107 GoTo Finally
2108 End Function &apos; ScriptForge.SF_FileSystem._Delete
2110 REM -----------------------------------------------------------------------------
2111 Private Function _GetConfigFolder(ByVal psFolder As String) As String
2112 &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
2113 &apos;&apos;&apos; inst =&gt; Installation path of LibreOffice
2114 &apos;&apos;&apos; prog =&gt; Program path of LibreOffice
2115 &apos;&apos;&apos; user =&gt; The user installation/config directory
2116 &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
2117 &apos;&apos;&apos; home =&gt; The home directory of the user. Under Unix this would be the home- directory.
2118 &apos;&apos;&apos; Under Windows this would be the CSIDL_PERSONAL directory, for example &quot;Documents and Settings\&lt;username&gt;\Documents&quot;
2119 &apos;&apos;&apos; temp =&gt; The current temporary directory
2121 Dim oSubst As Object &apos; com.sun.star.util.PathSubstitution
2122 Dim sConfig As String &apos; Return value
2124 sConfig = &quot;&quot;
2125 Set oSubst = SF_Utils._GetUNOService(&quot;PathSubstitution&quot;)
2126 If Not IsNull(oSubst) Then sConfig = oSubst.getSubstituteVariableValue(&quot;$(&quot; &amp; psFolder &amp; &quot;)&quot;) &amp; &quot;/&quot;
2128 _GetConfigFolder = SF_FileSystem._ConvertFromUrl(sConfig)
2130 End Function &apos; ScriptForge.FileSystem._GetConfigFolder
2132 REM -----------------------------------------------------------------------------
2133 Public Function _ParseUrl(psUrl As String) As Object
2134 &apos;&apos;&apos; Returns a com.sun.star.util.URL structure based on the argument
2136 Dim oParse As Object &apos; com.sun.star.util.URLTransformer
2137 Dim bParsed As Boolean &apos; True if parsing is successful
2138 Dim oUrl As New com.sun.star.util.URL &apos; Return value
2140 oUrl.Complete = psUrl
2141 Set oParse = SF_Utils._GetUNOService(&quot;URLTransformer&quot;)
2142 bParsed = oParse.parseStrict(oUrl, &quot;&quot;)
2143 If bParsed Then oUrl.Path = ConvertToUrl(oUrl.Path)
2145 Set _ParseUrl = oUrl
2147 End Function &apos; ScriptForge.SF_FileSystem._ParseUrl
2149 REM -----------------------------------------------------------------------------
2150 Public Function _SFInstallFolder() As String
2151 &apos;&apos;&apos; Returns the installation folder of the ScriptForge library
2152 &apos;&apos;&apos; Either:
2153 &apos;&apos;&apos; - The library is present in [My Macros &amp; Dialogs]
2154 &apos;&apos;&apos; ($config)/basic/ScriptForge
2155 &apos;&apos;&apos; - The library is present in [LibreOffice Macros &amp; Dialogs]
2156 &apos;&apos;&apos; ($install)/share/basic/ScriptForge
2158 Dim sFolder As String &apos; Folder
2160 _SFInstallFolder = &quot;&quot;
2162 sFolder = BuildPath(ConfigFolder, &quot;basic/ScriptForge&quot;)
2163 If Not FolderExists(sFolder) Then
2164 sFolder = BuildPath(InstallFolder, &quot;share/basic/ScriptForge&quot;)
2165 If Not FolderExists(sFolder) Then Exit Function
2166 End If
2168 _SFInstallFolder = _ConvertFromUrl(sFolder)
2170 End Function &apos; ScriptForge.SF_FileSystem._SFInstallFolder
2172 REM ============================================ END OF SCRIPTFORGE.SF_FileSystem
2173 </script:module>