summaryrefslogtreecommitdiffstats
path: root/wizards/source/scriptforge/SF_FileSystem.xba
diff options
context:
space:
mode:
Diffstat (limited to 'wizards/source/scriptforge/SF_FileSystem.xba')
-rw-r--r--wizards/source/scriptforge/SF_FileSystem.xba2128
1 files changed, 2128 insertions, 0 deletions
diff --git a/wizards/source/scriptforge/SF_FileSystem.xba b/wizards/source/scriptforge/SF_FileSystem.xba
new file mode 100644
index 000000000..39ea4888e
--- /dev/null
+++ b/wizards/source/scriptforge/SF_FileSystem.xba
@@ -0,0 +1,2128 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
+<script:module xmlns:script="http://openoffice.org/2000/script" script:name="SF_FileSystem" script:language="StarBasic" script:moduleType="normal">REM =======================================================================================================================
+REM === The ScriptForge library and its associated libraries are part of the LibreOffice project. ===
+REM === Full documentation is available on https://help.libreoffice.org/ ===
+REM =======================================================================================================================
+
+Option Compatible
+Option Explicit
+
+&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;
+&apos;&apos;&apos; SF_FileSystem
+&apos;&apos;&apos; =============
+&apos;&apos;&apos; Class implementing the file system service
+&apos;&apos;&apos; for common file and folder handling routines
+&apos;&apos;&apos; Including copy and move of files and folders, with or without wildcards
+&apos;&apos;&apos; The design choices are largely inspired by
+&apos;&apos;&apos; https://docs.microsoft.com/en-us/office/vba/language/reference/user-interface-help/filesystemobject-object
+&apos;&apos;&apos; The File and Folder classes have been found redundant with the current class and have not been implemented
+&apos;&apos;&apos; The implementation is mainly based on the XSimpleFileAccess UNO interface
+&apos;&apos;&apos; https://api.libreoffice.org/docs/idl/ref/interfacecom_1_1sun_1_1star_1_1ucb_1_1XSimpleFileAccess.html
+&apos;&apos;&apos;
+&apos;&apos;&apos; Subclasses:
+&apos;&apos;&apos; SF_TextStream
+&apos;&apos;&apos;
+&apos;&apos;&apos; Definitions:
+&apos;&apos;&apos; File and folder names may be expressed either in the (preferable because portable) URL form
+&apos;&apos;&apos; or in the more usual operating system notation (e.g. C:\... for Windows)
+&apos;&apos;&apos; The notation, both for arguments and for returned values
+&apos;&apos;&apos; is determined by the FileNaming property: either &quot;URL&quot; (default) or &quot;SYS&quot;
+&apos;&apos;&apos;
+&apos;&apos;&apos; FileName: the full name of the file including the path without any ending path separator
+&apos;&apos;&apos; FolderName: the full name of the folder including the path and the ending path separator
+&apos;&apos;&apos; Name: the last component of the File- or FolderName including its extension
+&apos;&apos;&apos; BaseName: the last component of the File- or FolderName without its extension
+&apos;&apos;&apos; NamePattern: any of the above names containing wildcards in its last component
+&apos;&apos;&apos; Admitted wildcards are: the &quot;?&quot; represents any single character
+&apos;&apos;&apos; the &quot;*&quot; represents zero, one, or multiple characters
+&apos;&apos;&apos;
+&apos;&apos;&apos; Service invocation example:
+&apos;&apos;&apos; Dim FSO As Variant
+&apos;&apos;&apos; Set FSO = CreateScriptService(&quot;FileSystem&quot;)
+&apos;&apos;&apos;
+&apos;&apos;&apos; Detailed user documentation:
+&apos;&apos;&apos; https://help.libreoffice.org/latest/en-US/text/sbasic/shared/03/sf_filesystem.html?DbPAR=BASIC
+&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;
+
+REM ================================================================== EXCEPTIONS
+
+Const UNKNOWNFILEERROR = &quot;UNKNOWNFILEERROR&quot; &apos; Source file does not exist
+Const UNKNOWNFOLDERERROR = &quot;UNKNOWNFOLDERERROR&quot; &apos; Source folder or Destination folder does not exist
+Const NOTAFILEERROR = &quot;NOTAFILEERROR&quot; &apos; Destination is a folder, not a file
+Const NOTAFOLDERERROR = &quot;NOTAFOLDERERROR&quot; &apos; Destination is a file, not a folder
+Const OVERWRITEERROR = &quot;OVERWRITEERROR&quot; &apos; Destination can not be overwritten
+Const READONLYERROR = &quot;READONLYERROR&quot; &apos; Destination has its read-only attribute set
+Const NOFILEMATCHERROR = &quot;NOFILEMATCHFOUND&quot; &apos; No file matches Source containing wildcards
+Const FOLDERCREATIONERROR = &quot;FOLDERCREATIONERROR&quot; &apos; FolderName is an existing folder or file
+
+REM ============================================================ MODULE CONSTANTS
+
+&apos;&apos;&apos; TextStream open modes
+Const cstForReading = 1
+Const cstForWriting = 2
+Const cstForAppending = 8
+
+REM ===================================================== CONSTRUCTOR/DESTRUCTOR
+
+REM -----------------------------------------------------------------------------
+Public Function Dispose() As Variant
+ Set Dispose = Nothing
+End Function &apos; ScriptForge.SF_FileSystem Explicit destructor
+
+REM ================================================================== PROPERTIES
+
+REM -----------------------------------------------------------------------------
+Property Get ConfigFolder() As String
+&apos;&apos;&apos; Return the configuration folder of LibreOffice
+
+Const cstThisSub = &quot;FileSystem.getConfigFolder&quot;
+
+ SF_Utils._EnterFunction(cstThisSub)
+ ConfigFolder = SF_FileSystem._GetConfigFolder(&quot;user&quot;)
+ SF_Utils._ExitFunction(cstThisSub)
+
+End Property &apos; ScriptForge.SF_FileSystem.ConfigFolder
+
+REM -----------------------------------------------------------------------------
+Property Get ExtensionsFolder() As String
+&apos;&apos;&apos; Return the folder containing the extensions installed for the current user
+
+Dim oMacro As Object &apos; /singletons/com.sun.star.util.theMacroExpander
+Const cstThisSub = &quot;FileSystem.getExtensionsFolder&quot;
+
+ SF_Utils._EnterFunction(cstThisSub)
+ Set oMacro = SF_Utils._GetUNOService(&quot;MacroExpander&quot;)
+ ExtensionsFolder = SF_FileSystem._ConvertFromUrl(oMacro.ExpandMacros(&quot;$UNO_USER_PACKAGES_CACHE&quot;) &amp; &quot;/&quot;)
+ SF_Utils._ExitFunction(cstThisSub)
+
+End Property &apos; ScriptForge.SF_FileSystem.ExtensionsFolder
+
+REM -----------------------------------------------------------------------------
+Property Get FileNaming() As Variant
+&apos;&apos;&apos; Return the current files and folder notation, either &quot;ANY&quot;, &quot;URL&quot; or &quot;SYS&quot;
+&apos;&apos;&apos; &quot;ANY&quot;: methods receive either URL or native file names, but always return URL file names
+&apos;&apos;&apos; &quot;URL&quot;: methods expect URL arguments and return URL strings (when relevant)
+&apos;&apos;&apos; &quot;SYS&quot;: idem but operating system notation
+
+Const cstThisSub = &quot;FileSystem.getFileNaming&quot;
+ SF_Utils._EnterFunction(cstThisSub)
+ FileNaming = _SF_.FileSystemNaming
+ SF_Utils._ExitFunction(cstThisSub)
+
+End Property &apos; ScriptForge.SF_FileSystem.FileNaming (get)
+
+REM -----------------------------------------------------------------------------
+Property Let FileNaming(ByVal pvNotation As Variant)
+&apos;&apos;&apos; Set the files and folders notation: &quot;ANY&quot;, &quot;URL&quot; or &quot;SYS&quot;
+
+Const cstThisSub = &quot;FileSystem.setFileNaming&quot;
+ SF_Utils._EnterFunction(cstThisSub)
+ If VarType(pvNotation) = V_STRING Then
+ Select Case UCase(pvNotation)
+ Case &quot;ANY&quot;, &quot;URL&quot;, &quot;SYS&quot; : _SF_.FileSystemNaming = UCase(pvNotation)
+ Case Else &apos; Unchanged
+ End Select
+ End If
+ SF_Utils._ExitFunction(cstThisSub)
+
+End Property &apos; ScriptForge.SF_FileSystem.FileNaming (let)
+
+REM -----------------------------------------------------------------------------
+Property Get ForAppending As Integer
+&apos;&apos;&apos; Convenient constant (see documentation)
+ ForAppending = cstForAppending
+End Property &apos; ScriptForge.SF_FileSystem.ForAppending
+
+REM -----------------------------------------------------------------------------
+Property Get ForReading As Integer
+&apos;&apos;&apos; Convenient constant (see documentation)
+ ForReading = cstForReading
+End Property &apos; ScriptForge.SF_FileSystem.ForReading
+
+REM -----------------------------------------------------------------------------
+Property Get ForWriting As Integer
+&apos;&apos;&apos; Convenient constant (see documentation)
+ ForWriting = cstForWriting
+End Property &apos; ScriptForge.SF_FileSystem.ForWriting
+
+REM -----------------------------------------------------------------------------
+Property Get HomeFolder() As String
+&apos;&apos;&apos; Return the user home folder
+
+Const cstThisSub = &quot;FileSystem.getHomeFolder&quot;
+
+ SF_Utils._EnterFunction(cstThisSub)
+ HomeFolder = SF_FileSystem._GetConfigFolder(&quot;home&quot;)
+ SF_Utils._ExitFunction(cstThisSub)
+
+End Property &apos; ScriptForge.SF_FileSystem.HomeFolder
+
+REM -----------------------------------------------------------------------------
+Property Get InstallFolder() As String
+&apos;&apos;&apos; Return the installation folder of LibreOffice
+
+Const cstThisSub = &quot;FileSystem.getInstallFolder&quot;
+
+ SF_Utils._EnterFunction(cstThisSub)
+ InstallFolder = SF_FileSystem._GetConfigFolder(&quot;inst&quot;)
+ SF_Utils._ExitFunction(cstThisSub)
+
+End Property &apos; ScriptForge.SF_FileSystem.InstallFolder
+
+REM -----------------------------------------------------------------------------
+Property Get ObjectType As String
+&apos;&apos;&apos; Only to enable object representation
+ ObjectType = &quot;SF_FileSystem&quot;
+End Property &apos; ScriptForge.SF_FileSystem.ObjectType
+
+REM -----------------------------------------------------------------------------
+Property Get ServiceName As String
+&apos;&apos;&apos; Internal use
+ ServiceName = &quot;ScriptForge.FileSystem&quot;
+End Property &apos; ScriptForge.SF_FileSystem.ServiceName
+
+REM -----------------------------------------------------------------------------
+Property Get TemplatesFolder() As String
+&apos;&apos;&apos; Return the folder defined in the LibreOffice paths options as intended for templates files
+
+Dim sPath As String &apos; Template property of com.sun.star.util.PathSettings
+Const cstThisSub = &quot;FileSystem.getTemplatesFolder&quot;
+
+ SF_Utils._EnterFunction(cstThisSub)
+ sPath = SF_Utils._GetUNOService(&quot;PathSettings&quot;).Template
+ TemplatesFolder = SF_FileSystem._ConvertFromUrl(Split(sPath, &quot;;&quot;)(0) &amp; &quot;/&quot;)
+ SF_Utils._ExitFunction(cstThisSub)
+
+End Property &apos; ScriptForge.SF_FileSystem.TemplatesFolder
+
+REM -----------------------------------------------------------------------------
+Property Get TemporaryFolder() As String
+&apos;&apos;&apos; Return the folder defined in the LibreOffice paths options as intended for temporary files
+
+Const cstThisSub = &quot;FileSystem.getTemporaryFolder&quot;
+
+ SF_Utils._EnterFunction(cstThisSub)
+ TemporaryFolder = SF_FileSystem._GetConfigFolder(&quot;temp&quot;)
+ SF_Utils._ExitFunction(cstThisSub)
+
+End Property &apos; ScriptForge.SF_FileSystem.TemporaryFolder
+
+REM -----------------------------------------------------------------------------
+Property Get UserTemplatesFolder() As String
+&apos;&apos;&apos; Return the folder defined in the LibreOffice paths options as intended for User templates files
+
+Dim sPath As String &apos; Template_writable property of com.sun.star.util.PathSettings
+Const cstThisSub = &quot;FileSystem.getUserTemplatesFolder&quot;
+
+ SF_Utils._EnterFunction(cstThisSub)
+ sPath = SF_Utils._GetUNOService(&quot;PathSettings&quot;).Template_writable
+ UserTemplatesFolder = SF_FileSystem._ConvertFromUrl(sPath &amp; &quot;/&quot;)
+ SF_Utils._ExitFunction(cstThisSub)
+
+End Property &apos; ScriptForge.SF_FileSystem.UserTemplatesFolder
+
+REM ===================================================================== METHODS
+
+REM -----------------------------------------------------------------------------
+Public Function BuildPath(Optional ByVal FolderName As Variant _
+ , Optional ByVal Name As Variant _
+ ) As String
+&apos;&apos;&apos; Combines a folder path and the name of a file and returns the combination with a valid path separator
+&apos;&apos;&apos; Inserts an additional path separator between the foldername and the name, only if necessary
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; FolderName: Path with which Name is combined. Path need not specify an existing folder
+&apos;&apos;&apos; Name: To be appended to the existing path.
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The path concatenated with the file name after insertion of a path separator, if necessary
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; Dim a As String
+&apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
+&apos;&apos;&apos; a = FSO.BuildPath(&quot;C:\Windows&quot;, &quot;Notepad.exe&quot;) returns C:\Windows\Notepad.exe
+
+Dim sBuild As String &apos; Return value
+Dim sFile As String &apos; Alias for Name
+Const cstFileProtocol = &quot;file:///&quot;
+Const cstThisSub = &quot;FileSystem.BuildPath&quot;
+Const cstSubArgs = &quot;FolderName, Name&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sBuild = &quot;&quot;
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateFile(FolderName, &quot;FolderName&quot;) Then GoTo Finally
+ If Not SF_Utils._Validate(Name, &quot;Name&quot;, V_STRING) Then GoTo Finally
+ End If
+ FolderName = SF_FileSystem._ConvertToUrl(FolderName)
+
+Try:
+ &apos; Add separator if necessary. FolderName is now in URL notation
+ If Len(FolderName) &gt; 0 Then
+ If Right(FolderName, 1) &lt;&gt; &quot;/&quot; Then sBuild = FolderName &amp; &quot;/&quot; Else sBuild = FolderName
+ Else
+ sBuild = cstFileProtocol
+ End If
+ &apos; Encode the file name
+ sFile = ConvertToUrl(Name)
+ &apos; Some file names produce http://file.name.suffix/
+ If Left(sFile, 7) = &quot;http://&quot; Then sFile = cstFileProtocol &amp; Mid(sFile, 8, Len(sFile) - 8)
+ &apos; Combine both parts
+ If Left(sFile, Len(cstFileProtocol)) = cstFileProtocol Then sBuild = sBuild &amp; Mid(sFile, Len(cstFileProtocol) + 1) Else sBuild = sBuild &amp; sFile
+
+Finally:
+ BuildPath = SF_FileSystem._ConvertFromUrl(sBuild)
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_FileSystem.BuildPath
+
+REM -----------------------------------------------------------------------------
+Public Function CompareFiles(Optional ByVal FileName1 As Variant _
+ , Optional ByVal FileName2 As Variant _
+ , Optional ByVal CompareContents As Variant _
+ )
+&apos;&apos;&apos; Compare 2 files and return True if they seem identical
+&apos;&apos;&apos; The comparison may be based on the file attributes, like modification time,
+&apos;&apos;&apos; or on their contents.
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; FileName1: The 1st file to compare
+&apos;&apos;&apos; FileName2: The 2nd file to compare
+&apos;&apos;&apos; CompareContents: When True, the contents of the files are compared. Default = False
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True when the files seem identical
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; UNKNOWNFILEERROR One of the files does not exist
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
+&apos;&apos;&apos; MsgBox FSO.CompareFiles(&quot;C:\myFile1.txt&quot;, &quot;C:\myFile2.txt&quot;, CompareContents := True)
+
+Dim bCompare As Boolean &apos; Return value
+Dim sFile As String &apos; Alias of FileName1 and 2
+Dim iFile As Integer &apos; 1 or 2
+Const cstPyHelper = &quot;$&quot; &amp; &quot;_SF_FileSystem__CompareFiles&quot;
+
+Const cstThisSub = &quot;FileSystem.CompareFiles&quot;
+Const cstSubArgs = &quot;FileName1, FileName2, [CompareContents=False]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bCompare = False
+
+Check:
+ If IsMissing(CompareContents) Or IsEmpty(CompareContents) Then CompareContents = False
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateFile(FileName1, &quot;FileName1&quot;, False) Then GoTo Finally
+ If Not SF_Utils._ValidateFile(FileName2, &quot;FileName2&quot;, False) Then GoTo Finally
+ If Not SF_Utils._Validate(CompareContents, &quot;CompareContents&quot;, V_BOOLEAN) Then GoTo Finally
+ End If
+ &apos; Do the files exist ? Otherwise raise error
+ sFile = FileName1 : iFile = 1
+ If Not SF_FileSystem.FileExists(sFile) Then GoTo CatchNotExists
+ sFile = FileName2 : iFile = 2
+ If Not SF_FileSystem.FileExists(sFile) Then GoTo CatchNotExists
+
+Try:
+ With ScriptForge.SF_Session
+ bCompare = .ExecutePythonScript(.SCRIPTISSHARED, _SF_.PythonHelper &amp; cstPyHelper _
+ , _ConvertFromUrl(FileName1) _
+ , _ConvertFromUrl(FileName2) _
+ , CompareContents)
+ End With
+
+Finally:
+ CompareFiles = bCompare
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchNotExists:
+ SF_Exception.RaiseFatal(UNKNOWNFILEERROR, &quot;FileName&quot; &amp; iFile, sFile)
+ GoTo Finally
+End Function &apos; ScriptForge.SF_FileSystem.CompareFiles
+
+REM -----------------------------------------------------------------------------
+Public Function CopyFile(Optional ByVal Source As Variant _
+ , Optional ByVal Destination As Variant _
+ , Optional ByVal Overwrite As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Copies one or more files from one location to another
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Source: FileName or NamePattern which can include wildcard characters, for one or more files to be copied
+&apos;&apos;&apos; Destination: FileName where the single Source file is to be copied
+&apos;&apos;&apos; or FolderName where the multiple files from Source are to be copied
+&apos;&apos;&apos; If FolderName does not exist, it is created
+&apos;&apos;&apos; Anyway, wildcard characters are not allowed in Destination
+&apos;&apos;&apos; Overwrite: If True (default), files may be overwritten
+&apos;&apos;&apos; CopyFile will fail if Destination has the read-only attribute set, regardless of the value of Overwrite.
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if at least one file has been copied
+&apos;&apos;&apos; False if an error occurred
+&apos;&apos;&apos; An error also occurs if a source using wildcard characters doesn&apos;t match any files.
+&apos;&apos;&apos; The method stops on the first error it encounters
+&apos;&apos;&apos; No attempt is made to roll back or undo any changes made before an error occurs
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; UNKNOWNFILEERROR Source does not exist
+&apos;&apos;&apos; UNKNOWNFOLDERERROR Source folder or Destination folder does not exist
+&apos;&apos;&apos; NOFILEMATCHERROR No file matches Source containing wildcards
+&apos;&apos;&apos; NOTAFOLDERERROR Destination is a file, not a folder
+&apos;&apos;&apos; NOTAFILEERROR Destination is a folder, not a file
+&apos;&apos;&apos; OVERWRITEERROR Destination can not be overwritten
+&apos;&apos;&apos; READONLYERROR Destination has its read-only attribute set
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
+&apos;&apos;&apos; FSO.CopyFile(&quot;C:\Windows\*.*&quot;, &quot;C:\Temp\&quot;, Overwrite := False) &apos; Only files are copied, subfolders are not
+
+Dim bCopy As Boolean &apos; Return value
+
+Const cstThisSub = &quot;FileSystem.CopyFile&quot;
+Const cstSubArgs = &quot;Source, Destination, [Overwrite=True]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bCopy = False
+
+Check:
+ If IsMissing(Overwrite) Or IsEmpty(Overwrite) Then Overwrite = True
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateFile(Source, &quot;Source&quot;, True) Then GoTo Finally
+ If Not SF_Utils._ValidateFile(Destination, &quot;Destination&quot;, False) Then GoTo Finally
+ If Not SF_Utils._Validate(Overwrite, &quot;Overwrite&quot;, V_BOOLEAN) Then GoTo Finally
+ End If
+
+Try:
+ bCopy = SF_FileSystem._CopyMove(&quot;CopyFile&quot;, Source, Destination, Overwrite)
+
+Finally:
+ CopyFile = bCopy
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_FileSystem.CopyFile
+
+REM -----------------------------------------------------------------------------
+Public Function CopyFolder(Optional ByVal Source As Variant _
+ , Optional ByVal Destination As Variant _
+ , Optional ByVal Overwrite As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Copies one or more folders from one location to another
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Source: FolderName or NamePattern which can include wildcard characters, for one or more folders to be copied
+&apos;&apos;&apos; Destination: FolderName where the single Source folder is to be copied
+&apos;&apos;&apos; or FolderName where the multiple folders from Source are to be copied
+&apos;&apos;&apos; If FolderName does not exist, it is created
+&apos;&apos;&apos; Anyway, wildcard characters are not allowed in Destination
+&apos;&apos;&apos; Overwrite: If True (default), folders and their content may be overwritten
+&apos;&apos;&apos; CopyFile will fail if Destination has the read-only attribute set, regardless of the value of Overwrite.
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if at least one folder has been copied
+&apos;&apos;&apos; False if an error occurred
+&apos;&apos;&apos; An error also occurs if a source using wildcard characters doesn&apos;t match any folders.
+&apos;&apos;&apos; The method stops on the first error it encounters
+&apos;&apos;&apos; No attempt is made to roll back or undo any changes made before an error occurs
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; UNKNOWNFILEERROR Source does not exist
+&apos;&apos;&apos; UNKNOWNFOLDERERROR Source folder or Destination folder does not exist
+&apos;&apos;&apos; NOFILEMATCHERROR No file matches Source containing wildcards
+&apos;&apos;&apos; NOTAFOLDERERROR Destination is a file, not a folder
+&apos;&apos;&apos; OVERWRITEERROR Destination can not be overwritten
+&apos;&apos;&apos; READONLYERROR Destination has its read-only attribute set
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
+&apos;&apos;&apos; FSO.CopyFolder(&quot;C:\Windows\*&quot;, &quot;C:\Temp\&quot;, Overwrite := False)
+
+Dim bCopy As Boolean &apos; Return value
+
+Const cstThisSub = &quot;FileSystem.CopyFolder&quot;
+Const cstSubArgs = &quot;Source, Destination, [Overwrite=True]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bCopy = False
+
+Check:
+ If IsMissing(Overwrite) Or IsEmpty(Overwrite) Then Overwrite = True
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateFile(Source, &quot;Source&quot;, True) Then GoTo Finally
+ If Not SF_Utils._ValidateFile(Destination, &quot;Destination&quot;, False) Then GoTo Finally
+ If Not SF_Utils._Validate(Overwrite, &quot;Overwrite&quot;, V_BOOLEAN) Then GoTo Finally
+ End If
+
+Try:
+ bCopy = SF_FileSystem._CopyMove(&quot;CopyFolder&quot;, Source, Destination, Overwrite)
+
+Finally:
+ CopyFolder = bCopy
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_FileSystem.CopyFolder
+
+REM -----------------------------------------------------------------------------
+Public Function CreateFolder(Optional ByVal FolderName As Variant) As Boolean
+&apos;&apos;&apos; Return True if the given folder name could be created successfully
+&apos;&apos;&apos; The parent folder does not need to exist beforehand
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; FolderName: a string representing the folder to create. It must not exist
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if FolderName is a valid folder name, does not exist and creation was successful
+&apos;&apos;&apos; False otherwise including when FolderName is a file
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; FOLDERCREATIONERROR FolderName is an existing folder or file
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
+&apos;&apos;&apos; FSO.CreateFolder(&quot;C:\NewFolder\&quot;)
+
+Dim bCreate As Boolean &apos; Return value
+Dim oSfa As Object &apos; com.sun.star.ucb.SimpleFileAccess
+
+Const cstThisSub = &quot;FileSystem.CreateFolder&quot;
+Const cstSubArgs = &quot;FolderName&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bCreate = False
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateFile(FolderName, &quot;FolderName&quot;) Then GoTo Finally
+ End If
+
+Try:
+ Set oSfa = SF_Utils._GetUnoService(&quot;FileAccess&quot;)
+ If SF_FileSystem.FolderExists(FolderName) Then GoTo CatchExists
+ If SF_FileSystem.FileExists(FolderName) Then GoTo CatchExists
+ oSfa.createFolder(SF_FileSystem._ConvertToUrl(FolderName))
+ bCreate = True
+
+Finally:
+ CreateFolder = bCreate
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchExists:
+ SF_Exception.RaiseFatal(FOLDERCREATIONERROR, &quot;FolderName&quot;, FolderName)
+ GoTo Finally
+End Function &apos; ScriptForge.SF_FileSystem.CreateFolder
+
+REM -----------------------------------------------------------------------------
+Public Function CreateTextFile(Optional ByVal FileName As Variant _
+ , Optional ByVal Overwrite As Variant _
+ , Optional ByVal Encoding As Variant _
+ ) As Object
+&apos;&apos;&apos; Creates a specified file and returns a TextStream object that can be used to write to the file
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; FileName: Identifies the file to create
+&apos;&apos;&apos; Overwrite: Boolean value that indicates if an existing file can be overwritten (default = True)
+&apos;&apos;&apos; Encoding: The character set that should be used
+&apos;&apos;&apos; Use one of the Names listed in https://www.iana.org/assignments/character-sets/character-sets.xhtml
+&apos;&apos;&apos; Note that LibreOffice does not implement all existing sets
+&apos;&apos;&apos; Default = UTF-8
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; An instance of the SF_TextStream class representing the opened file or a Null object if an error occurred
+&apos;&apos;&apos; It doesn&apos;t check either if the given encoding is implemented in LibreOffice
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; OVERWRITEERROR File exists, creation impossible
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; Dim myFile As Object
+&apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
+&apos;&apos;&apos; Set myFile = FSO.CreateTextFile(&quot;C:\Temp\ThisFile.txt&quot;, Overwrite := True)
+
+Dim oTextStream As Object &apos; Return value
+Const cstThisSub = &quot;FileSystem.CreateTextFile&quot;
+Const cstSubArgs = &quot;FileName, [Overwrite=True], [Encoding=&quot;&quot;UTF-8&quot;&quot;]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ Set oTextStream = Nothing
+
+Check:
+ If IsMissing(Overwrite) Or IsEmpty(Overwrite) Then Overwrite = True
+ If IsMissing(Encoding) Or IsEmpty(Encoding) Then Encoding = &quot;UTF-8&quot;
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateFile(FileName, &quot;FileName&quot;) Then GoTo Finally
+ If Not SF_Utils._Validate(Overwrite, &quot;Overwrite&quot;, V_BOOLEAN) Then GoTo Finally
+ If Not SF_Utils._Validate(Encoding, &quot;Encoding&quot;, V_STRING) Then GoTo Finally
+ End If
+
+ With SF_FileSystem
+ If .FileExists(FileName) Then
+ If Overwrite Then .DeleteFile(FileName) Else GoTo CatchOverWrite
+ End If
+
+Try:
+ Set oTextStream = .OpenTextFile(FileName, .ForWriting, Create := True, Encoding := Encoding)
+ End With
+
+Finally:
+ Set CreateTextFile = oTextStream
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchOverWrite:
+ SF_Exception.RaiseFatal(OVERWRITEERROR, &quot;FileName&quot;, FileName)
+ GoTo Finally
+End Function &apos; ScriptForge.SF_FileSystem.CreateTextFile
+
+REM -----------------------------------------------------------------------------
+Public Function DeleteFile(Optional ByVal FileName As Variant) As Boolean
+&apos;&apos;&apos; Deletes one or more files
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; FileName: FileName or NamePattern which can include wildcard characters, for one or more files to be deleted
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if at least one file has been deleted
+&apos;&apos;&apos; False if an error occurred
+&apos;&apos;&apos; An error also occurs if a FileName using wildcard characters doesn&apos;t match any files.
+&apos;&apos;&apos; The method stops on the first error it encounters
+&apos;&apos;&apos; No attempt is made to roll back or undo any changes made before an error occurs
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; UNKNOWNFILEERROR FileName does not exist
+&apos;&apos;&apos; NOFILEMATCHERROR No file matches FileName containing wildcards
+&apos;&apos;&apos; NOTAFILEERROR Argument is a folder, not a file
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
+&apos;&apos;&apos; FSO.DeleteFile(&quot;C:\Temp\*.*&quot;) &apos; Only files are deleted, subfolders are not
+
+Dim bDelete As Boolean &apos; Return value
+
+Const cstThisSub = &quot;FileSystem.DeleteFile&quot;
+Const cstSubArgs = &quot;FileName&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bDelete = False
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateFile(FileName, &quot;FileName&quot;, True) Then GoTo Finally
+ End If
+
+Try:
+ bDelete = SF_FileSystem._Delete(&quot;DeleteFile&quot;, FileName)
+
+Finally:
+ DeleteFile = bDelete
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_FileSystem.DeleteFile
+
+REM -----------------------------------------------------------------------------
+Public Function DeleteFolder(Optional ByVal FolderName As Variant) As Boolean
+&apos;&apos;&apos; Deletes one or more Folders
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; FolderName: FolderName or NamePattern which can include wildcard characters, for one or more Folders to be deleted
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if at least one folder has been deleted
+&apos;&apos;&apos; False if an error occurred
+&apos;&apos;&apos; An error also occurs if a FolderName using wildcard characters doesn&apos;t match any folders.
+&apos;&apos;&apos; The method stops on the first error it encounters
+&apos;&apos;&apos; No attempt is made to roll back or undo any changes made before an error occurs
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; UNKNOWNFOLDERERROR FolderName does not exist
+&apos;&apos;&apos; NOFILEMATCHERROR No folder matches FolderName containing wildcards
+&apos;&apos;&apos; NOTAFOLDERERROR Argument is a file, not a folder
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
+&apos;&apos;&apos; FSO.DeleteFolder(&quot;C:\Temp\*&quot;) &apos; Only folders are deleted, files in the parent folder are not
+
+Dim bDelete As Boolean &apos; Return value
+
+Const cstThisSub = &quot;FileSystem.DeleteFolder&quot;
+Const cstSubArgs = &quot;FolderName&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bDelete = False
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateFile(FolderName, &quot;FolderName&quot;, True) Then GoTo Finally
+ End If
+
+Try:
+ bDelete = SF_FileSystem._Delete(&quot;DeleteFolder&quot;, FolderName)
+
+Finally:
+ DeleteFolder = bDelete
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_FileSystem.DeleteFolder
+
+REM -----------------------------------------------------------------------------
+Public Function ExtensionFolder(Optional ByVal Extension As Variant) As String
+&apos;&apos;&apos; Return the folder where the given extension is installed. The argument must
+&apos;&apos;&apos; be in the list of extensions provided by the SF_Platform.Extensions property
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Extension: a valid extension name
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The requested folder using the FileNaming notation
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; MsgBox FSO.ExtensionFolder(&quot;apso.python.script.organizer&quot;)
+
+Dim sFolder As String &apos; Return value
+Static vExtensions As Variant &apos; Cached list of existing extension names
+Dim oPackage As Object &apos; /singletons/com.sun.star.deployment.PackageInformationProvider
+Const cstThisSub = &quot;FileSystem.ExtensionFolder&quot;
+Const cstSubArgs = &quot;Extension&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sFolder = &quot;&quot;
+
+Check:
+ If IsEmpty(vExtensions) Then vExtensions = SF_Platform.Extensions
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(Extension, &quot;Extension&quot;, V_STRING, vExtensions) Then GoTo Finally
+ End If
+
+Try:
+ &apos; Search an individual folder
+ Set oPackage = SF_Utils._GetUnoService(&quot;PackageInformationProvider&quot;)
+ sFolder = oPackage.getPackageLocation(Extension)
+
+Finally:
+ ExtensionFolder = SF_FileSystem._ConvertFromUrl(sFolder)
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_FileSystem.ExtensionFolder
+
+REM -----------------------------------------------------------------------------
+Public Function FileExists(Optional ByVal FileName As Variant) As Boolean
+&apos;&apos;&apos; Return True if the given file exists
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; FileName: a string representing a file
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if FileName is a valid File name and it exists
+&apos;&apos;&apos; False otherwise including when FileName is a folder
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
+&apos;&apos;&apos; If FSO.FileExists(&quot;C:\Notepad.exe&quot;) Then ...
+
+Dim bExists As Boolean &apos; Return value
+Dim oSfa As Object &apos; com.sun.star.ucb.SimpleFileAccess
+
+Const cstThisSub = &quot;FileSystem.FileExists&quot;
+Const cstSubArgs = &quot;FileName&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bExists = False
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateFile(FileName, &quot;FileName&quot;) Then GoTo Finally
+ End If
+ FileName = SF_FileSystem._ConvertToUrl(FileName)
+
+Try:
+ Set oSfa = SF_Utils._GetUnoService(&quot;FileAccess&quot;)
+ bExists = oSfa.exists(FileName) And Not oSfa.isFolder(FileName)
+
+Finally:
+ FileExists = bExists
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_FileSystem.FileExists
+
+REM -----------------------------------------------------------------------------
+Public Function Files(Optional ByVal FolderName As Variant _
+ , Optional ByVal Filter As Variant _
+ ) As Variant
+&apos;&apos;&apos; Return an array of the FileNames stored in the given folder. The folder must exist
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; FolderName: the folder to explore
+&apos;&apos;&apos; Filter: contains wildcards (&quot;?&quot; and &quot;*&quot;) to limit the list to the relevant files (default = &quot;&quot;)
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; An array of strings, each entry is the FileName of an existing file
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; UNKNOWNFOLDERERROR Folder does not exist
+&apos;&apos;&apos; NOTAFOLDERERROR FolderName is a file, not a folder
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; Dim a As Variant
+&apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
+&apos;&apos;&apos; a = FSO.Files(&quot;C:\Windows\&quot;)
+
+Dim vFiles As Variant &apos; Return value
+Dim oSfa As Object &apos; com.sun.star.ucb.SimpleFileAccess
+Dim sFolderName As String &apos; URL lias for FolderName
+Dim sFile As String &apos; Single file
+Dim i As Long
+
+Const cstThisSub = &quot;FileSystem.Files&quot;
+Const cstSubArgs = &quot;FolderName, [Filter=&quot;&quot;&quot;&quot;]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ vFiles = Array()
+
+Check:
+ If IsMissing(Filter) Or IsEmpty(Filter) Then Filter = &quot;&quot;
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateFile(FolderName, &quot;FolderName&quot;) Then GoTo Finally
+ If Not SF_Utils._Validate(Filter, &quot;Filter&quot;, V_STRING) Then GoTo Finally
+ End If
+ sFolderName = SF_FileSystem._ConvertToUrl(FolderName)
+ If SF_FileSystem.FileExists(FolderName) Then GoTo CatchFile &apos; Must not be a file
+ If Not SF_FileSystem.FolderExists(FolderName) Then GoTo CatchFolder &apos; Folder must exist
+
+Try:
+ &apos; Get files
+ Set oSfa = SF_Utils._GetUnoService(&quot;FileAccess&quot;)
+ vFiles = oSfa.getFolderContents(sFolderName, False)
+ &apos; Adjust notations
+ For i = 0 To UBound(vFiles)
+ sFile = SF_FileSystem._ConvertFromUrl(vFiles(i))
+ vFiles(i) = sFile
+ Next i
+ &apos; Reduce list to those passing the filter
+ If Len(Filter) &gt; 0 Then
+ For i = 0 To UBound(vFiles)
+ sFile = SF_FileSystem.GetName(vFiles(i))
+ If Not SF_String.IsLike(sFile, Filter) Then vFiles(i) = &quot;&quot;
+ Next i
+ vFiles = Sf_Array.TrimArray(vFiles)
+ End If
+
+Finally:
+ Files = vFiles
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchFile:
+ SF_Exception.RaiseFatal(NOTAFOLDERERROR, &quot;FolderName&quot;, FolderName)
+ GoTo Finally
+CatchFolder:
+ SF_Exception.RaiseFatal(UNKNOWNFOLDERERROR, &quot;FolderName&quot;, FolderName)
+ GoTo Finally
+End Function &apos; ScriptForge.SF_FileSystem.Files
+
+REM -----------------------------------------------------------------------------
+Public Function FolderExists(Optional ByVal FolderName As Variant) As Boolean
+&apos;&apos;&apos; Return True if the given folder name exists
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; FolderName: a string representing a folder
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if FolderName is a valid folder name and it exists
+&apos;&apos;&apos; False otherwise including when FolderName is a file
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
+&apos;&apos;&apos; If FSO.FolderExists(&quot;C:\&quot;) Then ...
+
+Dim bExists As Boolean &apos; Return value
+Dim oSfa As Object &apos; com.sun.star.ucb.SimpleFileAccess
+
+Const cstThisSub = &quot;FileSystem.FolderExists&quot;
+Const cstSubArgs = &quot;FolderName&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bExists = False
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateFile(FolderName, &quot;FolderName&quot;) Then GoTo Finally
+ End If
+ FolderName = SF_FileSystem._ConvertToUrl(FolderName)
+
+Try:
+ Set oSfa = SF_Utils._GetUnoService(&quot;FileAccess&quot;)
+ bExists = oSfa.isFolder(FolderName)
+
+Finally:
+ FolderExists = bExists
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_FileSystem.FolderExists
+
+REM -----------------------------------------------------------------------------
+Public Function GetBaseName(Optional ByVal FileName As Variant) As String
+&apos;&apos;&apos; Returns the BaseName part of the last component of a File- or FolderName, without its extension
+&apos;&apos;&apos; The method does not check for the existence of the specified file or folder
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; FileName: Path and file name
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The BaseName of the given argument in native operating system format. May be empty
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; Dim a As String
+&apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
+&apos;&apos;&apos; a = FSO.GetBaseName(&quot;C:\Windows\Notepad.exe&quot;) returns Notepad
+
+Dim sBase As String &apos; Return value
+Dim sExt As String &apos; Extension
+Dim sName As String &apos; Last component of FileName
+Dim vName As Variant &apos; Array of trunks of sName
+Const cstThisSub = &quot;FileSystem.GetBaseName&quot;
+Const cstSubArgs = &quot;FileName&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sBase = &quot;&quot;
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateFile(FileName, &quot;FileName&quot;) Then GoTo Finally
+ End If
+
+Try:
+ sName = SF_FileSystem.GetName(FileName)
+ If Len(sName) &gt; 0 Then
+ If InStr(sName, &quot;.&quot;) &gt; 0 Then
+ vName = Split(sName, &quot;.&quot;)
+ sExt = vName(UBound(vName))
+ sBase = Left(sName, Len(sName) - Len(sExt) - 1)
+ Else
+ sBase = sName
+ End If
+ End If
+
+Finally:
+ GetBaseName = sBase
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_FileSystem.GetBaseName
+
+REM -----------------------------------------------------------------------------
+Public Function GetExtension(Optional ByVal FileName As Variant) As String
+&apos;&apos;&apos; Returns the extension part of a File- or FolderName, without the dot (.).
+&apos;&apos;&apos; The method does not check for the existence of the specified file or folder
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; FileName: Path and file name
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The extension without a leading dot. May be empty
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; Dim a As String
+&apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
+&apos;&apos;&apos; a = FSO.GetExtension(&quot;C:\Windows\Notepad.exe&quot;) returns exe
+
+Dim sExt As String &apos; Return value
+Dim sName As String &apos; Last component of FileName
+Dim vName As Variant &apos; Array of trunks of sName
+Const cstThisSub = &quot;FileSystem.GetExtension&quot;
+Const cstSubArgs = &quot;FileName&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sExt = &quot;&quot;
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateFile(FileName, &quot;FileName&quot;) Then GoTo Finally
+ End If
+
+Try:
+ sName = SF_FileSystem.GetName(FileName)
+ If Len(sName) &gt; 0 And InStr(sName, &quot;.&quot;) &gt; 0 Then
+ vName = Split(sName, &quot;.&quot;)
+ sExt = vName(UBound(vName))
+ End If
+
+Finally:
+ GetExtension = sExt
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_FileSystem.GetExtension
+
+REM -----------------------------------------------------------------------------
+Public Function GetFileLen(Optional ByVal FileName As Variant) As Currency
+&apos;&apos;&apos; Return file size in bytes with four decimals &apos;&apos;&apos;
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; FileName: a string representing a file
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; File size if FileName exists
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; UNKNOWNFILEERROR The file does not exist of is a folder
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; Print SF_FileSystem.GetFileLen(&quot;C:\pagefile.sys&quot;)
+
+Dim curSize As Currency &apos; Return value
+Const cstPyHelper = &quot;$&quot; &amp; &quot;_SF_FileSystem__GetFilelen&quot;
+Const cstThisSub = &quot;FileSystem.GetFileLen&quot;
+Const cstSubArgs = &quot;FileName&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ curSize = 0
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateFile(FileName, &quot;FileName&quot;) Then GoTo Finally
+ End If
+
+Try:
+ If SF_FileSystem.FileExists(FileName) Then
+ With ScriptForge.SF_Session
+ curSize = .ExecutePythonScript(.SCRIPTISSHARED, _SF_.PythonHelper &amp; cstPyHelper _
+ , _ConvertFromUrl(FileName))
+ End With
+ Else
+ GoTo CatchNotExists
+ End If
+
+Finally:
+ GetFileLen = curSize
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchNotExists:
+ SF_Exception.RaiseFatal(UNKNOWNFILEERROR, &quot;FileName&quot;, FileName)
+ GoTo Finally
+End Function &apos; ScriptForge.SF_FileSystem.GetFileLen
+
+REM -----------------------------------------------------------------------------
+Public Function GetFileModified(Optional ByVal FileName As Variant) As Variant
+&apos;&apos;&apos; Returns the last modified date for the given file
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; FileName: a string representing an existing file
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The modification date and time as a Basic Date
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; UNKNOWNFILEERROR The file does not exist of is a folder
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; Dim a As Date
+&apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
+&apos;&apos;&apos; a = FSO.GetFileModified(&quot;C:\Temp\myDoc.odt&quot;)
+
+Dim dModified As Date &apos; Return value
+Dim oModified As New com.sun.star.util.DateTime
+Dim oSfa As Object &apos; com.sun.star.ucb.SimpleFileAccess
+
+Const cstThisSub = &quot;FileSystem.GetFileModified&quot;
+Const cstSubArgs = &quot;FileName&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ dModified = 0
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateFile(FileName, &quot;FileName&quot;) Then GoTo Finally
+ End If
+
+Try:
+ Set oSfa = SF_Utils._GetUnoService(&quot;FileAccess&quot;)
+ If SF_FileSystem.FileExists(FileName) Then
+ FileName = SF_FileSystem._ConvertToUrl(FileName)
+ Set oModified = oSfa.getDateTimeModified(FileName)
+ dModified = CDateFromUnoDateTime(oModified)
+ Else
+ GoTo CatchNotExists
+ End If
+
+Finally:
+ GetFileModified = dModified
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchNotExists:
+ SF_Exception.RaiseFatal(UNKNOWNFILEERROR, &quot;FileName&quot;, FileName)
+ GoTo Finally
+End Function &apos; ScriptForge.SF_FileSystem.GetFileModified
+
+REM -----------------------------------------------------------------------------
+Public Function GetName(Optional ByVal FileName As Variant) As String
+&apos;&apos;&apos; Returns the last component of a File- or FolderName
+&apos;&apos;&apos; The method does not check for the existence of the specified file or folder
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; FileName: Path and file name
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The last component of the full file name in native operating system format
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; Dim a As String
+&apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
+&apos;&apos;&apos; a = FSO.GetName(&quot;C:\Windows\Notepad.exe&quot;) returns Notepad.exe
+
+Dim sName As String &apos; Return value
+Dim vFile As Variant &apos; Array of components
+Const cstThisSub = &quot;FileSystem.GetName&quot;
+Const cstSubArgs = &quot;FileName&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sName = &quot;&quot;
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateFile(FileName, &quot;FileName&quot;) Then GoTo Finally
+ End If
+ FileName = SF_FileSystem._ConvertToUrl(FileName)
+
+Try:
+ If Len(FileName) &gt; 0 Then
+ If Right(FileName, 1) = &quot;/&quot; Then FileName = Left(FileName, Len(FileName) - 1)
+ vFile = Split(FileName, &quot;/&quot;)
+ sName = ConvertFromUrl(vFile(UBound(vFile))) &apos; Always in SYS format
+ End If
+
+Finally:
+ GetName = sName
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_FileSystem.GetName
+
+REM -----------------------------------------------------------------------------
+Public Function GetParentFolderName(Optional ByVal FileName As Variant) As String
+&apos;&apos;&apos; Returns a string containing the name of the parent folder of the last component in a specified File- or FolderName
+&apos;&apos;&apos; The method does not check for the existence of the specified file or folder
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; FileName: Path and file name
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; A FolderName including its final path separator
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; Dim a As String
+&apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
+&apos;&apos;&apos; a = FSO.GetParentFolderName(&quot;C:\Windows\Notepad.exe&quot;) returns C:\Windows\
+
+Dim sFolder As String &apos; Return value
+Dim sName As String &apos; Last component of FileName
+Dim vFile As Variant &apos; Array of file components
+Const cstThisSub = &quot;FileSystem.GetParentFolderName&quot;
+Const cstSubArgs = &quot;FileName&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sFolder = &quot;&quot;
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateFile(FileName, &quot;FileName&quot;) Then GoTo Finally
+ End If
+ FileName = SF_FileSystem._ConvertToUrl(FileName)
+
+Try:
+ If Right(FileName, 1) = &quot;/&quot; Then FileName = Left(FileName, Len(FileName) - 1)
+ vFile = Split(FileName, &quot;/&quot;)
+ If UBound(vFile) &gt;= 0 Then vFile(UBound(vFile)) = &quot;&quot;
+ sFolder = Join(vFile, &quot;/&quot;)
+ If sFolder = &quot;&quot; Or Right(sFolder, 1) &lt;&gt; &quot;/&quot; Then sFolder = sFolder &amp; &quot;/&quot;
+
+Finally:
+ GetParentFolderName = SF_FileSystem._ConvertFromUrl(sFolder)
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_FileSystem.GetParentFolderName
+
+REM -----------------------------------------------------------------------------
+Public Function GetProperty(Optional ByVal PropertyName As Variant) As Variant
+&apos;&apos;&apos; Return the actual value of the given property
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; PropertyName: the name of the property as a string
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The actual value of the property
+&apos;&apos;&apos; Exceptions
+&apos;&apos;&apos; ARGUMENTERROR The property does not exist
+
+Const cstThisSub = &quot;FileSystem.GetProperty&quot;
+Const cstSubArgs = &quot;PropertyName&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ GetProperty = Null
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(PropertyName, &quot;PropertyName&quot;, V_STRING, Properties()) Then GoTo Catch
+ End If
+
+Try:
+ Select Case UCase(PropertyName)
+ Case UCase(&quot;ConfigFolder&quot;) : GetProperty = ConfigFolder
+ Case UCase(&quot;ExtensionsFolder&quot;) : GetProperty = ExtensionsFolder
+ Case UCase(&quot;FileNaming&quot;) : GetProperty = FileNaming
+ Case UCase(&quot;HomeFolder&quot;) : GetProperty = HomeFolder
+ Case UCase(&quot;InstallFolder&quot;) : GetProperty = InstallFolder
+ Case UCase(&quot;TemplatesFolder&quot;) : GetProperty = TemplatesFolder
+ Case UCase(&quot;TemporaryFolder&quot;) : GetProperty = TemporaryFolder
+ Case UCase(&quot;UserTemplatesFolder&quot;) : GetProperty = UserTemplatesFolder
+ Case Else
+ End Select
+
+Finally:
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_FileSystem.GetProperty
+
+REM -----------------------------------------------------------------------------
+Public Function GetTempName() As String
+&apos;&apos;&apos; Returns a randomly generated temporary file name that is useful for performing
+&apos;&apos;&apos; operations that require a temporary file : the method does not create any file
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; A FileName as a String that can be used f.i. with CreateTextFile()
+&apos;&apos;&apos; The FileName does not have any suffix
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; Dim a As String
+&apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
+&apos;&apos;&apos; a = FSO.GetTempName() &amp; &quot;.txt&quot;
+
+Dim sFile As String &apos; Return value
+Dim sTempDir As String &apos; The path to a temporary folder
+Dim lRandom As Long &apos; Random integer
+
+Const cstThisSub = &quot;FileSystem.GetTempName&quot;
+Const cstSubArgs = &quot;&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sFile = &quot;&quot;
+
+Check:
+ SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
+
+Try:
+ lRandom = SF_Session.ExecuteCalcFunction(&quot;RANDBETWEEN&quot;, 1, 999999)
+ sFile = SF_FileSystem.TemporaryFolder &amp; &quot;SF_&quot; &amp; Right(&quot;000000&quot; &amp; lRandom, 6)
+
+Finally:
+ GetTempName = SF_FileSystem._ConvertFromUrl(sFile)
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_FileSystem.GetTempName
+
+REM -----------------------------------------------------------------------------
+Public Function HashFile(Optional ByVal FileName As Variant _
+ , Optional ByVal Algorithm As Variant _
+ ) As String
+&apos;&apos;&apos; Return an hexadecimal string representing a checksum of the given file
+&apos;&apos;&apos; Next algorithms are supported: MD5, SHA1, SHA224, SHA256, SHA384 and SHA512
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; FileName: a string representing a file
+&apos;&apos;&apos; Algorithm: The hashing algorithm to use
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The requested checksum as a string. Hexadecimal digits are lower-cased
+&apos;&apos;&apos; A zero-length string when an error occurred
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; UNKNOWNFILEERROR The file does not exist of is a folder
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; Print SF_FileSystem.HashFile(&quot;C:\pagefile.sys&quot;, &quot;MD5&quot;)
+
+Dim sHash As String &apos; Return value
+Const cstPyHelper = &quot;$&quot; &amp; &quot;_SF_FileSystem__HashFile&quot;
+Const cstThisSub = &quot;FileSystem.HashFile&quot;
+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;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sHash = &quot;&quot;
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateFile(FileName, &quot;FileName&quot;) Then GoTo Finally
+ If Not SF_Utils._Validate(Algorithm, &quot;Algorithm&quot;, V_STRING _
+ , Array(&quot;MD5&quot;, &quot;SHA1&quot;, &quot;SHA224&quot;, &quot;SHA256&quot;, &quot;SHA384&quot;, &quot;SHA512&quot;)) Then GoTo Finally
+ End If
+
+Try:
+ If SF_FileSystem.FileExists(FileName) Then
+ With ScriptForge.SF_Session
+ sHash = .ExecutePythonScript(.SCRIPTISSHARED, _SF_.PythonHelper &amp; cstPyHelper _
+ , _ConvertFromUrl(FileName), LCase(Algorithm))
+ End With
+ Else
+ GoTo CatchNotExists
+ End If
+
+Finally:
+ HashFile = sHash
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchNotExists:
+ SF_Exception.RaiseFatal(UNKNOWNFILEERROR, &quot;FileName&quot;, FileName)
+ GoTo Finally
+End Function &apos; ScriptForge.SF_FileSystem.HashFile
+
+REM -----------------------------------------------------------------------------
+Public Function Methods() As Variant
+&apos;&apos;&apos; Return the list or methods of the FileSystem service as an array
+
+ Methods = Array(&quot;BuildPath&quot; _
+ , &quot;CompareFiles&quot; _
+ , &quot;CopyFile&quot; _
+ , &quot;CopyFolder&quot; _
+ , &quot;CreateFolder&quot; _
+ , &quot;CreateTextFile&quot; _
+ , &quot;DeleteFile&quot; _
+ , &quot;DeleteFolder&quot; _
+ , &quot;ExtensionFolder&quot; _
+ , &quot;FileExists&quot; _
+ , &quot;Files&quot; _
+ , &quot;FolderExists&quot; _
+ , &quot;GetBaseName&quot; _
+ , &quot;GetExtension&quot; _
+ , &quot;GetFileLen&quot; _
+ , &quot;GetFileModified&quot; _
+ , &quot;GetName&quot; _
+ , &quot;GetParentFolderName&quot; _
+ , &quot;GetTempName&quot; _
+ , &quot;HashFile&quot; _
+ , &quot;MoveFile&quot; _
+ , &quot;MoveFolder&quot; _
+ , &quot;OpenTextFile&quot; _
+ , &quot;PickFile&quot; _
+ , &quot;PickFolder&quot; _
+ , &quot;SubFolders&quot; _
+ )
+
+End Function &apos; ScriptForge.SF_FileSystem.Methods
+
+REM -----------------------------------------------------------------------------
+Public Function MoveFile(Optional ByVal Source As Variant _
+ , Optional ByVal Destination As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Moves one or more files from one location to another
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Source: FileName or NamePattern which can include wildcard characters, for one or more files to be moved
+&apos;&apos;&apos; Destination: FileName where the single Source file is to be moved
+&apos;&apos;&apos; If Source and Destination have the same parent folder MoveFile amounts to renaming the Source
+&apos;&apos;&apos; or FolderName where the multiple files from Source are to be moved
+&apos;&apos;&apos; If FolderName does not exist, it is created
+&apos;&apos;&apos; Anyway, wildcard characters are not allowed in Destination
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if at least one file has been moved
+&apos;&apos;&apos; False if an error occurred
+&apos;&apos;&apos; An error also occurs if a source using wildcard characters doesn&apos;t match any files.
+&apos;&apos;&apos; The method stops on the first error it encounters
+&apos;&apos;&apos; No attempt is made to roll back or undo any changes made before an error occurs
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; UNKNOWNFILEERROR Source does not exist
+&apos;&apos;&apos; UNKNOWNFOLDERERROR Source folder or Destination folder does not exist
+&apos;&apos;&apos; NOFILEMATCHERROR No file matches Source containing wildcards
+&apos;&apos;&apos; NOTAFOLDERERROR Destination is a file, not a folder
+&apos;&apos;&apos; NOTAFILEERROR Destination is a folder, not a file
+&apos;&apos;&apos; OVERWRITEERROR Destination can not be overwritten
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
+&apos;&apos;&apos; FSO.MoveFile(&quot;C:\Temp1\*.*&quot;, &quot;C:\Temp2\&quot;) &apos; Only files are moved, subfolders are not
+
+Dim bMove As Boolean &apos; Return value
+
+Const cstThisSub = &quot;FileSystem.MoveFile&quot;
+Const cstSubArgs = &quot;Source, Destination&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bMove = False
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateFile(Source, &quot;Source&quot;, True) Then GoTo Finally
+ If Not SF_Utils._ValidateFile(Destination, &quot;Destination&quot;, False) Then GoTo Finally
+ End If
+
+Try:
+ bMove = SF_FileSystem._CopyMove(&quot;MoveFile&quot;, Source, Destination, False)
+
+Finally:
+ MoveFile = bMove
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_FileSystem.MoveFile
+
+REM -----------------------------------------------------------------------------
+Public Function MoveFolder(Optional ByVal Source As Variant _
+ , Optional ByVal Destination As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Moves one or more folders from one location to another
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; Source: FolderName or NamePattern which can include wildcard characters, for one or more folders to be moved
+&apos;&apos;&apos; Destination: FolderName where the single Source folder is to be moved
+&apos;&apos;&apos; FolderName must not exist
+&apos;&apos;&apos; or FolderName where the multiple folders from Source are to be moved
+&apos;&apos;&apos; If FolderName does not exist, it is created
+&apos;&apos;&apos; Anyway, wildcard characters are not allowed in Destination
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; True if at least one folder has been moved
+&apos;&apos;&apos; False if an error occurred
+&apos;&apos;&apos; An error also occurs if a source using wildcard characters doesn&apos;t match any folders.
+&apos;&apos;&apos; The method stops on the first error it encounters
+&apos;&apos;&apos; No attempt is made to roll back or undo any changes made before an error occurs
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; UNKNOWNFILEERROR Source does not exist
+&apos;&apos;&apos; UNKNOWNFOLDERERROR Source folder or Destination folder does not exist
+&apos;&apos;&apos; NOFILEMATCHERROR No file matches Source containing wildcards
+&apos;&apos;&apos; NOTAFOLDERERROR Destination is a file, not a folder
+&apos;&apos;&apos; OVERWRITEERROR Destination can not be overwritten
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
+&apos;&apos;&apos; FSO.MoveFolder(&quot;C:\Temp1\*&quot;, &quot;C:\Temp2\&quot;)
+
+Dim bMove As Boolean &apos; Return value
+
+Const cstThisSub = &quot;FileSystem.MoveFolder&quot;
+Const cstSubArgs = &quot;Source, Destination&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ bMove = False
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateFile(Source, &quot;Source&quot;, True) Then GoTo Finally
+ If Not SF_Utils._ValidateFile(Destination, &quot;Destination&quot;, False) Then GoTo Finally
+ End If
+
+Try:
+ bMove = SF_FileSystem._CopyMove(&quot;MoveFolder&quot;, Source, Destination, False)
+
+Finally:
+ MoveFolder = bMove
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_FileSystem.MoveFolder
+
+REM -----------------------------------------------------------------------------
+Public Function OpenTextFile(Optional ByVal FileName As Variant _
+ , Optional ByVal IOMode As Variant _
+ , Optional ByVal Create As Variant _
+ , Optional ByVal Encoding As Variant _
+ ) As Object
+&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
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; FileName: Identifies the file to open
+&apos;&apos;&apos; IOMode: Indicates input/output mode. Can be one of three constants: ForReading, ForWriting, or ForAppending
+&apos;&apos;&apos; Create: Boolean value that indicates whether a new file can be created if the specified filename doesn&apos;t exist.
+&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)
+&apos;&apos;&apos; Encoding: The character set that should be used
+&apos;&apos;&apos; Use one of the Names listed in https://www.iana.org/assignments/character-sets/character-sets.xhtml
+&apos;&apos;&apos; Note that LibreOffice does not implement all existing sets
+&apos;&apos;&apos; Default = UTF-8
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; An instance of the SF_TextStream class representing the opened file or a Null object if an error occurred
+&apos;&apos;&apos; The method does not check if the file is really a text file
+&apos;&apos;&apos; It doesn&apos;t check either if the given encoding is implemented in LibreOffice nor if it is the right one
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; UNKNOWNFILEERROR File does not exist
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; Dim myFile As Object
+&apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
+&apos;&apos;&apos; Set myFile = FSO.OpenTextFile(&quot;C:\Temp\ThisFile.txt&quot;, FSO.ForReading)
+&apos;&apos;&apos; If Not IsNull(myFile) Then &apos; ... Go ahead with reading text lines
+
+Dim oTextStream As Object &apos; Return value
+Dim bExists As Boolean &apos; File to open does exist
+Const cstThisSub = &quot;FileSystem.OpenTextFile&quot;
+Const cstSubArgs = &quot;FileName, [IOMode=1], [Create=False], [Encoding=&quot;&quot;UTF-8&quot;&quot;]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ Set oTextStream = Nothing
+
+Check:
+ With SF_FileSystem
+ If IsMissing(IOMode) Or IsEmpty(IOMode) Then IOMode = ForReading
+ If IsMissing(Create) Or IsEmpty(Create) Then Create = False
+ If IsMissing(Encoding) Or IsEmpty(Encoding) Then Encoding = &quot;UTF-8&quot;
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateFile(FileName, &quot;FileName&quot;) Then GoTo Finally
+ If Not SF_Utils._Validate(IOMode, &quot;IOMode&quot;, V_NUMERIC _
+ , Array(ForReading, ForWriting, ForAppending)) _
+ Then GoTo Finally
+ If Not SF_Utils._Validate(Create, &quot;Create&quot;, V_BOOLEAN) Then GoTo Finally
+ If Not SF_Utils._Validate(Encoding, &quot;Encoding&quot;, V_STRING) Then GoTo Finally
+ End If
+
+ bExists = .FileExists(FileName)
+ Select Case IOMode
+ Case ForReading : If Not bExists Then GoTo CatchNotExists
+ Case Else : If Not bExists And Not Create Then GoTo CatchNotExists
+ End Select
+
+ If IOMode = ForAppending And Not bExists Then IOMode = ForWriting
+ End With
+
+Try:
+ &apos; Create and initialize TextStream class instance
+ Set oTextStream = New SF_TextStream
+ With oTextStream
+ .[Me] = oTextStream
+ .[_Parent] = SF_FileSystem
+ ._FileName = SF_FileSystem._ConvertToUrl(FileName)
+ ._IOMode = IOMode
+ ._Encoding = Encoding
+ ._FileExists = bExists
+ ._Initialize()
+ End With
+
+Finally:
+ Set OpenTextFile = oTextStream
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchNotExists:
+ SF_Exception.RaiseFatal(UNKNOWNFILEERROR, &quot;FileName&quot;, FileName)
+ GoTo Finally
+End Function &apos; ScriptForge.SF_FileSystem.OpenTextFile
+
+REM -----------------------------------------------------------------------------
+Public Function PickFile(Optional ByVal DefaultFile As Variant _
+ , Optional ByVal Mode As Variant _
+ , Optional ByVal Filter As Variant _
+ ) As String
+&apos;&apos;&apos; Returns the file selected with a FilePicker dialog box
+&apos;&apos;&apos; The mode, OPEN or SAVE, and the filter may be preset
+&apos;&apos;&apos; If mode = SAVE and the picked file exists, a warning message will be displayed
+&apos;&apos;&apos; Modified from Andrew Pitonyak&apos;s Base Macro Programming ยง10.4
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; DefaultFile: Folder part: the FolderName from which to start. Default = the last selected folder
+&apos;&apos;&apos; File part: the default file to open or save
+&apos;&apos;&apos; Mode: &quot;OPEN&quot; (input file) or &quot;SAVE&quot; (output file)
+&apos;&apos;&apos; Filter: by default only files having the given suffix will be displayed. Default = all suffixes
+&apos;&apos;&apos; The filter combo box will contain the given SuffixFilter (if not &quot;*&quot;) and &quot;*.*&quot;
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The selected FileName in URL format or &quot;&quot; if the dialog was cancelled
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
+&apos;&apos;&apos; FSO.PickFile(&quot;C:\&quot;, &quot;OPEN&quot;, &quot;txt&quot;) &apos; Only *.txt files are displayed
+
+Dim oFileDialog As Object &apos; com.sun.star.ui.dialogs.FilePicker
+Dim oFileAccess As object &apos; com.sun.star.ucb.SimpleFileAccess
+Dim oPath As Object &apos; com.sun.star.util.PathSettings
+Dim iAccept As Integer &apos; Result of dialog execution
+Dim sInitPath As String &apos; Current working directory
+Dim sBaseFile As String
+Dim iMode As Integer &apos; Numeric alias for SelectMode
+Dim sFile As String &apos; Return value
+
+Const cstThisSub = &quot;FileSystem.PickFile&quot;
+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;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sFile = &quot;&quot;
+
+Check:
+ If IsMissing(DefaultFile) Or IsEmpty(DefaultFile) Then DefaultFile = &quot;&quot;
+ If IsMissing(Mode) Or IsEmpty(Mode) Then Mode = &quot;OPEN&quot;
+ If IsMissing(Filter) Or IsEmpty(Filter) Then Filter = &quot;&quot;
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateFile(DefaultFile, &quot;DefaultFile&quot;, , True) Then GoTo Finally
+ If Not SF_Utils._Validate(Mode, &quot;Mode&quot;, V_STRING, Array(&quot;OPEN&quot;, &quot;SAVE&quot;)) Then GoTo Finally
+ If Not SF_Utils._Validate(Filter, &quot;Filter&quot;, V_STRING) Then GoTo Finally
+ End If
+ DefaultFile = SF_FileSystem._ConvertToUrl(DefaultFile)
+
+Try:
+ &apos; Derive numeric equivalent of the Mode argument: https://api.libreoffice.org/docs/idl/ref/TemplateDescription_8idl.html
+ With com.sun.star.ui.dialogs.TemplateDescription
+ If Mode = &quot;OPEN&quot; Then iMode = .FILEOPEN_SIMPLE Else iMode = .FILESAVE_AUTOEXTENSION
+ End With
+
+ &apos; Activate the filepicker dialog
+ Set oFileDialog = SF_Utils._GetUNOService(&quot;FilePicker&quot;)
+ With oFileDialog
+ .Initialize(Array(iMode))
+
+ &apos; Set filters
+ If Len(Filter) &gt; 0 Then .appendFilter(&quot;*.&quot; &amp; Filter, &quot;*.&quot; &amp; Filter) &apos; Twice: required by API
+ .appendFilter(&quot;*.*&quot;, &quot;*.*&quot;)
+ If Len(Filter) &gt; 0 Then .setCurrentFilter(&quot;*.&quot; &amp; Filter) Else .setCurrentFilter(&quot;*.*&quot;)
+
+ &apos; Set initial folder
+ If Len(DefaultFile) = 0 Then &apos; TODO: SF_Session.WorkingFolder
+ Set oPath = SF_Utils._GetUNOService(&quot;PathSettings&quot;)
+ sInitPath = oPath.Work &apos; Probably My Documents
+ Else
+ sInitPath = SF_FileSystem._ParseUrl(ConvertToUrl(DefaultFile)).Path
+ End If
+
+ &apos; Set default values
+ Set oFileAccess = SF_Utils._GetUNOService(&quot;FileAccess&quot;)
+ If oFileAccess.exists(sInitPath) Then .SetDisplayDirectory(sInitPath)
+ sBaseFile = SF_FileSystem.GetName(DefaultFile)
+ .setDefaultName(sBaseFile)
+
+ &apos; Get selected file
+ iAccept = .Execute()
+ If iAccept = com.sun.star.ui.dialogs.ExecutableDialogResults.OK Then sFile = .getSelectedFiles()(0)
+ End With
+
+Finally:
+ PickFile = SF_FileSystem._ConvertFromUrl(sFile)
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_FileSystem.PickFile
+
+REM -----------------------------------------------------------------------------
+Public Function PickFolder(Optional ByVal DefaultFolder As Variant _
+ , Optional ByVal FreeText As Variant _
+ ) As String
+&apos;&apos;&apos; Display a FolderPicker dialog box
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; DefaultFolder: the FolderName from which to start. Default = the last selected folder
+&apos;&apos;&apos; FreeText: text to display in the dialog. Default = &quot;&quot;
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The selected FolderName in URL or operating system format
+&apos;&apos;&apos; The zero-length string if the dialog was cancelled
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
+&apos;&apos;&apos; FSO.PickFolder(&quot;C:\&quot;, &quot;Choose a folder or press Cancel&quot;)
+
+Dim oFolderDialog As Object &apos; com.sun.star.ui.dialogs.FolderPicker
+Dim iAccept As Integer &apos; Value returned by the dialog (OK, Cancel, ..)
+Dim sFolder As String &apos; Return value &apos;
+
+Const cstThisSub = &quot;FileSystem.PickFolder&quot;
+Const cstSubArgs = &quot;[DefaultFolder=&quot;&quot;&quot;&quot;], [FreeText=&quot;&quot;&quot;&quot;]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ sFolder = &quot;&quot;
+
+Check:
+ If IsMissing(DefaultFolder) Or IsEmpty(DefaultFolder) Then DefaultFolder = &quot;&quot;
+ If IsMissing(FreeText) Or IsEmpty(FreeText) Then FreeText = &quot;&quot;
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateFile(DefaultFolder, &quot;DefaultFolder&quot;, , True) Then GoTo Finally
+ If Not SF_Utils._Validate(FreeText, &quot;FreeText&quot;, V_STRING) Then GoTo Finally
+ End If
+ DefaultFolder = SF_FileSystem._ConvertToUrl(DefaultFolder)
+
+Try:
+ Set oFolderDialog = SF_Utils._GetUNOService(&quot;FolderPicker&quot;)
+ If Not IsNull(oFolderDialog) Then
+ With oFolderDialog
+ If Len(DefaultFolder) &gt; 0 Then .DisplayDirectory = ConvertToUrl(DefaultFolder)
+ .Description = FreeText
+ iAccept = .Execute()
+ &apos; https://api.libreoffice.org/docs/idl/ref/ExecutableDialogResults_8idl.html
+ If iAccept = com.sun.star.ui.dialogs.ExecutableDialogResults.OK Then
+ .DisplayDirectory = .Directory &apos; Set the next default initial folder to the selected one
+ sFolder = .Directory &amp; &quot;/&quot;
+ End If
+ End With
+ End If
+
+Finally:
+ PickFolder = SF_FileSystem._ConvertFromUrl(sFolder)
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_FileSystem.PickFolder
+
+REM -----------------------------------------------------------------------------
+Public Function Properties() As Variant
+&apos;&apos;&apos; Return the list or properties of the FileSystem module as an array
+
+ Properties = Array( _
+ &quot;ConfigFolder&quot; _
+ , &quot;ExtensionsFolder&quot; _
+ , &quot;FileNaming&quot; _
+ , &quot;HomeFolder&quot; _
+ , &quot;InstallFolder&quot; _
+ , &quot;TemplatesFolder&quot; _
+ , &quot;TemporaryFolder&quot; _
+ , &quot;UserTemplatesFolder&quot; _
+ )
+
+End Function &apos; ScriptForge.SF_FileSystem.Properties
+
+REM -----------------------------------------------------------------------------
+Public Function SetProperty(Optional ByVal PropertyName As Variant _
+ , Optional ByRef Value As Variant _
+ ) As Boolean
+&apos;&apos;&apos; Set a new value to the given property
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; PropertyName: the name of the property as a string
+&apos;&apos;&apos; Value: its new value
+&apos;&apos;&apos; Exceptions
+&apos;&apos;&apos; ARGUMENTERROR The property does not exist
+
+Const cstThisSub = &quot;FileSystem.SetProperty&quot;
+Const cstSubArgs = &quot;PropertyName, Value&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ SetProperty = False
+
+Check:
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._Validate(PropertyName, &quot;PropertyName&quot;, V_STRING, Properties()) Then GoTo Catch
+ End If
+
+Try:
+ Select Case UCase(PropertyName)
+ Case UCase(&quot;FileNaming&quot;) : FileNaming = Value
+ Case Else
+ End Select
+
+Finally:
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+End Function &apos; ScriptForge.SF_FileSystem.SetProperty
+
+REM -----------------------------------------------------------------------------
+Public Function SubFolders(Optional ByVal FolderName As Variant _
+ , Optional ByVal Filter As Variant _
+ ) As Variant
+&apos;&apos;&apos; Return an array of the FolderNames stored in the given folder. The folder must exist
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; FolderName: the folder to explore
+&apos;&apos;&apos; Filter: contains wildcards (&quot;?&quot; and &quot;*&quot;) to limit the list to the relevant folders (default = &quot;&quot;)
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; An array of strings, each entry is the FolderName of an existing folder
+&apos;&apos;&apos; Exceptions:
+&apos;&apos;&apos; UNKNOWNFOLDERERROR Folder does not exist
+&apos;&apos;&apos; NOTAFOLDERERROR FolderName is a file, not a folder
+&apos;&apos;&apos; Example:
+&apos;&apos;&apos; Dim a As Variant
+&apos;&apos;&apos; FSO.FileNaming = &quot;SYS&quot;
+&apos;&apos;&apos; a = FSO.SubFolders(&quot;C:\Windows\&quot;)
+
+Dim vSubFolders As Variant &apos; Return value
+Dim oSfa As Object &apos; com.sun.star.ucb.SimpleFileAccess
+Dim sFolderName As String &apos; URL lias for FolderName
+Dim sFolder As String &apos; Single folder
+Dim i As Long
+
+Const cstThisSub = &quot;FileSystem.SubFolders&quot;
+Const cstSubArgs = &quot;FolderName, [Filter=&quot;&quot;&quot;&quot;]&quot;
+
+ If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
+ vSubFolders = Array()
+
+Check:
+ If IsMissing(Filter) Or IsEmpty(Filter) Then Filter = &quot;&quot;
+ If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
+ If Not SF_Utils._ValidateFile(FolderName, &quot;FolderName&quot;) Then GoTo Finally
+ If Not SF_Utils._Validate(Filter, &quot;Filter&quot;, V_STRING) Then GoTo Finally
+ End If
+ sFolderName = SF_FileSystem._ConvertToUrl(FolderName)
+ If SF_FileSystem.FileExists(FolderName) Then GoTo CatchFile &apos; Must not be a file
+ If Not SF_FileSystem.FolderExists(FolderName) Then GoTo CatchFolder &apos; Folder must exist
+
+Try:
+ &apos; Get SubFolders
+ Set oSfa = SF_Utils._GetUnoService(&quot;FileAccess&quot;)
+ vSubFolders = oSfa.getFolderContents(sFolderName, True)
+ &apos; List includes files; remove them or adjust notations of folders
+ For i = 0 To UBound(vSubFolders)
+ sFolder = SF_FileSystem._ConvertFromUrl(vSubFolders(i) &amp; &quot;/&quot;)
+ If SF_FileSystem.FileExists(sFolder) Then vSubFolders(i) = &quot;&quot; Else vSubFolders(i) = sFolder
+ &apos; Reduce list to those passing the filter
+ If Len(Filter) &gt; 0 And Len(vSubFolders(i)) &gt; 0 Then
+ sFolder = SF_FileSystem.GetName(vSubFolders(i))
+ If Not SF_String.IsLike(sFolder, Filter) Then vSubFolders(i) = &quot;&quot;
+ End If
+ Next i
+ vSubFolders = SF_Array.TrimArray(vSubFolders)
+
+Finally:
+ SubFolders = vSubFolders
+ SF_Utils._ExitFunction(cstThisSub)
+ Exit Function
+Catch:
+ GoTo Finally
+CatchFile:
+ SF_Exception.RaiseFatal(NOTAFOLDERERROR, &quot;FolderName&quot;, FolderName)
+ GoTo Finally
+CatchFolder:
+ SF_Exception.RaiseFatal(UNKNOWNFOLDERERROR, &quot;FolderName&quot;, FolderName)
+ GoTo Finally
+End Function &apos; ScriptForge.SF_FileSystem.SubFolders
+
+REM =========================================================== PRIVATE FUNCTIONS
+
+REM -----------------------------------------------------------------------------
+Private Function _ConvertFromUrl(psFile) As String
+&apos;&apos;&apos; Execute the builtin ConvertFromUrl function only when relevant
+&apos;&apos;&apos; i.e. when FileNaming (how arguments and return values are provided) = &quot;SYS&quot;
+&apos;&apos;&apos; Called at the bottom of methods returning file names
+&apos;&apos;&apos; Remark: psFile might contain wildcards
+
+Const cstQuestion = &quot;$QUESTION$&quot;, cstStar = &quot;$STAR$&quot; &apos; Special tokens to replace wildcards
+
+ If SF_FileSystem.FileNaming = &quot;SYS&quot; Then
+ _ConvertFromUrl = Replace(Replace( _
+ ConvertFromUrl(Replace(Replace(psFile, &quot;?&quot;, cstQuestion), &quot;*&quot;, cstStar)) _
+ , cstQuestion, &quot;?&quot;), cstStar, &quot;*&quot;)
+ Else
+ _ConvertFromUrl = psFile
+ End If
+
+End Function &apos; ScriptForge.FileSystem._ConvertFromUrl
+
+REM -----------------------------------------------------------------------------
+Private Function _ConvertToUrl(psFile) As String
+&apos;&apos;&apos; Execute the builtin ConvertToUrl function only when relevant
+&apos;&apos;&apos; i.e. when FileNaming (how arguments and return values are provided) = &quot;SYS&quot;
+&apos;&apos;&apos; Called at the top of methods receiving file names as arguments
+&apos;&apos;&apos; Remark: psFile might contain wildcards
+
+ If SF_FileSystem.FileNaming = &quot;URL&quot; Then
+ _ConvertToUrl = psFile
+ Else
+ &apos; ConvertToUrl encodes &quot;?&quot;
+ _ConvertToUrl = Replace(ConvertToUrl(psFile), &quot;%3F&quot;, &quot;?&quot;)
+ End If
+
+End Function &apos; ScriptForge.FileSystem._ConvertToUrl
+
+REM -----------------------------------------------------------------------------
+Private Function _CopyMove(psMethod As String _
+ , psSource As String _
+ , psDestination As String _
+ , pbOverWrite As Boolean _
+ ) As Boolean
+&apos;&apos;&apos; Checks the arguments and executes the given method
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; psMethod: CopyFile/CopyFolder or MoveFile/MoveFolder
+&apos;&apos;&apos; psSource: Either File/FolderName
+&apos;&apos;&apos; or NamePattern which can include wildcard characters, for one or more files/folders to be copied
+&apos;&apos;&apos; psDestination: FileName or FolderName for copy/move of a single file/folder
+&apos;&apos;&apos; Otherwise a destination FolderName. If it does not exist, it is created
+&apos;&apos;&apos; pbOverWrite: If True, files/folders may be overwritten
+&apos;&apos;&apos; Must be False for Move operations
+&apos;&apos;&apos; Next checks are done:
+&apos;&apos;&apos; With wildcards (multiple files/folders):
+&apos;&apos;&apos; - Parent folder of source must exist
+&apos;&apos;&apos; - Destination must not be a file
+&apos;&apos;&apos; - Parent folder of Destination must exist
+&apos;&apos;&apos; - If the Destination folder does not exist a new folder is created,
+&apos;&apos;&apos; - At least one file matches the wildcards expression
+&apos;&apos;&apos; - Destination files/folder must not exist if pbOverWrite = False
+&apos;&apos;&apos; - Destination files/folders must not have the read-only attribute set
+&apos;&apos;&apos; - Destination files must not be folders, destination folders must not be files
+&apos;&apos;&apos; Without wildcards (single file/folder):
+&apos;&apos;&apos; - Source file/folder must exist and be a file/folder
+&apos;&apos;&apos; - Parent folder of Destination must exist
+&apos;&apos;&apos; - Destination must not be an existing folder/file
+&apos;&apos;&apos; - Destination file/folder must not exist if pbOverWrite = False
+&apos;&apos;&apos; - Destination file must not have the read-only attribute set
+
+Dim bCopyMove As Boolean &apos; Return value
+Dim bCopy As Boolean &apos; True if Copy, False if Move
+Dim bFile As Boolean &apos; True if File, False if Folder
+Dim oSfa As Object &apos; com.sun.star.ucb.SimpleFileAccess
+Dim bWildCards As Boolean &apos; True if wildcards found in Source
+Dim bCreateFolder As Boolean &apos; True when the destination folder should be created
+Dim bDestExists As Boolean &apos; True if destination exists
+Dim sSourceUrl As String &apos; Alias for Source
+Dim sDestinationUrl As String &apos; Alias for Destination
+Dim sDestinationFile As String &apos; Destination FileName
+Dim sParentFolder As String &apos; Parent folder of Source
+Dim vFiles As Variant &apos; Array of candidates for copy/move
+Dim sFile As String &apos; Single file/folder
+Dim sName As String &apos; Name (last component) of file
+Dim i As Long
+
+ &apos; Error handling left to calling routine
+ bCopyMove = False
+ bCopy = ( Left(psMethod, 4) = &quot;Copy&quot; )
+ bFile = ( Right(psMethod, 4) = &quot;File&quot; )
+ 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;
+ bDestExists = False
+
+ With SF_FileSystem
+
+Check:
+ If bWildCards Then
+ sParentFolder = .GetParentFolderName(psSource)
+ If Not .FolderExists(sParentFolder) Then GoTo CatchNoMatch
+ If .FileExists(psDestination) Then GoTo CatchFileNotFolder
+ If Not .FolderExists(.GetParentFolderName(psDestination)) Then GoTo CatchDestFolderNotExists
+ bCreateFolder = Not .FolderExists(psDestination)
+ Else
+ Select Case bFile
+ Case True &apos; File
+ If Not .FileExists(psSource) Then GoTo CatchFileNotExists
+ If Not .FolderExists(.GetParentFolderName(psDestination)) Then GoTo CatchSourceFolderNotExists
+ If .FolderExists(psDestination) Then GoTo CatchFolderNotFile
+ bDestExists = .FileExists(psDestination)
+ If pbOverWrite = False And bDestExists = True Then GoTo CatchDestinationExists
+ bCreateFolder = False
+ Case False &apos; Folder
+ If Not .FolderExists(psSource) Then GoTo CatchSourceFolderNotExists
+ If Not .FolderExists(.GetParentFolderName(psDestination)) Then GoTo CatchDestFolderNotExists
+ If .FileExists(psDestination) Then GoTo CatchFileNotFolder
+ bDestExists = .FolderExists(psDestination)
+ If pbOverWrite = False And bDestExists Then GoTo CatchDestinationExists
+ bCreateFolder = Not bDestExists
+ End Select
+ End If
+
+Try:
+ Set oSfa = SF_Utils._GetUnoService(&quot;FileAccess&quot;)
+ If bWildCards Then
+ If bFile Then vFiles = .Files(sParentFolder, .GetName(psSource)) Else vFiles = .SubFolders(sParentFolder, .GetName(psSource))
+ If UBound(vFiles) &lt; 0 Then GoTo CatchNoMatch
+ &apos; Go through the candidates
+ If bCreateFolder Then .CreateFolder(psDestination)
+ For i = 0 To UBound(vFiles)
+ sFile = vFiles(i)
+ sDestinationFile = .BuildPath(psDestination, .GetName(sFile))
+ If bFile Then bDestExists = .FileExists(sDestinationFile) Else bDestExists = .FolderExists(sDestinationFile)
+ If pbOverWrite = False Then
+ If bDestExists Then GoTo CatchDestinationExists
+ If .FolderExists(sDestinationFile) Then GoTo CatchDestinationExists
+ End If
+ sSourceUrl = ._ConvertToUrl(sFile)
+ sDestinationUrl = ._ConvertToUrl(sDestinationFile)
+ If bDestExists Then
+ If oSfa.isReadOnly(sDestinationUrl) Then GoTo CatchDestinationReadOnly
+ End If
+ Select Case bCopy
+ Case True : oSfa.copy(sSourceUrl, sDestinationUrl)
+ Case False : oSfa.move(sSourceUrl, sDestinationUrl)
+ End Select
+ Next i
+ Else
+ sSourceUrl = ._ConvertToUrl(psSource)
+ sDestinationUrl = ._ConvertToUrl(psDestination)
+ If bDestExists Then
+ If oSfa.isReadOnly(sDestinationUrl) Then GoTo CatchDestinationReadOnly
+ End If
+ If bCreateFolder Then .CreateFolder(psDestination)
+ Select Case bCopy
+ Case True : oSfa.copy(sSourceUrl, sDestinationUrl)
+ Case False : oSfa.move(sSourceUrl, sDestinationUrl)
+ End Select
+ End If
+
+ End With
+
+ bCopyMove = True
+
+Finally:
+ _CopyMove = bCopyMove
+ Exit Function
+CatchFileNotExists:
+ SF_Exception.RaiseFatal(UNKNOWNFILEERROR, &quot;Source&quot;, psSource)
+ GoTo Finally
+CatchSourceFolderNotExists:
+ SF_Exception.RaiseFatal(UNKNOWNFOLDERERROR, &quot;Source&quot;, psSource)
+ GoTo Finally
+CatchDestFolderNotExists:
+ SF_Exception.RaiseFatal(UNKNOWNFOLDERERROR, &quot;Destination&quot;, psDestination)
+ GoTo Finally
+CatchFolderNotFile:
+ SF_Exception.RaiseFatal(NOTAFILEERROR, &quot;Destination&quot;, psDestination)
+ GoTo Finally
+CatchDestinationExists:
+ SF_Exception.RaiseFatal(OVERWRITEERROR, &quot;Destination&quot;, psDestination)
+ GoTo Finally
+CatchNoMatch:
+ SF_Exception.RaiseFatal(NOFILEMATCHERROR, &quot;Source&quot;, psSource)
+ GoTo Finally
+CatchFileNotFolder:
+ SF_Exception.RaiseFatal(NOTAFOLDERERROR, &quot;Destination&quot;, psDestination)
+ GoTo Finally
+CatchDestinationReadOnly:
+ SF_Exception.RaiseFatal(READONLYERROR, &quot;Destination&quot;, Iif(bWildCards, sDestinationFile, psDestination))
+ GoTo Finally
+End Function &apos; ScriptForge.SF_FileSystem._CopyMove
+
+REM -----------------------------------------------------------------------------
+Public Function _CountTextLines(ByVal psFileName As String _
+ , Optional ByVal pbIncludeBlanks As Boolean _
+ ) As Long
+&apos;&apos;&apos; Convenient function to count the number of lines in a textfile
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; psFileName: the file in FileNaming notation
+&apos;&apos;&apos; pbIncludeBlanks: if True (default), zero-length lines are included
+&apos;&apos;&apos; Returns:
+&apos;&apos;&apos; The number of lines, f.i. to ease array sizing. -1 if file reading error
+
+Dim lLines As Long &apos; Return value
+Dim oFile As Object &apos; File handler
+Dim sLine As String &apos; The last line read
+
+Try:
+ lLines = 0
+ If IsMissing(pbIncludeBlanks) Then pbIncludeBlanks = True
+ Set oFile = SF_FileSystem.OpenTextFile(psFileName, ForReading)
+ With oFile
+ If Not IsNull(oFile) Then
+ Do While Not .AtEndOfStream
+ sLine = .ReadLine()
+ lLines = lLines + Iif(Len(sLine) &gt; 0 Or pbIncludeBlanks, 1, 0)
+ Loop
+ End If
+ .CloseFile()
+ Set oFile = .Dispose()
+ End With
+
+Finally:
+ _CountTextLines = lLines
+ Exit Function
+End Function &apos; ScriptForge.SF_FileSystem._CountTextLines
+
+REM -----------------------------------------------------------------------------
+Private Function _Delete(psMethod As String _
+ , psFile As String _
+ ) As Boolean
+&apos;&apos;&apos; Checks the argument and executes the given psMethod
+&apos;&apos;&apos; Args:
+&apos;&apos;&apos; psMethod: CopyFile/CopyFolder or MoveFile/MoveFolder
+&apos;&apos;&apos; psFile: Either File/FolderName
+&apos;&apos;&apos; or NamePattern which can include wildcard characters, for one or more files/folders to be deleted
+&apos;&apos;&apos; Next checks are done:
+&apos;&apos;&apos; With wildcards (multiple files/folders):
+&apos;&apos;&apos; - Parent folder of File must exist
+&apos;&apos;&apos; - At least one file matches the wildcards expression
+&apos;&apos;&apos; - Files or folders to delete must not have the read-only attribute set
+&apos;&apos;&apos; Without wildcards (single file/folder):
+&apos;&apos;&apos; - File/folder must exist and be a file/folder
+&apos;&apos;&apos; - A file or folder to delete must not have the read-only attribute set
+
+Dim bDelete As Boolean &apos; Return value
+Dim bFile As Boolean &apos; True if File, False if Folder
+Dim oSfa As Object &apos; com.sun.star.ucb.SimpleFileAccess
+Dim bWildCards As Boolean &apos; True if wildcards found in File
+Dim sFileUrl As String &apos; Alias for File
+Dim sParentFolder As String &apos; Parent folder of File
+Dim vFiles As Variant &apos; Array of candidates for deletion
+Dim sFile As String &apos; Single file/folder
+Dim sName As String &apos; Name (last component) of file
+Dim i As Long
+
+ &apos; Error handling left to calling routine
+ bDelete = False
+ bFile = ( Right(psMethod, 4) = &quot;File&quot; )
+ 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;
+
+ With SF_FileSystem
+
+Check:
+ If bWildCards Then
+ sParentFolder = .GetParentFolderName(psFile)
+ If Not .FolderExists(sParentFolder) Then GoTo CatchNoMatch
+ Else
+ Select Case bFile
+ Case True &apos; File
+ If .FolderExists(psFile) Then GoTo CatchFolderNotFile
+ If Not .FileExists(psFile) Then GoTo CatchFileNotExists
+ Case False &apos; Folder
+ If .FileExists(psFile) Then GoTo CatchFileNotFolder
+ If Not .FolderExists(psFile) Then GoTo CatchFolderNotExists
+ End Select
+ End If
+
+Try:
+ Set oSfa = SF_Utils._GetUnoService(&quot;FileAccess&quot;)
+ If bWildCards Then
+ If bFile Then vFiles = .Files(sParentFolder) Else vFiles = .SubFolders(sParentFolder)
+ &apos; Select candidates
+ For i = 0 To UBound(vFiles)
+ If Not SF_String.IsLike(.GetName(vFiles(i)), .GetName(psFile)) Then vFiles(i) = &quot;&quot;
+ Next i
+ vFiles = SF_Array.TrimArray(vFiles)
+ If UBound(vFiles) &lt; 0 Then GoTo CatchNoMatch
+ &apos; Go through the candidates
+ For i = 0 To UBound(vFiles)
+ sFile = vFiles(i)
+ sFileUrl = ._ConvertToUrl(sFile)
+ If oSfa.isReadOnly(sFileUrl) Then GoTo CatchReadOnly
+ oSfa.kill(sFileUrl)
+ Next i
+ Else
+ sFileUrl = ._ConvertToUrl(psFile)
+ If oSfa.isReadOnly(sFileUrl) Then GoTo CatchReadOnly
+ oSfa.kill(sFileUrl)
+ End If
+
+ End With
+
+ bDelete = True
+
+Finally:
+ _Delete = bDelete
+ Exit Function
+CatchFolderNotExists:
+ SF_Exception.RaiseFatal(UNKNOWNFOLDERERROR, &quot;FolderName&quot;, psFile)
+ GoTo Finally
+CatchFileNotExists:
+ SF_Exception.RaiseFatal(UNKNOWNFILEERROR, &quot;FileName&quot;, psFile)
+ GoTo Finally
+CatchFolderNotFile:
+ SF_Exception.RaiseFatal(NOTAFILEERROR, &quot;FileName&quot;, psFile)
+ GoTo Finally
+CatchNoMatch:
+ SF_Exception.RaiseFatal(NOFILEMATCHERROR, Iif(bFile, &quot;FileName&quot;, &quot;FolderName&quot;), psFile)
+ GoTo Finally
+CatchFileNotFolder:
+ SF_Exception.RaiseFatal(NOTAFOLDERERROR, &quot;FolderName&quot;, psFile)
+ GoTo Finally
+CatchReadOnly:
+ SF_Exception.RaiseFatal(READONLYERROR, Iif(bFile, &quot;FileName&quot;, &quot;FolderName&quot;), Iif(bWildCards, sFile, psFile))
+ GoTo Finally
+End Function &apos; ScriptForge.SF_FileSystem._Delete
+
+REM -----------------------------------------------------------------------------
+Private Function _GetConfigFolder(ByVal psFolder As String) As String
+&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
+&apos;&apos;&apos; inst =&gt; Installation path of LibreOffice
+&apos;&apos;&apos; prog =&gt; Program path of LibreOffice
+&apos;&apos;&apos; user =&gt; The user installation/config directory
+&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
+&apos;&apos;&apos; home =&gt; The home directory of the user. Under Unix this would be the home- directory.
+&apos;&apos;&apos; Under Windows this would be the CSIDL_PERSONAL directory, for example &quot;Documents and Settings\&lt;username&gt;\Documents&quot;
+&apos;&apos;&apos; temp =&gt; The current temporary directory
+
+Dim oSubst As Object &apos; com.sun.star.util.PathSubstitution
+Dim sConfig As String &apos; Return value
+
+ sConfig = &quot;&quot;
+ Set oSubst = SF_Utils._GetUNOService(&quot;PathSubstitution&quot;)
+ If Not IsNull(oSubst) Then sConfig = oSubst.getSubstituteVariableValue(&quot;$(&quot; &amp; psFolder &amp; &quot;)&quot;) &amp; &quot;/&quot;
+
+ _GetConfigFolder = SF_FileSystem._ConvertFromUrl(sConfig)
+
+End Function &apos; ScriptForge.FileSystem._GetConfigFolder
+
+REM -----------------------------------------------------------------------------
+Public Function _ParseUrl(psUrl As String) As Object
+&apos;&apos;&apos; Returns a com.sun.star.util.URL structure based on the argument
+
+Dim oParse As Object &apos; com.sun.star.util.URLTransformer
+Dim bParsed As Boolean &apos; True if parsing is successful
+Dim oUrl As New com.sun.star.util.URL &apos; Return value
+
+ oUrl.Complete = psUrl
+ Set oParse = SF_Utils._GetUNOService(&quot;URLTransformer&quot;)
+ bParsed = oParse.parseStrict(oUrl, &quot;&quot;)
+ If bParsed Then oUrl.Path = ConvertToUrl(oUrl.Path)
+
+ Set _ParseUrl = oUrl
+
+End Function &apos; ScriptForge.SF_FileSystem._ParseUrl
+
+REM -----------------------------------------------------------------------------
+Public Function _SFInstallFolder() As String
+&apos;&apos;&apos; Returns the installation folder of the ScriptForge library
+&apos;&apos;&apos; Either:
+&apos;&apos;&apos; - The library is present in [My Macros &amp; Dialogs]
+&apos;&apos;&apos; ($config)/basic/ScriptForge
+&apos;&apos;&apos; - The library is present in [LibreOffice Macros &amp; Dialogs]
+&apos;&apos;&apos; ($install)/share/basic/ScriptForge
+
+Dim sFolder As String &apos; Folder
+
+ _SFInstallFolder = &quot;&quot;
+
+ sFolder = BuildPath(ConfigFolder, &quot;basic/ScriptForge&quot;)
+ If Not FolderExists(sFolder) Then
+ sFolder = BuildPath(InstallFolder, &quot;share/basic/ScriptForge&quot;)
+ If Not FolderExists(sFolder) Then Exit Function
+ End If
+
+ _SFInstallFolder = _ConvertFromUrl(sFolder)
+
+End Function &apos; ScriptForge.SF_FileSystem._SFInstallFolder
+
+REM ============================================ END OF SCRIPTFORGE.SF_FileSystem
+</script:module> \ No newline at end of file