1
0
Fork 0
libreoffice/wizards/source/scriptforge/SF_TextStream.xba
Daniel Baumann 8e63e14cf6
Adding upstream version 4:25.2.3.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
2025-06-22 16:20:04 +02:00

725 lines
No EOL
30 KiB
XML

<?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_TextStream" 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 ClassModule
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_TextStream
&apos;&apos;&apos; =============
&apos;&apos;&apos; Class instantiated by the
&apos;&apos;&apos; SF_FileSystem.CreateTextFile
&apos;&apos;&apos; SF_FileSystem.OpenTextFile
&apos;&apos;&apos; methods to facilitate the sequential processing of text files
&apos;&apos;&apos; All open/read/write/close operations are presumed to happen during the same macro run
&apos;&apos;&apos; The encoding to be used may be chosen by the user
&apos;&apos;&apos; The list is in the Name column of https://www.iana.org/assignments/character-sets/character-sets.xhtml
&apos;&apos;&apos; Note that probably not all values are available
&apos;&apos;&apos; Line delimiters may be chosen by the user
&apos;&apos;&apos; In input, CR, LF or CR+LF are supported
&apos;&apos;&apos; In output, the default value is the usual newline on the actual operating system (see SF_FileSystem.sfNEWLINE)
&apos;&apos;&apos;
&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/textstream-object
&apos;&apos;&apos; The implementation is mainly based on the XTextInputStream and XTextOutputStream UNO interfaces
&apos;&apos;&apos; https://api.libreoffice.org/docs/idl/ref/interfacecom_1_1sun_1_1star_1_1io_1_1XTextInputStream.html
&apos;&apos;&apos; https://api.libreoffice.org/docs/idl/ref/interfacecom_1_1sun_1_1star_1_1io_1_1XTextOutputStream.html
&apos;&apos;&apos;
&apos;&apos;&apos; Disk file systems and document&apos;s internal file systems
&apos;&apos;&apos; All methods and properties are applicable without restrictions on both file systems.
&apos;&apos;&apos; However, when updates are operated on text files embedded in a document, (with the WriteXXX() methods),
&apos;&apos;&apos; the updates are first done on a copy of the original file. When the file is closed, the copy
&apos;&apos;&apos; will overwrite the original file. The whole process is transparent for the user script.
&apos;&apos;&apos;
&apos;&apos;&apos; Instantiation example:
&apos;&apos;&apos; Dim FSO As Object, myFile As Object
&apos;&apos;&apos; Set FSO = CreateScriptService(&quot;FileSystem&quot;)
&apos;&apos;&apos; Set myFile = FSO.OpenTextFile(&quot;C:\Temp\ThisFile.txt&quot;, FSO.ForReading) &apos; Once per file
&apos;&apos;&apos;
&apos;&apos;&apos; Detailed user documentation:
&apos;&apos;&apos; https://help.libreoffice.org/latest/en-US/text/sbasic/shared/03/sf_textstream.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 FILENOTOPENERROR = &quot;FILENOTOPENERROR&quot; &apos; The file is already closed
Const FILEOPENMODEERROR = &quot;FILEOPENMODEERROR&quot; &apos; The file is open in incompatible mode
Const ENDOFFILEERROR = &quot;ENDOFFILEERROR&quot; &apos; When file was read, an end-of-file was encountered
REM ============================================================= PRIVATE MEMBERS
Private [Me] As Object
Private [_Parent] As Object
Private ObjectType As String &apos; Must be TEXTSTREAM
Private ServiceName As String
Private _FileName As String &apos; File where it is about in URL format
Private _IOMode As Integer &apos; ForReading, ForWriting or ForAppending
Private _Encoding As String &apos; https://www.iana.org/assignments/character-sets/character-sets.xhtml
Private _NewLine As String &apos; Line break in write mode
Private _FileExists As Boolean &apos; True if file exists before open
Private _LineNumber As Long &apos; Number of lines read or written
Private _FileHandler As Object &apos; com.sun.star.io.XInputStream or
&apos; com.sun.star.io.XOutputStream or
&apos; com.sun.star.io.XStream
Private _InputStream As Object &apos; com.sun.star.io.TextInputStream
Private _OutputStream As Object &apos; com.sun.star.io.TextOutputStream
Private _ForceBlankLine As Boolean &apos; Workaround: XTextInputStream misses last line if file ends with newline
&apos; Document&apos;s file system only
Private _IsEmbeddedFile As Boolean &apos; True when concerned file is embedded in a document
Private _EmbeddedFileName As String &apos; When not blank and in update mode, the full embedded file name
&apos; This file is initially copied in a temporary storage, modified by the actual class,
&apos; and rewritten in the document when the textstream.CloseFile() method is run
REM ============================================================ MODULE CONSTANTS
REM ===================================================== CONSTRUCTOR/DESTRUCTOR
REM -----------------------------------------------------------------------------
Private Sub Class_Initialize()
Set [Me] = Nothing
Set [_Parent] = Nothing
ObjectType = &quot;TEXTSTREAM&quot;
ServiceName = &quot;ScriptForge.TextStream&quot;
_FileName = &quot;&quot;
_IOMode = -1
_Encoding = &quot;&quot;
_NewLine = &quot;&quot;
_FileExists = False
_LineNumber = 0
Set _FileHandler = Nothing
Set _InputStream = Nothing
Set _OutputStream = Nothing
_ForceBlankLine = False
_IsEmbeddedFile = False
_EmbeddedFileName = &quot;&quot;
End Sub &apos; ScriptForge.SF_TextStream Constructor
REM -----------------------------------------------------------------------------
Private Sub Class_Terminate()
Call Class_Initialize()
End Sub &apos; ScriptForge.SF_TextStream Destructor
REM -----------------------------------------------------------------------------
Public Function Dispose() As Variant
Call Class_Terminate()
Set Dispose = Nothing
End Function &apos; ScriptForge.SF_TextStream Explicit Destructor
REM ================================================================== PROPERTIES
REM -----------------------------------------------------------------------------
Property Get AtEndOfStream() As Boolean
&apos;&apos;&apos; In reading mode, True indicates that the end of the file has been reached
&apos;&apos;&apos; In write and append modes, or if the file is not ready =&gt; always True
&apos;&apos;&apos; The property should be invoked BEFORE each ReadLine() method:
&apos;&apos;&apos; A ReadLine() executed while AtEndOfStream is True will raise an error
&apos;&apos;&apos; Example:
&apos;&apos;&apos; Dim sLine As String
&apos;&apos;&apos; Do While Not myFile.AtEndOfStream
&apos;&apos;&apos; sLine = myFile.ReadLine()
&apos;&apos;&apos; &apos; ...
&apos;&apos;&apos; Loop
AtEndOfStream = _PropertyGet(&quot;AtEndOfStream&quot;)
End Property &apos; ScriptForge.SF_TextStream.AtEndOfStream
REM -----------------------------------------------------------------------------
Property Get Encoding() As String
&apos;&apos;&apos; Returns the name of the text file either in url or in native operating system format
&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\myFile.txt&quot;)
&apos;&apos;&apos; MsgBox myFile.Encoding &apos; UTF-8
Encoding = _PropertyGet(&quot;Encoding&quot;)
End Property &apos; ScriptForge.SF_TextStream.Encoding
REM -----------------------------------------------------------------------------
Property Get FileName() As String
&apos;&apos;&apos; Returns the name of the text file either in url or in native operating system format
&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\myFile.txt&quot;)
&apos;&apos;&apos; MsgBox myFile.FileName &apos; C:\Temp\myFile.txt
FileName = _PropertyGet(&quot;FileName&quot;)
End Property &apos; ScriptForge.SF_TextStream.FileName
REM -----------------------------------------------------------------------------
Property Get IOMode() As String
&apos;&apos;&apos; Returns either &quot;READ&quot;, &quot;WRITE&quot; or &quot;APPEND&quot;
&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\myFile.txt&quot;)
&apos;&apos;&apos; MsgBox myFile.IOMode &apos; READ
IOMode = _PropertyGet(&quot;IOMode&quot;)
End Property &apos; ScriptForge.SF_TextStream.IOMode
REM -----------------------------------------------------------------------------
Property Get Line() As Long
&apos;&apos;&apos; Returns the number of lines read or written so far
&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\myFile.txt&quot;, FSO.ForAppending)
&apos;&apos;&apos; MsgBox myFile.Line &apos; The number of lines already present in myFile
Line = _PropertyGet(&quot;Line&quot;)
End Property &apos; ScriptForge.SF_TextStream.Line
REM -----------------------------------------------------------------------------
Property Get NewLine() As Variant
&apos;&apos;&apos; Returns the current character string to be inserted between 2 successive written lines
&apos;&apos;&apos; The default value is the native line separator in the current operating system
&apos;&apos;&apos; Example:
&apos;&apos;&apos; MsgBox myFile.NewLine
NewLine = _PropertyGet(&quot;NewLine&quot;)
End Property &apos; ScriptForge.SF_TextStream.NewLine (get)
REM -----------------------------------------------------------------------------
Property Let NewLine(ByVal pvLineBreak As Variant)
&apos;&apos;&apos; Sets the current character string to be inserted between 2 successive written lines
&apos;&apos;&apos; Example:
&apos;&apos;&apos; myFile.NewLine = Chr(13) &amp; Chr(10)
Const cstThisSub = &quot;TextStream.setNewLine&quot;
SF_Utils._EnterFunction(cstThisSub)
If VarType(pvLineBreak) = V_STRING Then _NewLine = pvLineBreak
SF_Utils._ExitFunction(cstThisSub)
End Property &apos; ScriptForge.SF_TextStream.NewLine (let)
REM ===================================================================== METHODS
REM -----------------------------------------------------------------------------
Public Function CloseFile() As Boolean
&apos;&apos;&apos; Empties the output buffer if relevant. Closes the actual input or output stream
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; True if the closure was successful
&apos;&apos;&apos; Exceptions:
&apos;&apos;&apos; FILENOTOPENERROR Nothing found to close
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; myFile.CloseFile()
Dim bClose As Boolean &apos; Return value
Dim oSfa As Object &apos; com.sun.star.ucb.SimpleFileAccess
Const cstThisSub = &quot;TextStream.CloseFile&quot;
Const cstSubArgs = &quot;&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
bClose = False
Check:
SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
If Not _IsFileOpen() Then GoTo Finally
Try:
If Not IsNull(_InputStream) Then _InputStream.closeInput()
If Not IsNull(_OutputStream) Then
_OutputStream.flush()
_OutputStream.closeOutput()
End If
Set _InputStream = Nothing
Set _OutputStream = Nothing
Set _FileHandler = Nothing
&apos; Manage embedded file closure: copy temporary file to document internal storage
If _IsEmbeddedFile Then
Set oSfa = SF_Utils._GetUnoService(&quot;FileAccess&quot;)
oSfa.copy(_FileName, _EmbeddedFileName)
End If
bClose = True
Finally:
CloseFile = bClose
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
End Function &apos; ScriptForge.SF_TextStream.CloseFile
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; If the property does not exist, returns Null
&apos;&apos;&apos; Exceptions:
&apos;&apos;&apos; see the exceptions of the individual properties
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; myModel.GetProperty(&quot;MyProperty&quot;)
Const cstThisSub = &quot;TextStream.GetProperty&quot;
Const cstSubArgs = &quot;&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:
GetProperty = _PropertyGet(PropertyName)
Finally:
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
End Function &apos; ScriptForge.SF_TextStream.GetProperty
REM -----------------------------------------------------------------------------
Public Function Methods() As Variant
&apos;&apos;&apos; Return the list of public methods of the Model service as an array
Methods = Array( _
&quot;CloseFile&quot; _
, &quot;ReadAll&quot; _
, &quot;readLine&quot; _
, &quot;SkipLine&quot; _
, &quot;WriteBlankLines&quot; _
, &quot;WriteLine&quot; _
)
End Function &apos; ScriptForge.SF_TextStream.Methods
REM -----------------------------------------------------------------------------
Public Function Properties() As Variant
&apos;&apos;&apos; Return the list or properties of the Timer class as an array
Properties = Array( _
&quot;AtEndOfStream&quot; _
, &quot;Encoding&quot; _
, &quot;FileName&quot; _
, &quot;IOMode&quot; _
, &quot;Line&quot; _
, &quot;NewLine&quot; _
)
End Function &apos; ScriptForge.SF_TextStream.Properties
REM -----------------------------------------------------------------------------
Public Function ReadAll() As String
&apos;&apos;&apos; Returns all the remaining lines in the text stream as one string. Line breaks are NOT removed
&apos;&apos;&apos; The resulting string can be split in lines
&apos;&apos;&apos; either by using the usual Split Basic builtin function if the line delimiter is known
&apos;&apos;&apos; or with the SF_String.SplitLines method
&apos;&apos;&apos; For large files, using the ReadAll method wastes memory resources.
&apos;&apos;&apos; Other techniques should be used to input a file, such as reading a file line-by-line
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; The read lines. The string may be empty.
&apos;&apos;&apos; Note that the Line property in incremented only by 1
&apos;&apos;&apos; Exceptions:
&apos;&apos;&apos; FILENOTOPENERROR File not open or already closed
&apos;&apos;&apos; FILEOPENMODEERROR File opened in write or append modes
&apos;&apos;&apos; ENDOFFILEERROR Previous reads already reached the end of the file
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; Dim a As String
&apos;&apos;&apos; a = myFile.ReadAll()
Dim sRead As String &apos; Return value
Const cstThisSub = &quot;TextStream.ReadAll&quot;
Const cstSubArgs = &quot;&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
sRead = &quot;&quot;
Check:
If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not _IsFileOpen(&quot;READ&quot;) Then GoTo Finally
If _InputStream.isEOF() Then GoTo CatchEOF
End If
Try:
sRead = _InputStream.readString(Array(), False)
_LineNumber = _LineNumber + 1
Finally:
ReadAll = sRead
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
CatchEOF:
SF_Exception.RaiseFatal(ENDOFFILEERROR, FileName)
GoTo Finally
End Function &apos; ScriptForge.SF_TextStream.ReadAll
REM -----------------------------------------------------------------------------
Public Function ReadLine() As String
&apos;&apos;&apos; Returns the next line in the text stream as a string. Line breaks are removed.
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; The read line. The string may be empty.
&apos;&apos;&apos; Exceptions:
&apos;&apos;&apos; FILENOTOPENERROR File not open or already closed
&apos;&apos;&apos; FILEOPENMODEERROR File opened in write or append modes
&apos;&apos;&apos; ENDOFFILEERROR Previous reads already reached the end of the file
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; Dim a As String
&apos;&apos;&apos; a = myFile.ReadLine()
Dim sRead As String &apos; Return value
Dim iRead As Integer &apos; Length of line break
Const cstThisSub = &quot;TextStream.ReadLine&quot;
Const cstSubArgs = &quot;&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
sRead = &quot;&quot;
Check:
If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not _IsFileOpen(&quot;READ&quot;) Then GoTo Finally
If AtEndOfStream Then GoTo CatchEOF
End If
Try:
&apos; When the text file ends with a line break,
&apos; XTextInputStream.readLine() returns the line break together with the last line
&apos; Hence the workaround to force a blank line at the end
If _ForceBlankLine Then
sRead = &quot;&quot;
_ForceBlankLine = False
Else
sRead = _InputStream.readLine()
&apos; The isEOF() is set immediately after having read the last line
If _InputStream.isEOF() And Len(sRead) &gt; 0 Then
iRead = 0
If SF_String.EndsWith(sRead, SF_String.sfCRLF) Then
iRead = 2
ElseIf SF_String.EndsWith(sRead, SF_String.sfLF) Or SF_String.EndsWith(sRead, SF_String.sfCR) Then
iRead = 1
End If
If iRead &gt; 0 Then
sRead = Left(sRead, Len(sRead) - iRead)
_ForceBlankLine = True &apos; Provision for a last empty line at the next read loop
End If
End If
End If
_LineNumber = _LineNumber + 1
Finally:
ReadLine = sRead
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
CatchEOF:
SF_Exception.RaiseFatal(ENDOFFILEERROR, FileName)
GoTo Finally
End Function &apos; ScriptForge.SF_TextStream.ReadLine
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
Dim bSet As Boolean &apos; Return value
Const cstThisSub = &quot;TextStream.SetProperty&quot;
Const cstSubArgs = &quot;PropertyName, Value&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
bSet = 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:
bSet = True
Select Case UCase(PropertyName)
Case &quot;NEWLINE&quot;
If Not SF_Utils._Validate(Value, &quot;Value&quot;, V_STRING) Then GoTo Catch
NewLine = Value
Case Else
bSet = False
End Select
Finally:
SetProperty = bSet
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
End Function &apos; ScriptForge.SF_TextStream.SetProperty
REM -----------------------------------------------------------------------------
Public Sub SkipLine()
&apos;&apos;&apos; Skips the next line when reading a TextStream file.
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Exceptions:
&apos;&apos;&apos; FILENOTOPENERROR File not open or already closed
&apos;&apos;&apos; FILEOPENMODEERROR File opened in write or append modes
&apos;&apos;&apos; ENDOFFILEERROR Previous reads already reached the end of the file
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; myFile.SkipLine()
Dim sRead As String &apos; Read buffer
Const cstThisSub = &quot;TextStream.SkipLine&quot;
Const cstSubArgs = &quot;&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
Check:
If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not _IsFileOpen(&quot;READ&quot;) Then GoTo Finally
If Not _ForceBlankLine Then &apos; The file ends with a newline =&gt; return one empty line more
If _InputStream.isEOF() Then GoTo CatchEOF
End If
End If
Try:
sRead = ReadLine()
Finally:
SF_Utils._ExitFunction(cstThisSub)
Exit Sub
Catch:
GoTo Finally
CatchEOF:
SF_Exception.RaiseFatal(ENDOFFILEERROR, FileName)
GoTo Finally
End Sub &apos; ScriptForge.SF_TextStream.SkipLine
REM -----------------------------------------------------------------------------
Public Sub WriteBlankLines(Optional ByVal Lines As Variant)
&apos;&apos;&apos; Writes a number of empty lines in the output stream
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Lines: the number of lines to write
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; Exceptions:
&apos;&apos;&apos; FILENOTOPENERROR File not open or already closed
&apos;&apos;&apos; FILEOPENMODEERROR File opened in read mode
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; myFile.WriteBlankLines(10)
Dim i As Long
Const cstThisSub = &quot;TextStream.WriteBlankLines&quot;
Const cstSubArgs = &quot;Lines&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
Check:
If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not _IsFileOpen(&quot;WRITE&quot;) Then GoTo Finally
If Not SF_Utils._Validate(Lines, &quot;Lines&quot;, V_NUMERIC) Then GoTo Finally
End If
Try:
For i = 1 To Lines
_OutputStream.writeString(_NewLine)
Next i
_LineNumber = _LineNumber + Lines
Finally:
SF_Utils._ExitFunction(cstThisSub)
Exit Sub
Catch:
GoTo Finally
End Sub &apos; ScriptForge.SF_TextStream.WriteBlankLines
REM -----------------------------------------------------------------------------
Public Sub WriteLine(Optional ByVal Line As Variant)
&apos;&apos;&apos; Writes the given line to the output stream. A newline is inserted if relevant
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Line: the line to write, may be empty
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; Exceptions:
&apos;&apos;&apos; FILENOTOPENERROR File not open or already closed
&apos;&apos;&apos; FILEOPENMODEERROR File opened in in read mode
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; myFile.WriteLine(&quot;Next line&quot;)
Dim i As Long
Const cstThisSub = &quot;TextStream.WriteLine&quot;
Const cstSubArgs = &quot;Line&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
Check:
If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not _IsFileOpen(&quot;WRITE&quot;) Then GoTo Finally
If Not SF_Utils._Validate(Line, &quot;Line&quot;, V_STRING) Then GoTo Finally
End If
Try:
_OutputStream.writeString(Iif(_LineNumber &gt; 0, _NewLine, &quot;&quot;) &amp; Line)
_LineNumber = _LineNumber + 1
Finally:
SF_Utils._ExitFunction(cstThisSub)
Exit Sub
Catch:
GoTo Finally
End Sub &apos; ScriptForge.SF_TextStream.WriteLine
REM =========================================================== PRIVATE FUNCTIONS
REM -----------------------------------------------------------------------------
Public Sub _Initialize()
&apos;&apos;&apos; Opens file and setup input and/or output streams (ForAppending requires both)
Dim oSfa As Object &apos; com.sun.star.ucb.SimpleFileAccess
&apos; Default newline related to current operating system
_NewLine = SF_String.sfNEWLINE
Set oSfa = SF_Utils._GetUNOService(&quot;FileAccess&quot;)
&apos; Setup input and/or output streams based on READ/WRITE/APPEND IO modes
Select Case _IOMode
Case SF_FileSystem.ForReading
Set _FileHandler = oSfa.openFileRead(_FileName)
Set _InputStream = CreateUnoService(&quot;com.sun.star.io.TextInputStream&quot;)
_InputStream.setInputStream(_FileHandler)
Case SF_FileSystem.ForWriting
&apos; Output file is deleted beforehand
If _FileExists Then oSfa.kill(_FileName)
Set _FileHandler = oSfa.openFileWrite(_FileName)
Set _OutputStream = CreateUnoService(&quot;com.sun.star.io.TextOutputStream&quot;)
_OutputStream.setOutputStream(_FileHandler)
Case SF_FileSystem.ForAppending
Set _FileHandler = oSfa.openFileReadWrite(_FileName)
Set _InputStream = CreateUnoService(&quot;com.sun.star.io.TextInputStream&quot;)
Set _OutputStream = CreateUnoService(&quot;com.sun.star.io.TextOutputStream&quot;)
_InputStream.setInputStream(_FileHandler)
&apos; Position at end of file: Skip and count existing lines
_LineNumber = 0
Do While Not _InputStream.isEOF()
_InputStream.readLine()
_LineNumber = _LineNumber + 1
Loop
_OutputStream.setOutputStream(_FileHandler)
End Select
If _Encoding = &quot;&quot; Then _Encoding = &quot;UTF-8&quot;
If Not IsNull(_InputStream) Then _InputStream.setEncoding(_Encoding)
If Not IsNull(_OutputStream) Then _OutputStream.setEncoding(_Encoding)
End Sub &apos; ScriptForge.SF_TextStream._Initialize
REM -----------------------------------------------------------------------------
Private Function _IsFileOpen(Optional ByVal psMode As String) As Boolean
&apos;&apos;&apos; Checks if file is open with the right mode (READ or WRITE)
&apos;&apos;&apos; Raises an exception if the file is not open at all or not in the right mode
&apos;&apos;&apos; Args:
&apos;&apos;&apos; psMode: READ or WRITE or zero-length string
&apos;&apos;&apos; Exceptions:
&apos;&apos;&apos; FILENOTOPENERROR File not open or already closed
&apos;&apos;&apos; FILEOPENMODEERROR File opened in incompatible mode
_IsFileOpen = False
If IsMissing(psMode) Then psMode = &quot;&quot;
If IsNull(_InputStream) And IsNull(_OutputStream) Then GoTo CatchNotOpen
Select Case psMode
Case &quot;READ&quot;
If IsNull(_InputStream) Then GoTo CatchOpenMode
If _IOMode &lt;&gt; SF_FileSystem.ForReading Then GoTo CatchOpenMode
Case &quot;WRITE&quot;
If IsNull(_OutputStream) Then GoTo CatchOpenMode
If _IOMode = SF_FileSystem.ForReading Then GoTo CatchOpenMode
Case Else
End Select
_IsFileOpen = True
Finally:
Exit Function
CatchNotOpen:
SF_Exception.RaiseFatal(FILENOTOPENERROR, FileName)
GoTo Finally
CatchOpenMode:
SF_Exception.RaiseFatal(FILEOPENMODEERROR, FileName, IOMode)
GoTo Finally
End Function &apos; ScriptForge.SF_TextStream._IsFileOpen
REM -----------------------------------------------------------------------------
Private Function _PropertyGet(Optional ByVal psProperty As String)
&apos;&apos;&apos; Return the value of the named property
&apos;&apos;&apos; Args:
&apos;&apos;&apos; psProperty: the name of the property
Dim cstThisSub As String
Dim cstSubArgs As String
cstThisSub = &quot;TextStream.get&quot; &amp; psProperty
cstSubArgs = &quot;&quot;
SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
Select Case UCase(psProperty)
Case UCase(&quot;AtEndOfStream&quot;)
Select Case _IOMode
Case SF_FileSystem.ForReading
If IsNull(_InputStream) Then _PropertyGet = True Else _PropertyGet = CBool(_InputStream.isEOF() And Not _ForceBlankLine)
Case Else : _PropertyGet = True
End Select
Case UCase(&quot;Encoding&quot;)
_PropertyGet = _Encoding
Case UCase(&quot;FileName&quot;)
&apos; Requested is the user visible file name in FileNaming notation
_PropertyGet = SF_FileSystem._ConvertFromUrl(Iif(_IsEmbeddedFile, _EmbeddedFileName, _FileName))
Case UCase(&quot;IOMode&quot;)
With SF_FileSystem
Select Case _IOMode
Case .ForReading : _PropertyGet = &quot;READ&quot;
Case .ForWriting : _PropertyGet = &quot;WRITE&quot;
Case .ForAppending : _PropertyGet = &quot;APPEND&quot;
Case Else : _PropertyGet = &quot;&quot;
End Select
End With
Case UCase(&quot;Line&quot;)
_PropertyGet = _LineNumber
Case UCase(&quot;NewLine&quot;)
_PropertyGet = _NewLine
Case Else
_PropertyGet = Null
End Select
Finally:
SF_Utils._ExitFunction(cstThisSub)
Exit Function
End Function &apos; ScriptForge.SF_TextStream._PropertyGet
REM -----------------------------------------------------------------------------
Private Function _Repr() As String
&apos;&apos;&apos; Convert the TextStream instance to a readable string, typically for debugging purposes (DebugPrint ...)
&apos;&apos;&apos; Args:
&apos;&apos;&apos; Return:
&apos;&apos;&apos; &quot;[TextStream]: File name, IOMode, LineNumber&quot;
_Repr = &quot;[TextStream]: &quot; &amp; FileName &amp; &quot;,&quot; &amp; IOMode &amp; &quot;,&quot; &amp; CStr(Line)
End Function &apos; ScriptForge.SF_TextStream._Repr
REM ============================================ END OF SCRIPTFORGE.SF_TextStream
</script:module>