From 278a4c8142c29f60242bb74e83b7f0ac45133735 Mon Sep 17 00:00:00 2001 From: Gerhard Muth Date: Thu, 12 Dec 2024 17:57:02 +0100 Subject: [PATCH] refactored compression support, handle compression transparently, compress only when writing or reading from IPP streams --- .../kotlin/de/gmuth/ipp/core/IppMessage.kt | 67 +++++++++---------- .../kotlin/de/gmuth/ipp/core/IppRequest.kt | 1 - .../de/gmuth/ipp/core/IppMessageTests.kt | 2 +- src/test/resources/logging.properties | 1 + 4 files changed, 33 insertions(+), 38 deletions(-) diff --git a/src/main/kotlin/de/gmuth/ipp/core/IppMessage.kt b/src/main/kotlin/de/gmuth/ipp/core/IppMessage.kt index c3bbe9ab..45d01559 100644 --- a/src/main/kotlin/de/gmuth/ipp/core/IppMessage.kt +++ b/src/main/kotlin/de/gmuth/ipp/core/IppMessage.kt @@ -103,12 +103,17 @@ abstract class IppMessage() { rawBytes = byteArraySavingOutputStream.getSavedBytes() } if (writeDocumentIfAvailable && hasDocument()) { - writeDocument(outputStream) + val outputStreamWithCompressionSupport = + if (operationGroup.containsKey("compression")) compression.getCompressingOutputStream(outputStream) + else outputStream + logger.fine { "Write document using ${outputStreamWithCompressionSupport.javaClass.simpleName}" } + copyUnconsumedDocumentInputStream(outputStreamWithCompressionSupport) + outputStreamWithCompressionSupport.close() // finalize compression } } - fun write(file: File) = - write(FileOutputStream(file)) + fun write(file: File, writeDocumentIfAvailable: Boolean = false) = + write(FileOutputStream(file), writeDocumentIfAvailable) @JvmOverloads fun encode(appendDocumentIfAvailable: Boolean = true) = ByteArrayOutputStream().use { @@ -129,8 +134,17 @@ abstract class IppMessage() { val bufferedInputStream = byteArraySavingInputStream.buffered() try { IppInputStream(bufferedInputStream).readMessage(this) - if (bufferedInputStream.available() > 0) documentInputStream = bufferedInputStream - else logger.finest { "No document bytes available from bufferedInputStream after readMessage()" } + if (bufferedInputStream.available() == 0) { + logger.finest { "No document bytes available from bufferedInputStream after readMessage()" } + } else { + documentInputStream = + if (operationGroup.containsKey("compression")) { + compression.getUncompressingInputStream(bufferedInputStream) + } else { + bufferedInputStream + } + logger.fine { "documentInputStream class: ${documentInputStream!!.javaClass.simpleName}" } + } } finally { rawBytes = byteArrayOutputStream.toByteArray() } @@ -150,40 +164,21 @@ abstract class IppMessage() { // DOCUMENT and IPP-MESSAGE // ------------------------ - fun writeDocument(notCompressingOutputStream: OutputStream) { - if (documentInputStreamIsConsumed) { - throw IppException("documentInputStream is consumed") - // write documentBytes? take care of compression! - } else { - val outputStream = if (operationGroup.containsKey("compression")) { - compression.getCompressingOutputStream(notCompressingOutputStream) - } else { - notCompressingOutputStream - } - logger.fine { "Write document using ${outputStream.javaClass.simpleName}" } - copyUnconsumedDocumentInputStream(outputStream) - outputStream.close() // starts optional compression + private fun copyUnconsumedDocumentInputStream(outputStream: OutputStream) { + if (hasDocument() && documentInputStreamIsConsumed) throw IppException("documentInputStream is consumed") + val outputStreamWithCopySupport = + if (keepDocumentCopy) ByteArraySavingOutputStream(outputStream) + else outputStream + documentInputStream!! + .copyTo(outputStreamWithCopySupport) // returns number of bytes copied + .apply { logger.finer { "Consumed documentInputStreamWithUncompressingSupport: $this bytes" } } + documentInputStreamIsConsumed = true + if (outputStreamWithCopySupport is ByteArraySavingOutputStream) { + documentBytes = outputStreamWithCopySupport.getSavedBytes() + logger.finer("Keeping ${documentBytes!!.size} document bytes") } } - private fun copyUnconsumedDocumentInputStream(outputStream: OutputStream): Long { - if (hasDocument() && documentInputStreamIsConsumed) { - throw IppException("documentInputStream is consumed") - } - val byteArraySavingOutputStream = ByteArraySavingOutputStream(outputStream) - return documentInputStream!! - .copyTo(if (keepDocumentCopy) byteArraySavingOutputStream else outputStream) // number of bytes copied - .apply { - logger.finer { "Consumed documentInputStream: $this bytes" } - documentInputStreamIsConsumed = true - if (keepDocumentCopy) { - documentBytes = byteArraySavingOutputStream.getSavedBytes() - if (documentBytes!!.isNotEmpty()) logger.finer("Keeping ${documentBytes!!.size} document bytes") - } - byteArraySavingOutputStream.close() - } - } - fun saveDocumentBytes(file: File) = file.run { if (documentBytes == null || documentBytes!!.isEmpty()) throw IppException("No documentBytes available. You should enable flag IppMessage.keepDocumentCopy.") outputStream().use { ByteArrayInputStream(documentBytes).copyTo(it) } diff --git a/src/main/kotlin/de/gmuth/ipp/core/IppRequest.kt b/src/main/kotlin/de/gmuth/ipp/core/IppRequest.kt index 09e231f8..6a3b788f 100644 --- a/src/main/kotlin/de/gmuth/ipp/core/IppRequest.kt +++ b/src/main/kotlin/de/gmuth/ipp/core/IppRequest.kt @@ -4,7 +4,6 @@ package de.gmuth.ipp.core * Copyright (c) 2020-2024 Gerhard Muth */ -import de.gmuth.ipp.attributes.Compression import de.gmuth.ipp.client.IppOperationException import de.gmuth.ipp.core.IppStatus.ClientErrorBadRequest import de.gmuth.ipp.core.IppTag.* diff --git a/src/test/kotlin/de/gmuth/ipp/core/IppMessageTests.kt b/src/test/kotlin/de/gmuth/ipp/core/IppMessageTests.kt index b6542a7c..e76bd6f9 100644 --- a/src/test/kotlin/de/gmuth/ipp/core/IppMessageTests.kt +++ b/src/test/kotlin/de/gmuth/ipp/core/IppMessageTests.kt @@ -52,7 +52,7 @@ class IppMessageTests { documentInputStream = ByteArrayInputStream("01 02 03".toByteArray()) val tmpFile = createTempFile("test", null) try { - write(tmpFile) + write(tmpFile, true) } finally { tmpFile.delete() } diff --git a/src/test/resources/logging.properties b/src/test/resources/logging.properties index 38bced54..204d0b62 100644 --- a/src/test/resources/logging.properties +++ b/src/test/resources/logging.properties @@ -10,6 +10,7 @@ de.gmuth.level=INFO #de.gmuth.ipp.client.IppJob.level=FINE #de.gmuth.ipp.client.IppSubscription.level=ALL #de.gmuth.ipp.client.CupsClient.level=FINE +de.gmuth.ipp.core.IppMessage.level=FINE #sun.net.www.protocol.level=FINE # ------- formatters -------