From 92e7d50bab5646b2752c25768d1d403fcd983540 Mon Sep 17 00:00:00 2001 From: JeremyStarTM Date: Sun, 22 Dec 2024 14:21:05 +0100 Subject: [PATCH] Add support for file streams --- .../exception/io/StreamClosedException.kt | 32 ++ .../base/implementable/stream/FileStream.kt | 439 ++++++++++++++++++ .../implementable/stream/ReadFileStream.kt | 30 ++ .../implementable/stream/WriteFileStream.kt | 33 ++ .../base/implementable/stream/package-info.kt | 25 + .../implementation/stream/FileAccessStream.kt | 134 ++++++ .../implementation/stream/LoggerFileStream.kt | 90 ++++ .../implementation/stream/NullFileStream.kt | 55 +++ .../implementation/stream/package-info.kt | 27 ++ .../engine/base/logging/Logger.kt | 26 +- .../engine/base/utility/FileAccess.kt | 27 ++ 11 files changed, 917 insertions(+), 1 deletion(-) create mode 100644 base/src/main/kotlin/de/staropensource/engine/base/exception/io/StreamClosedException.kt create mode 100644 base/src/main/kotlin/de/staropensource/engine/base/implementable/stream/FileStream.kt create mode 100644 base/src/main/kotlin/de/staropensource/engine/base/implementable/stream/ReadFileStream.kt create mode 100644 base/src/main/kotlin/de/staropensource/engine/base/implementable/stream/WriteFileStream.kt create mode 100644 base/src/main/kotlin/de/staropensource/engine/base/implementable/stream/package-info.kt create mode 100644 base/src/main/kotlin/de/staropensource/engine/base/implementation/stream/FileAccessStream.kt create mode 100644 base/src/main/kotlin/de/staropensource/engine/base/implementation/stream/LoggerFileStream.kt create mode 100644 base/src/main/kotlin/de/staropensource/engine/base/implementation/stream/NullFileStream.kt create mode 100644 base/src/main/kotlin/de/staropensource/engine/base/implementation/stream/package-info.kt 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.