diff --git a/base/src/main/kotlin/de/staropensource/engine/base/exception/io/StreamClosedException.kt b/base/src/main/kotlin/de/staropensource/engine/base/exception/io/StreamClosedException.kt
new file mode 100644
index 000000000..a11f5be82
--- /dev/null
+++ b/base/src/main/kotlin/de/staropensource/engine/base/exception/io/StreamClosedException.kt
@@ -0,0 +1,32 @@
+/*
+ * STAROPENSOURCE ENGINE SOURCE FILE
+ * Copyright (c) 2024 The StarOpenSource Engine Authors
+ * Licensed under the GNU General Public License v3.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package de.staropensource.engine.base.exception.io
+
+import de.staropensource.engine.base.implementable.stream.FileStream
+
+/**
+ * Thrown when trying to
+ * access a closed [FileStream].
+ *
+ * @see FileStream
+ * @see FileStream.closed
+ * @since v1-alpha10
+ */
+class StreamClosedException(stream: FileStream) : RuntimeException("The file stream ${stream} was access whilst already closed")
diff --git a/base/src/main/kotlin/de/staropensource/engine/base/implementable/stream/FileStream.kt b/base/src/main/kotlin/de/staropensource/engine/base/implementable/stream/FileStream.kt
new file mode 100644
index 000000000..f593e9b9a
--- /dev/null
+++ b/base/src/main/kotlin/de/staropensource/engine/base/implementable/stream/FileStream.kt
@@ -0,0 +1,439 @@
+/*
+ * STAROPENSOURCE ENGINE SOURCE FILE
+ * Copyright (c) 2024 The StarOpenSource Engine Authors
+ * Licensed under the GNU General Public License v3.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package de.staropensource.engine.base.implementable.stream
+
+import de.staropensource.engine.base.annotation.NonKotlinContact
+import de.staropensource.engine.base.exception.io.IOAccessException
+import de.staropensource.engine.base.implementation.stream.NullFileStream
+import java.io.IOException
+import java.io.InputStream
+import java.io.OutputStream
+
+/**
+ * Makes streaming data easy.
+ *
+ * @param streamMode supported [StreamMode]s
+ * @since v1-alpha10
+ */
+abstract class FileStream(val streamMode: StreamMode) : AutoCloseable {
+ /**
+ * Companion object of [FileStream].
+ *
+ * @since v1-alpha10
+ */
+ companion object {
+ /**
+ * Returns a [FileStream] which does nothing.
+ *
+ * @since v1-alpha10
+ */
+ val nullStream: FileStream = NullFileStream.instance
+ }
+
+
+ // -----> Properties
+ /**
+ * Indicates whether this stream is closed.
+ *
+ * @since v1-alpha10
+ */
+ var closed: Boolean = false
+ private set
+
+ /**
+ * Contains the [java.io.InputStream]
+ * for this [FileStream] instance.
+ *
+ * @since v1-alpha10
+ */
+ private var inputStream: InputFileStream? = null
+
+ /**
+ * Contains the [java.io.OutputStream]
+ * for this [FileStream] instance.
+ *
+ * @since v1-alpha10
+ */
+ private var outputStream: OutputFileStream? = null
+
+
+ // -----> Closure
+ /**
+ * Closes this stream.
+ *
+ * @throws IOAccessException on IO error
+ * @since v1-alpha10
+ */
+ @Throws(IOAccessException::class)
+ override fun close() {
+ if (closed)
+ return
+
+ closed = true
+ closeStream()
+ }
+
+ /**
+ * Closes this stream.
+ *
+ * This method may be used by the
+ * implementation to close the stream.
+ *
+ * @throws IOAccessException on IO error
+ * @since v1-alpha10
+ */
+ @Throws(IOAccessException::class)
+ protected abstract fun closeStream()
+
+
+ // -----> Writing
+ /**
+ * Writes (or rather: appends)
+ * the specified [Byte].
+ *
+ * If you don't intend on optimizing
+ * for a single byte, just add this
+ * line to your implementation instead:
+ * ```kotlin
+ * override fun writeByte(byte: Byte): FileStream = writeBytes(byteArrayOf(byte))
+ * ```
+ *
+ * @param byte [Byte] to write
+ * @return this instance
+ * @throws IOAccessException on IO error
+ * @since v1-alpha10
+ */
+ @Throws(IOAccessException::class)
+ abstract fun writeByte(byte: Byte): FileStream
+
+ /**
+ * Writes (or rather: appends)
+ * the specified [Byte]s.
+ *
+ * @param bytes [Byte]s to write
+ * @return this instance
+ * @throws IOAccessException on IO error
+ * @since v1-alpha10
+ */
+ @Throws(IOAccessException::class)
+ abstract fun writeBytes(bytes: ByteArray): FileStream
+
+ /**
+ * Writes (or rather: appends)
+ * the specified [String].
+ *
+ * @param string [String] to write
+ * @return this instance
+ * @throws IOAccessException on IO error
+ * @since v1-alpha10
+ */
+ @Throws(IOAccessException::class)
+ fun writeString(string: String): FileStream = writeBytes(string.toByteArray())
+
+ /**
+ * Writes (or rather: appends)
+ * the specified value.
+ *
+ * @param value value to write
+ * @return this instance
+ * @throws IOAccessException on IO error
+ * @since v1-alpha10
+ */
+ @Throws(IOAccessException::class)
+ fun write(value: Any): FileStream = writeBytes(value.toString().toByteArray())
+
+
+ // -----> Reading
+ /**
+ * Returns whether any more
+ * bytes can be read from
+ * this stream.
+ *
+ * Returns `null` if unsupported
+ * by the implementation.
+ *
+ * @return if bytes are remaining or `null` if unsupported
+ * @throws IOAccessException on IO error
+ * @since v1-alpha10
+ */
+ @Throws(IOAccessException::class)
+ abstract fun remaining(): Boolean?
+
+ /**
+ * Returns the amount of
+ * [Byte]s which can be
+ * read without blocking.
+ *
+ * May or may not be
+ * equal to `0`
+ *
+ * @return amount of [Byte]s to read without blocking
+ * @throws IOAccessException on IO error
+ * @since v1-alpha10
+ */
+ @Throws(IOAccessException::class)
+ abstract fun available(): UInt
+
+ /**
+ * Reads the next [Byte].
+ *
+ * @return next [Byte] or `null` if no bytes are remaining
+ * @throws IOAccessException on IO error
+ * @since v1-alpha10
+ */
+ @Throws(IOAccessException::class)
+ abstract fun readNextByte(): Byte?
+
+ /**
+ * Reads the specified next [n] [Byte]s.
+ *
+ * @param n [Byte]s to read
+ * @return next [n] bytes or an empty array if no bytes are remaining
+ * @throws IOAccessException on IO error
+ * @since v1-alpha10
+ */
+ @Throws(IOAccessException::class)
+ abstract fun readNBytes(n: UInt): ByteArray
+
+ /**
+ * Reads all remaining [Byte]s.
+ *
+ * @return remaining [Byte]s or an empty array if no bytes are remaining
+ * @throws IOAccessException on IO error
+ * @since v1-alpha10
+ */
+ @Throws(IOAccessException::class)
+ abstract fun readRemainingBytes(): ByteArray
+
+ /**
+ * Discards the next [Byte].
+ *
+ * @return this instance
+ * @throws IOAccessException on IO error
+ * @since v1-alpha10
+ */
+ @Throws(IOAccessException::class)
+ fun skipNextByte(): FileStream {
+ readNextByte()
+ return this
+ }
+
+ /**
+ * Discards the specified next [n] bytes.
+ *
+ * @param n [Byte]s to discard
+ * @return this instance
+ * @throws IOAccessException on IO error
+ * @since v1-alpha10
+ */
+ @Throws(IOAccessException::class)
+ fun skipNBytes(n: UInt): FileStream {
+ readNBytes(n)
+ return this
+ }
+
+ /**
+ * Discards all remaining [Byte]s.
+ *
+ * @return this instance
+ * @throws IOAccessException on IO error
+ * @since v1-alpha10
+ */
+ @Throws(IOAccessException::class)
+ fun skipRemainingBytes(): FileStream {
+ readRemainingBytes()
+ return this
+ }
+
+
+ // -----> Redirection
+ /**
+ * Reads the next byte of this
+ * [FileStream] and writes it
+ * to the specified [FileStream].
+ *
+ * @param stream stream to write to
+ * @return this instance
+ * @throws IOAccessException on IO error
+ * @since v1-alpha10
+ */
+ @Throws(IOAccessException::class)
+ fun writeNextByteTo(stream: FileStream): FileStream {
+ val byte: Byte? = readNextByte()
+
+ if (byte != null)
+ stream.writeByte(byte)
+
+ return this
+ }
+
+ /**
+ * Reads the next [n] byte of this
+ * [FileStream] and writes it
+ * to the specified [FileStream].
+ *
+ * @param stream stream to write to
+ * @return this instance
+ * @throws IOAccessException on IO error
+ * @since v1-alpha10
+ */
+ @Throws(IOAccessException::class)
+ fun writeNBytesTo(stream: FileStream, n: UInt): FileStream {
+ stream.writeBytes(readNBytes(n))
+ return this
+ }
+
+ /**
+ * Reads all bytes of this
+ * [FileStream] and writes
+ * them to the specified
+ * [FileStream].
+ *
+ * @param stream stream to write to
+ * @return this instance
+ * @throws IOAccessException on IO error
+ * @since v1-alpha10
+ */
+ @Throws(IOAccessException::class)
+ fun writeRemainingBytesTo(stream: FileStream): FileStream {
+ stream.writeBytes(readRemainingBytes())
+ return this
+ }
+
+
+ // -----> Java interoperability
+ /**
+ * Returns this stream as
+ * a Java [InputStream].
+ *
+ * @since v1-alpha10
+ */
+ @NonKotlinContact
+ fun toInputStream(): InputStream {
+ if (inputStream == null)
+ inputStream = InputFileStream(this)
+
+ return inputStream!!
+ }
+
+ /**
+ * Returns this stream as
+ * a Java [OutputStream].
+ *
+ * @since v1-alpha10
+ */
+ @NonKotlinContact
+ fun toOutputStream(): OutputStream {
+ if (outputStream == null)
+ outputStream = OutputFileStream(this)
+
+ return outputStream!!
+ }
+
+
+ // -----> Inner classes
+ /**
+ * Represents the mode in which
+ * [FileStream]s can operate in.
+ *
+ * @since v1-alpha10
+ */
+ enum class StreamMode {
+ /**
+ * A [FileStream] which only
+ * supports reading.
+ *
+ * @since v1-alpha10
+ */
+ READ,
+
+ /**
+ * A [FileStream] which only
+ * supports writing.
+ *
+ * @since v1-alpha10
+ */
+ WRITE,
+
+ /**
+ * A [FileStream] which supports
+ * both reading and writing.
+ *
+ * @since v1-alpha10
+ */
+ READ_WRITE,
+ }
+
+ /**
+ * An implementation of Java
+ * [InputStream]s for [FileStream]s.
+ *
+ * @param fileStream [FileStream] to use
+ * @throws IOException on IO error
+ * @since v1-alpha10
+ */
+ class InputFileStream
+ @NonKotlinContact
+ internal constructor(val fileStream: FileStream)
+ : InputStream() {
+ /**
+ * Reads the next byte.
+ *
+ * @return byte read
+ * @throws IOException on IO error
+ * @since v1-alpha10
+ */
+ @Throws(IOException::class)
+ override fun read(): Int = try {
+ fileStream.readNextByte()?.toInt() ?: -1
+ } catch (exception: IOAccessException) {
+ throw IOException("Failed reading the next byte", exception)
+ }
+ }
+
+ /**
+ * An implementation of Java
+ * [OutputStream]s for [FileStream]s.
+ *
+ * @param fileStream [FileStream] to use
+ * @since v1-alpha10
+ */
+ @NonKotlinContact
+ class OutputFileStream
+ @NonKotlinContact
+ internal constructor(val fileStream: FileStream)
+ : OutputStream() {
+ /**
+ * Writes (or rather: appends) a byte.
+ *
+ * @param byte byte to append
+ * @throws IOException on IO error
+ * @since v1-alpha10
+ */
+ @Throws(IOException::class)
+ override fun write(byte: Int) {
+ try {
+ fileStream.writeByte(byte.toByte())
+ } catch (exception: IOAccessException) {
+ throw IOException("Failed writing the next byte", exception)
+ }
+ }
+ }
+}
diff --git a/base/src/main/kotlin/de/staropensource/engine/base/implementable/stream/ReadFileStream.kt b/base/src/main/kotlin/de/staropensource/engine/base/implementable/stream/ReadFileStream.kt
new file mode 100644
index 000000000..596668814
--- /dev/null
+++ b/base/src/main/kotlin/de/staropensource/engine/base/implementable/stream/ReadFileStream.kt
@@ -0,0 +1,30 @@
+/*
+ * STAROPENSOURCE ENGINE SOURCE FILE
+ * Copyright (c) 2024 The StarOpenSource Engine Authors
+ * Licensed under the GNU General Public License v3.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package de.staropensource.engine.base.implementable.stream
+
+/**
+ * A read-only [FileStream].
+ *
+ * @since v1-alpha10
+ */
+abstract class ReadFileStream : FileStream(streamMode = StreamMode.READ) {
+ override fun writeByte(byte: Byte): FileStream = this
+ override fun writeBytes(bytes: ByteArray): FileStream = this
+}
diff --git a/base/src/main/kotlin/de/staropensource/engine/base/implementable/stream/WriteFileStream.kt b/base/src/main/kotlin/de/staropensource/engine/base/implementable/stream/WriteFileStream.kt
new file mode 100644
index 000000000..01392c524
--- /dev/null
+++ b/base/src/main/kotlin/de/staropensource/engine/base/implementable/stream/WriteFileStream.kt
@@ -0,0 +1,33 @@
+/*
+ * STAROPENSOURCE ENGINE SOURCE FILE
+ * Copyright (c) 2024 The StarOpenSource Engine Authors
+ * Licensed under the GNU General Public License v3.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package de.staropensource.engine.base.implementable.stream
+
+/**
+ * A write-only [FileStream].
+ *
+ * @since v1-alpha10
+ */
+abstract class WriteFileStream : FileStream(streamMode = StreamMode.WRITE) {
+ override fun remaining(): Boolean = false
+ override fun available(): UInt = 0u
+ override fun readNextByte(): Byte? = 0x00
+ override fun readNBytes(n: UInt): ByteArray = byteArrayOf()
+ override fun readRemainingBytes(): ByteArray = byteArrayOf()
+}
diff --git a/base/src/main/kotlin/de/staropensource/engine/base/implementable/stream/package-info.kt b/base/src/main/kotlin/de/staropensource/engine/base/implementable/stream/package-info.kt
new file mode 100644
index 000000000..2591b87cb
--- /dev/null
+++ b/base/src/main/kotlin/de/staropensource/engine/base/implementable/stream/package-info.kt
@@ -0,0 +1,25 @@
+/*
+ * STAROPENSOURCE ENGINE SOURCE FILE
+ * Copyright (c) 2024 The StarOpenSource Engine Authors
+ * Licensed under the GNU General Public License v3.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+/**
+ * Streams. Particularly [FileStream]s.
+ *
+ * @since v1-alpha10
+ */
+package de.staropensource.engine.base.implementable.stream
diff --git a/base/src/main/kotlin/de/staropensource/engine/base/implementation/stream/FileAccessStream.kt b/base/src/main/kotlin/de/staropensource/engine/base/implementation/stream/FileAccessStream.kt
new file mode 100644
index 000000000..23a7ac9ec
--- /dev/null
+++ b/base/src/main/kotlin/de/staropensource/engine/base/implementation/stream/FileAccessStream.kt
@@ -0,0 +1,134 @@
+/*
+ * STAROPENSOURCE ENGINE SOURCE FILE
+ * Copyright (c) 2024 The StarOpenSource Engine Authors
+ * Licensed under the GNU General Public License v3.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package de.staropensource.engine.base.implementation.stream
+
+import de.staropensource.engine.base.exception.VerificationFailedException
+import de.staropensource.engine.base.exception.io.IOAccessException
+import de.staropensource.engine.base.exception.io.StreamClosedException
+import de.staropensource.engine.base.implementable.stream.FileStream
+import de.staropensource.engine.base.utility.FileAccess
+import java.io.InputStream
+
+/**
+ * A [FileStream] used exclusively for
+ * accessing files via the [FileAccess]
+ * API.
+ *
+ * @param file [FileAccess] to use
+ * @see FileAccess.toStream
+ * @since v1-alpha10
+ */
+class FileAccessStream internal constructor(val file: FileAccess) : FileStream(streamMode = StreamMode.READ_WRITE) {
+ // -----> Metadata
+ /**
+ * Contains the [InputStream] used
+ * for reading to files.
+ *
+ * @since v1-alpha10
+ */
+ val inputStream: InputStream = file.file.inputStream()
+
+
+ // -----> Closure
+ override fun closeStream() = Unit
+
+
+ // -----> Writing
+ override fun writeByte(byte: Byte): FileStream = writeBytes(byteArrayOf(byte))
+
+ override fun writeBytes(bytes: ByteArray): FileStream {
+ if (closed)
+ throw StreamClosedException(this)
+
+ try {
+ file
+ .createFile()
+ .verifyIsFile()
+ .appendBytes(bytes = bytes, async = false)
+ } catch (_: VerificationFailedException) {
+ throw IOAccessException("File '${file}' does not exist")
+ }
+
+ return this
+ }
+
+
+ // -----> Reading
+ override fun remaining(): Boolean? = null
+
+ override fun available(): UInt {
+ if (closed)
+ throw StreamClosedException(this)
+
+ try {
+ file
+ .createFile()
+ .verifyIsFile()
+
+ return inputStream.available().toUInt()
+ } catch (_: VerificationFailedException) {
+ throw IOAccessException("File '${file}' does not exist")
+ }
+ }
+
+ override fun readNextByte(): Byte? {
+ if (closed)
+ throw StreamClosedException(this)
+
+ try {
+ file
+ .createFile()
+ .verifyIsFile()
+
+ return inputStream.read().toByte()
+ } catch (_: VerificationFailedException) {
+ throw IOAccessException("File '${file}' does not exist")
+ }
+ }
+
+ override fun readNBytes(n: UInt): ByteArray {
+ if (closed)
+ throw StreamClosedException(this)
+
+ try {
+ file
+ .createFile()
+ .verifyIsFile()
+
+ return inputStream.readNBytes(n.toInt())
+ } catch (_: VerificationFailedException) {
+ throw IOAccessException("File '${file}' does not exist")
+ }
+ }
+
+ override fun readRemainingBytes(): ByteArray {
+
+ try {
+ file
+ .createFile()
+ .verifyIsFile()
+
+ return inputStream.readAllBytes()
+ } catch (_: VerificationFailedException) {
+ throw IOAccessException("File '${file}' does not exist")
+ }
+ }
+
+}
diff --git a/base/src/main/kotlin/de/staropensource/engine/base/implementation/stream/LoggerFileStream.kt b/base/src/main/kotlin/de/staropensource/engine/base/implementation/stream/LoggerFileStream.kt
new file mode 100644
index 000000000..1b4d876d4
--- /dev/null
+++ b/base/src/main/kotlin/de/staropensource/engine/base/implementation/stream/LoggerFileStream.kt
@@ -0,0 +1,90 @@
+/*
+ * STAROPENSOURCE ENGINE SOURCE FILE
+ * Copyright (c) 2024 The StarOpenSource Engine Authors
+ * Licensed under the GNU General Public License v3.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package de.staropensource.engine.base.implementation.stream
+
+import de.staropensource.engine.base.implementable.stream.FileStream
+import de.staropensource.engine.base.implementable.stream.WriteFileStream
+import de.staropensource.engine.base.logging.Logger
+import de.staropensource.engine.base.type.logging.Level
+import de.staropensource.engine.base.utility.FileAccess
+
+/**
+ * A [FileStream] used exclusively
+ * for printing log messages.
+ *
+ * A log message is only printed
+ * after a newline (`\n`) is written.
+ *
+ * @param logger [Logger] instance to use
+ * @see FileAccess.toStream
+ * @since v1-alpha10
+ */
+class LoggerFileStream internal constructor(val logger: Logger, val level: Level) : WriteFileStream() {
+ /**
+ * Contains the current line.
+ *
+ * @since v1-alpha10
+ */
+ val line: StringBuilder = StringBuilder()
+
+ override fun closeStream() {
+ logger.stream.remove(level)
+ }
+
+ override fun writeByte(byte: Byte): FileStream = writeBytes(byteArrayOf(byte))
+
+ override fun writeBytes(bytes: ByteArray): FileStream {
+ line.append(bytes.decodeToString())
+
+ checkAndPrint()
+
+ return this
+ }
+
+ /**
+ * Verifies whether [line]
+ * contains a newline and
+ * if so, prints it.
+ *
+ * @since v1-alpha10
+ */
+ private fun checkAndPrint() {
+ if (line.contains("\n")) {
+ var lineFinal: String = line.toString()
+
+ // Remove last newline
+ lineFinal = lineFinal.removeSuffix("\n")
+
+ // Print
+ when (level) {
+ Level.DIAGNOSTIC -> logger.diag(lineFinal)
+ Level.VERBOSE -> logger.verb(lineFinal)
+ Level.SILENT_WARNING -> logger.sarn(lineFinal)
+ Level.INFORMATIONAL -> logger.info(lineFinal)
+ Level.WARNING -> logger.warn(lineFinal)
+ Level.ERROR -> logger.error(lineFinal)
+ Level.CRASH -> logger.crash(lineFinal, throwable = null, fatal = true)
+ }
+
+ // Clear line
+ line.clear()
+ }
+ }
+}
diff --git a/base/src/main/kotlin/de/staropensource/engine/base/implementation/stream/NullFileStream.kt b/base/src/main/kotlin/de/staropensource/engine/base/implementation/stream/NullFileStream.kt
new file mode 100644
index 000000000..05754133f
--- /dev/null
+++ b/base/src/main/kotlin/de/staropensource/engine/base/implementation/stream/NullFileStream.kt
@@ -0,0 +1,55 @@
+/*
+ * STAROPENSOURCE ENGINE SOURCE FILE
+ * Copyright (c) 2024 The StarOpenSource Engine Authors
+ * Licensed under the GNU General Public License v3.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package de.staropensource.engine.base.implementation.stream
+
+import de.staropensource.engine.base.implementable.stream.FileStream
+
+/**
+ * A [de.staropensource.engine.base.implementable.stream.FileStream] which does nothing.
+ *
+ * @since v1-alpha10
+ */
+class NullFileStream private constructor() : FileStream(streamMode = StreamMode.READ_WRITE) {
+ /**
+ * Companion object of [NullFileStream].
+ *
+ * @since v1-alpha10
+ */
+ companion object {
+ /**
+ * Global instance of [NullFileStream].
+ *
+ * @since v1-alpha10
+ */
+ @JvmStatic
+ val instance: NullFileStream = NullFileStream()
+ }
+
+ override fun closeStream() = Unit
+
+ override fun writeByte(byte: Byte): FileStream = this
+ override fun writeBytes(bytes: ByteArray): FileStream = this
+
+ override fun remaining(): Boolean = true
+ override fun available(): UInt = 0u
+ override fun readNextByte(): Byte = 0
+ override fun readNBytes(n: UInt): ByteArray = byteArrayOf()
+ override fun readRemainingBytes(): ByteArray = byteArrayOf()
+}
diff --git a/base/src/main/kotlin/de/staropensource/engine/base/implementation/stream/package-info.kt b/base/src/main/kotlin/de/staropensource/engine/base/implementation/stream/package-info.kt
new file mode 100644
index 000000000..64220784f
--- /dev/null
+++ b/base/src/main/kotlin/de/staropensource/engine/base/implementation/stream/package-info.kt
@@ -0,0 +1,27 @@
+/*
+ * STAROPENSOURCE ENGINE SOURCE FILE
+ * Copyright (c) 2024 The StarOpenSource Engine Authors
+ * Licensed under the GNU General Public License v3.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+/**
+ * Implementations of [FileStream] far and wide.
+ *
+ * @since v1-alpha10
+ */
+package de.staropensource.engine.base.implementation.stream
+
+import de.staropensource.engine.base.implementable.stream.FileStream
diff --git a/base/src/main/kotlin/de/staropensource/engine/base/logging/Logger.kt b/base/src/main/kotlin/de/staropensource/engine/base/logging/Logger.kt
index 195fd98b7..6dc88faf3 100644
--- a/base/src/main/kotlin/de/staropensource/engine/base/logging/Logger.kt
+++ b/base/src/main/kotlin/de/staropensource/engine/base/logging/Logger.kt
@@ -20,7 +20,11 @@
package de.staropensource.engine.base.logging
import de.staropensource.engine.base.EngineConfiguration
+import de.staropensource.engine.base.annotation.NonKotlinContact
import de.staropensource.engine.base.implementable.logging.LoggerThreadingHandler
+import de.staropensource.engine.base.implementable.stream.FileStream
+import de.staropensource.engine.base.implementation.stream.FileAccessStream
+import de.staropensource.engine.base.implementation.stream.LoggerFileStream
import de.staropensource.engine.base.type.logging.Call
import de.staropensource.engine.base.type.logging.Level
import de.staropensource.engine.base.utility.misc.StackTraceUtils
@@ -68,7 +72,7 @@ class Logger {
}
- // -----> Fields
+ // -----> Properties
/**
* Holds the channel this instance uses.
*
@@ -76,6 +80,15 @@ class Logger {
*/
private val channel: String
+ /**
+ * Contains the [LoggerFileStream] for this instance.
+ *
+ * @since v1-alpha10
+ */
+ internal val stream: MutableMap = mutableMapOf()
+ @NonKotlinContact
+ @JvmName(name = "getActualStream") get
+
// -----> Constructors
/**
@@ -218,4 +231,15 @@ class Logger {
fun flush() {
EngineConfiguration.logThreadingHandler?.flush()
}
+
+ /**
+ * Returns a [FileStream] for
+ * writing to the specified
+ * [Level] using this instance.
+ *
+ * @param level [Level] to which the [FileStream] shall log to
+ * @return [FileAccessStream] instance
+ * @since v1-alpha10
+ */
+ fun toStream(level: Level): LoggerFileStream = stream.computeIfAbsent(level) { level -> LoggerFileStream(this, level) }
}
diff --git a/base/src/main/kotlin/de/staropensource/engine/base/utility/FileAccess.kt b/base/src/main/kotlin/de/staropensource/engine/base/utility/FileAccess.kt
index 2875df4f9..66a2d66d8 100644
--- a/base/src/main/kotlin/de/staropensource/engine/base/utility/FileAccess.kt
+++ b/base/src/main/kotlin/de/staropensource/engine/base/utility/FileAccess.kt
@@ -25,6 +25,8 @@ import de.staropensource.engine.base.exception.io.FileOrDirectoryNotFoundExcepti
import de.staropensource.engine.base.exception.io.FileTooLargeException
import de.staropensource.engine.base.exception.io.IOAccessException
import de.staropensource.engine.base.exception.VerificationFailedException
+import de.staropensource.engine.base.implementable.stream.FileStream
+import de.staropensource.engine.base.implementation.stream.FileAccessStream
import de.staropensource.engine.base.utility.Environment.OperatingSystem.*
import de.staropensource.engine.base.utility.FileAccess.Companion.configDirectory
import de.staropensource.engine.base.utility.FileAccess.Companion.format
@@ -301,6 +303,15 @@ class FileAccess {
@JvmName(name = "getJavaFile")
get
+ /**
+ * Contains the [FileAccessStream] for this instance.
+ *
+ * @since v1-alpha10
+ */
+ private var stream: FileAccessStream? = null
+ @NonKotlinContact
+ @JvmName(name = "getActualStream") get
+
// -----> Constructors
/**
@@ -557,6 +568,22 @@ class FileAccess {
}
+ // -----> Streams getters
+ /**
+ * Returns a [FileStream] for reading
+ * and writing from and to this file.
+ *
+ * @return [FileAccessStream] instance
+ * @since v1-alpha10
+ */
+ fun toStream(): FileAccessStream {
+ if (stream == null)
+ stream = FileAccessStream(this)
+
+ return stream!!
+ }
+
+
// -----> File creation, moving, copying and deletion
/**
* Creates a file at this location.