Refactor binary class

This commit is contained in:
J-Jamet
2019-11-26 11:07:29 +01:00
parent 1e71dd3031
commit 32343dc937
8 changed files with 87 additions and 206 deletions

View File

@@ -22,7 +22,7 @@ package com.kunzisoft.keepass.database.element
import android.os.Parcel import android.os.Parcel
import android.os.Parcelable import android.os.Parcelable
import com.kunzisoft.keepass.utils.MemoryUtil import com.kunzisoft.keepass.utils.ParcelableUtil
import java.util.HashMap import java.util.HashMap
@@ -48,7 +48,7 @@ class AutoType : Parcelable {
this.enabled = parcel.readByte().toInt() != 0 this.enabled = parcel.readByte().toInt() != 0
this.obfuscationOptions = parcel.readLong() this.obfuscationOptions = parcel.readLong()
this.defaultSequence = parcel.readString() ?: defaultSequence this.defaultSequence = parcel.readString() ?: defaultSequence
this.windowSeqPairs = MemoryUtil.readStringParcelableMap(parcel) this.windowSeqPairs = ParcelableUtil.readStringParcelableMap(parcel)
} }
override fun describeContents(): Int { override fun describeContents(): Int {
@@ -59,7 +59,7 @@ class AutoType : Parcelable {
dest.writeByte((if (enabled) 1 else 0).toByte()) dest.writeByte((if (enabled) 1 else 0).toByte())
dest.writeLong(obfuscationOptions) dest.writeLong(obfuscationOptions)
dest.writeString(defaultSequence) dest.writeString(defaultSequence)
MemoryUtil.writeStringParcelableMap(dest, windowSeqPairs) ParcelableUtil.writeStringParcelableMap(dest, windowSeqPairs)
} }
fun put(key: String, value: String) { fun put(key: String, value: String) {

View File

@@ -508,5 +508,7 @@ class PwDatabaseV4 : PwDatabase<UUID, UUID, PwGroupV4, PwEntryV4> {
private const val KeyDataElementName = "Data" private const val KeyDataElementName = "Data"
const val BASE_64_FLAG = Base64.DEFAULT const val BASE_64_FLAG = Base64.DEFAULT
const val BUFFER_SIZE_BYTES = 3 * 128
} }
} }

View File

@@ -23,7 +23,7 @@ import android.os.Parcel
import android.os.Parcelable import android.os.Parcelable
import com.kunzisoft.keepass.database.element.security.ProtectedBinary import com.kunzisoft.keepass.database.element.security.ProtectedBinary
import com.kunzisoft.keepass.database.element.security.ProtectedString import com.kunzisoft.keepass.database.element.security.ProtectedString
import com.kunzisoft.keepass.utils.MemoryUtil import com.kunzisoft.keepass.utils.ParcelableUtil
import java.util.* import java.util.*
class PwEntryV4 : PwEntry<UUID, UUID, PwGroupV4, PwEntryV4>, PwNodeV4Interface { class PwEntryV4 : PwEntry<UUID, UUID, PwGroupV4, PwEntryV4>, PwNodeV4Interface {
@@ -96,9 +96,9 @@ class PwEntryV4 : PwEntry<UUID, UUID, PwGroupV4, PwEntryV4>, PwNodeV4Interface {
iconCustom = parcel.readParcelable(PwIconCustom::class.java.classLoader) ?: iconCustom iconCustom = parcel.readParcelable(PwIconCustom::class.java.classLoader) ?: iconCustom
usageCount = parcel.readLong() usageCount = parcel.readLong()
locationChanged = parcel.readParcelable(PwDate::class.java.classLoader) ?: locationChanged locationChanged = parcel.readParcelable(PwDate::class.java.classLoader) ?: locationChanged
customData = MemoryUtil.readStringParcelableMap(parcel) customData = ParcelableUtil.readStringParcelableMap(parcel)
fields = MemoryUtil.readStringParcelableMap(parcel, ProtectedString::class.java) fields = ParcelableUtil.readStringParcelableMap(parcel, ProtectedString::class.java)
// TODO binaries = MemoryUtil.readStringParcelableMap(parcel, ProtectedBinary.class); // TODO binaries = ParcelableUtil.readStringParcelableMap(parcel, ProtectedBinary.class);
foregroundColor = parcel.readString() ?: foregroundColor foregroundColor = parcel.readString() ?: foregroundColor
backgroundColor = parcel.readString() ?: backgroundColor backgroundColor = parcel.readString() ?: backgroundColor
overrideURL = parcel.readString() ?: overrideURL overrideURL = parcel.readString() ?: overrideURL
@@ -114,9 +114,9 @@ class PwEntryV4 : PwEntry<UUID, UUID, PwGroupV4, PwEntryV4>, PwNodeV4Interface {
dest.writeParcelable(iconCustom, flags) dest.writeParcelable(iconCustom, flags)
dest.writeLong(usageCount) dest.writeLong(usageCount)
dest.writeParcelable(locationChanged, flags) dest.writeParcelable(locationChanged, flags)
MemoryUtil.writeStringParcelableMap(dest, customData) ParcelableUtil.writeStringParcelableMap(dest, customData)
MemoryUtil.writeStringParcelableMap(dest, flags, fields) ParcelableUtil.writeStringParcelableMap(dest, flags, fields)
// TODO MemoryUtil.writeStringParcelableMap(dest, flags, binaries); // TODO ParcelableUtil.writeStringParcelableMap(dest, flags, binaries);
dest.writeString(foregroundColor) dest.writeString(foregroundColor)
dest.writeString(backgroundColor) dest.writeString(backgroundColor)
dest.writeString(overrideURL) dest.writeString(overrideURL)

View File

@@ -69,7 +69,7 @@ class PwGroupV4 : PwGroup<UUID, UUID, PwGroupV4, PwEntryV4>, PwNodeV4Interface {
iconCustom = parcel.readParcelable(PwIconCustom::class.java.classLoader) ?: iconCustom iconCustom = parcel.readParcelable(PwIconCustom::class.java.classLoader) ?: iconCustom
usageCount = parcel.readLong() usageCount = parcel.readLong()
locationChanged = parcel.readParcelable(PwDate::class.java.classLoader) ?: locationChanged locationChanged = parcel.readParcelable(PwDate::class.java.classLoader) ?: locationChanged
// TODO customData = MemoryUtil.readStringParcelableMap(in); // TODO customData = ParcelableUtil.readStringParcelableMap(in);
notes = parcel.readString() ?: notes notes = parcel.readString() ?: notes
isExpanded = parcel.readByte().toInt() != 0 isExpanded = parcel.readByte().toInt() != 0
defaultAutoTypeSequence = parcel.readString() ?: defaultAutoTypeSequence defaultAutoTypeSequence = parcel.readString() ?: defaultAutoTypeSequence
@@ -93,7 +93,7 @@ class PwGroupV4 : PwGroup<UUID, UUID, PwGroupV4, PwEntryV4>, PwNodeV4Interface {
dest.writeParcelable(iconCustom, flags) dest.writeParcelable(iconCustom, flags)
dest.writeLong(usageCount) dest.writeLong(usageCount)
dest.writeParcelable(locationChanged, flags) dest.writeParcelable(locationChanged, flags)
// TODO MemoryUtil.writeStringParcelableMap(dest, customData); // TODO ParcelableUtil.writeStringParcelableMap(dest, customData);
dest.writeString(notes) dest.writeString(notes)
dest.writeByte((if (isExpanded) 1 else 0).toByte()) dest.writeByte((if (isExpanded) 1 else 0).toByte())
dest.writeString(defaultAutoTypeSequence) dest.writeString(defaultAutoTypeSequence)

View File

@@ -26,6 +26,7 @@ import com.kunzisoft.keepass.crypto.StreamCipherFactory
import com.kunzisoft.keepass.crypto.engine.CipherEngine import com.kunzisoft.keepass.crypto.engine.CipherEngine
import com.kunzisoft.keepass.database.element.* import com.kunzisoft.keepass.database.element.*
import com.kunzisoft.keepass.database.element.PwDatabaseV4.Companion.BASE_64_FLAG import com.kunzisoft.keepass.database.element.PwDatabaseV4.Companion.BASE_64_FLAG
import com.kunzisoft.keepass.database.element.PwDatabaseV4.Companion.BUFFER_SIZE_BYTES
import com.kunzisoft.keepass.database.element.security.ProtectedBinary import com.kunzisoft.keepass.database.element.security.ProtectedBinary
import com.kunzisoft.keepass.database.element.security.ProtectedString import com.kunzisoft.keepass.database.element.security.ProtectedString
import com.kunzisoft.keepass.database.exception.* import com.kunzisoft.keepass.database.exception.*
@@ -37,7 +38,6 @@ import com.kunzisoft.keepass.stream.HmacBlockInputStream
import com.kunzisoft.keepass.stream.LEDataInputStream import com.kunzisoft.keepass.stream.LEDataInputStream
import com.kunzisoft.keepass.tasks.ProgressTaskUpdater import com.kunzisoft.keepass.tasks.ProgressTaskUpdater
import com.kunzisoft.keepass.utils.DatabaseInputOutputUtils import com.kunzisoft.keepass.utils.DatabaseInputOutputUtils
import com.kunzisoft.keepass.utils.MemoryUtil
import org.apache.commons.io.IOUtils import org.apache.commons.io.IOUtils
import org.spongycastle.crypto.StreamCipher import org.spongycastle.crypto.StreamCipher
import org.xmlpull.v1.XmlPullParser import org.xmlpull.v1.XmlPullParser
@@ -968,7 +968,7 @@ class ImporterV4(private val streamDir: File,
return ProtectedBinary() return ProtectedBinary()
val data = Base64.decode(base64, BASE_64_FLAG) val data = Base64.decode(base64, BASE_64_FLAG)
return if (!compressed && data.size <= MemoryUtil.BUFFER_SIZE_BYTES) { return if (!compressed && data.size <= BUFFER_SIZE_BYTES) {
// Small data, don't need a file // Small data, don't need a file
ProtectedBinary(protected, data) ProtectedBinary(protected, data)
} else { } else {

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2017 Brian Pellin. * Copyright 2019 Jeremy Jamet / Kunzisoft.
* *
* This file is part of KeePass DX. * This file is part of KeePass DX.
* *
@@ -20,50 +20,70 @@
package com.kunzisoft.keepass.database.file.save package com.kunzisoft.keepass.database.file.save
import com.kunzisoft.keepass.database.element.PwDatabaseV4 import com.kunzisoft.keepass.database.element.PwDatabaseV4
import com.kunzisoft.keepass.database.element.PwDatabaseV4.Companion.BUFFER_SIZE_BYTES
import com.kunzisoft.keepass.database.file.PwDbHeaderV4 import com.kunzisoft.keepass.database.file.PwDbHeaderV4
import com.kunzisoft.keepass.stream.ActionReadBytes import com.kunzisoft.keepass.stream.ActionReadBytes
import com.kunzisoft.keepass.stream.LEDataOutputStream import com.kunzisoft.keepass.stream.LEDataOutputStream
import com.kunzisoft.keepass.utils.MemoryUtil
import java.io.IOException import java.io.IOException
import java.io.InputStream
import java.io.OutputStream import java.io.OutputStream
import kotlin.experimental.or import kotlin.experimental.or
class PwDbInnerHeaderOutputV4(private val db: PwDatabaseV4, private val header: PwDbHeaderV4, os: OutputStream) { class PwDbInnerHeaderOutputV4(private val database: PwDatabaseV4,
private val header: PwDbHeaderV4,
outputStream: OutputStream) {
private val los: LEDataOutputStream = LEDataOutputStream(os) private val dataOutputStream: LEDataOutputStream = LEDataOutputStream(outputStream)
@Throws(IOException::class) @Throws(IOException::class)
fun output() { fun output() {
los.write(PwDbHeaderV4.PwDbInnerHeaderV4Fields.InnerRandomStreamID.toInt()) dataOutputStream.write(PwDbHeaderV4.PwDbInnerHeaderV4Fields.InnerRandomStreamID.toInt())
los.writeInt(4) dataOutputStream.writeInt(4)
if (header.innerRandomStream == null) if (header.innerRandomStream == null)
throw IOException("Can't write innerRandomStream") throw IOException("Can't write innerRandomStream")
los.writeInt(header.innerRandomStream!!.id) dataOutputStream.writeInt(header.innerRandomStream!!.id)
val streamKeySize = header.innerRandomStreamKey.size val streamKeySize = header.innerRandomStreamKey.size
los.write(PwDbHeaderV4.PwDbInnerHeaderV4Fields.InnerRandomstreamKey.toInt()) dataOutputStream.write(PwDbHeaderV4.PwDbInnerHeaderV4Fields.InnerRandomstreamKey.toInt())
los.writeInt(streamKeySize) dataOutputStream.writeInt(streamKeySize)
los.write(header.innerRandomStreamKey) dataOutputStream.write(header.innerRandomStreamKey)
db.binPool.doForEachBinary { _, protectedBinary -> database.binPool.doForEachBinary { _, protectedBinary ->
var flag = PwDbHeaderV4.KdbxBinaryFlags.None var flag = PwDbHeaderV4.KdbxBinaryFlags.None
if (protectedBinary.isProtected) { if (protectedBinary.isProtected) {
flag = flag or PwDbHeaderV4.KdbxBinaryFlags.Protected flag = flag or PwDbHeaderV4.KdbxBinaryFlags.Protected
} }
los.write(PwDbHeaderV4.PwDbInnerHeaderV4Fields.Binary.toInt()) dataOutputStream.write(PwDbHeaderV4.PwDbInnerHeaderV4Fields.Binary.toInt())
los.writeInt(protectedBinary.length().toInt() + 1) // TODO verify dataOutputStream.writeInt(protectedBinary.length().toInt() + 1) // TODO verify
los.write(flag.toInt()) dataOutputStream.write(flag.toInt())
protectedBinary.getData()?.let { protectedBinary.getData()?.let {
MemoryUtil.readBytes(it, ActionReadBytes { buffer -> readBytes(it, ActionReadBytes { buffer ->
los.write(buffer) dataOutputStream.write(buffer)
}) })
} ?: throw IOException("Can't write protected binary") } ?: throw IOException("Can't write protected binary")
} }
los.write(PwDbHeaderV4.PwDbInnerHeaderV4Fields.EndOfHeader.toInt()) dataOutputStream.write(PwDbHeaderV4.PwDbInnerHeaderV4Fields.EndOfHeader.toInt())
los.writeInt(0) dataOutputStream.writeInt(0)
}
@Throws(IOException::class)
fun readBytes(inputStream: InputStream, actionReadBytes: ActionReadBytes) {
val buffer = ByteArray(BUFFER_SIZE_BYTES)
var read = 0
while (read != -1) {
read = inputStream.read(buffer, 0, buffer.size)
if (read != -1) {
val optimizedBuffer: ByteArray = if (buffer.size == read) {
buffer
} else {
buffer.copyOf(read)
}
actionReadBytes.doAction(optimizedBuffer)
}
}
} }
} }

View File

@@ -30,6 +30,7 @@ import com.kunzisoft.keepass.crypto.keyDerivation.KdfFactory
import com.kunzisoft.keepass.database.NodeHandler import com.kunzisoft.keepass.database.NodeHandler
import com.kunzisoft.keepass.database.element.* import com.kunzisoft.keepass.database.element.*
import com.kunzisoft.keepass.database.element.PwDatabaseV4.Companion.BASE_64_FLAG import com.kunzisoft.keepass.database.element.PwDatabaseV4.Companion.BASE_64_FLAG
import com.kunzisoft.keepass.database.element.PwDatabaseV4.Companion.BUFFER_SIZE_BYTES
import com.kunzisoft.keepass.database.element.security.ProtectedBinary import com.kunzisoft.keepass.database.element.security.ProtectedBinary
import com.kunzisoft.keepass.database.element.security.ProtectedString import com.kunzisoft.keepass.database.element.security.ProtectedString
import com.kunzisoft.keepass.database.exception.DatabaseOutputException import com.kunzisoft.keepass.database.exception.DatabaseOutputException
@@ -40,13 +41,10 @@ import com.kunzisoft.keepass.stream.HashedBlockOutputStream
import com.kunzisoft.keepass.stream.HmacBlockOutputStream import com.kunzisoft.keepass.stream.HmacBlockOutputStream
import com.kunzisoft.keepass.stream.LEDataOutputStream import com.kunzisoft.keepass.stream.LEDataOutputStream
import com.kunzisoft.keepass.utils.DatabaseInputOutputUtils import com.kunzisoft.keepass.utils.DatabaseInputOutputUtils
import com.kunzisoft.keepass.utils.MemoryUtil
import org.joda.time.DateTime import org.joda.time.DateTime
import org.spongycastle.crypto.StreamCipher import org.spongycastle.crypto.StreamCipher
import org.xmlpull.v1.XmlSerializer import org.xmlpull.v1.XmlSerializer
import java.io.IOException import java.io.*
import java.io.InputStream
import java.io.OutputStream
import java.security.NoSuchAlgorithmException import java.security.NoSuchAlgorithmException
import java.security.SecureRandom import java.security.SecureRandom
import java.util.* import java.util.*
@@ -362,7 +360,7 @@ class PwDbV4Output(private val mDatabaseV4: PwDatabaseV4, outputStream: OutputSt
@Throws(IllegalArgumentException::class, IllegalStateException::class, IOException::class) @Throws(IllegalArgumentException::class, IllegalStateException::class, IOException::class)
private fun writeObject(key: String, value: ProtectedBinary) { private fun writeObject(key: String, binary: ProtectedBinary) {
xml.startTag(null, PwDatabaseV4XML.ElemBinary) xml.startTag(null, PwDatabaseV4XML.ElemBinary)
xml.startTag(null, PwDatabaseV4XML.ElemKey) xml.startTag(null, PwDatabaseV4XML.ElemKey)
@@ -370,67 +368,19 @@ class PwDbV4Output(private val mDatabaseV4: PwDatabaseV4, outputStream: OutputSt
xml.endTag(null, PwDatabaseV4XML.ElemKey) xml.endTag(null, PwDatabaseV4XML.ElemKey)
xml.startTag(null, PwDatabaseV4XML.ElemValue) xml.startTag(null, PwDatabaseV4XML.ElemValue)
val ref = mDatabaseV4.binPool.findKey(value) val ref = mDatabaseV4.binPool.findKey(binary)
if (ref != null) { if (ref != null) {
xml.attribute(null, PwDatabaseV4XML.AttrRef, ref.toString()) xml.attribute(null, PwDatabaseV4XML.AttrRef, ref.toString())
} else { } else {
subWriteValue(value) writeBinary(binary)
} }
xml.endTag(null, PwDatabaseV4XML.ElemValue) xml.endTag(null, PwDatabaseV4XML.ElemValue)
xml.endTag(null, PwDatabaseV4XML.ElemBinary) xml.endTag(null, PwDatabaseV4XML.ElemBinary)
} }
/*
@Throws(IllegalArgumentException::class, IllegalStateException::class, IOException::class) @Throws(IllegalArgumentException::class, IllegalStateException::class, IOException::class)
private fun subWriteValue(value: ProtectedBinary) { private fun writeBinary(value: ProtectedBinary) {
try {
val inputStream = value.getData()
if (inputStream == null) {
Log.e(TAG, "Can't write a null input stream.")
return
}
if (value.isProtected) {
xml.attribute(null, PwDatabaseV4XML.AttrProtected, PwDatabaseV4XML.ValTrue)
try {
val cypherInputStream =
IOUtil.pipe(inputStream,
o -> new org.spongycastle.crypto.io.CipherOutputStream(o, randomStream))
writeInputStreamInBase64(cypherInputStream)
} catch (e: Exception) {}
} else {
if (mDatabaseV4.compressionAlgorithm == PwCompressionAlgorithm.GZip) {
xml.attribute(null, PwDatabaseV4XML.AttrCompressed, PwDatabaseV4XML.ValTrue)
try {
val gZipInputStream =
IOUtil.pipe(inputStream, GZIPOutputStream::new, (int) value.length())
writeInputStreamInBase64(gZipInputStream)
} catch (e: Exception) {}
} else {
writeInputStreamInBase64(inputStream);
}
}
} catch (e: Exception) {}
}
@Throws(IOException::class)
private fun writeInputStreamInBase64(inputStream: InputStream) {
try {
val base64InputStream = pipe(inputStream, Base64OutputStream(o, Base64OutputStream.DEFAULT))
MemoryUtil.readBytes(base64InputStream,
ActionReadBytes { buffer -> xml.text(Arrays.toString(buffer)) })
} catch (e: Exception) {}
}
*/
@Throws(IllegalArgumentException::class, IllegalStateException::class, IOException::class)
private fun subWriteValue(value: ProtectedBinary) {
val valLength = value.length().toInt() val valLength = value.length().toInt()
if (valLength > 0) { if (valLength > 0) {
@@ -448,8 +398,13 @@ class PwDbV4Output(private val mDatabaseV4: PwDatabaseV4, outputStream: OutputSt
if (mDatabaseV4.compressionAlgorithm === PwCompressionAlgorithm.GZip) { if (mDatabaseV4.compressionAlgorithm === PwCompressionAlgorithm.GZip) {
xml.attribute(null, PwDatabaseV4XML.AttrCompressed, PwDatabaseV4XML.ValTrue) xml.attribute(null, PwDatabaseV4XML.AttrCompressed, PwDatabaseV4XML.ValTrue)
val compressData = MemoryUtil.compress(buffer) val byteArrayOutputStream = ByteArrayOutputStream()
xml.text(String(Base64.encode(compressData, BASE_64_FLAG))) val gzipOutputStream = GZIPOutputStream(byteArrayOutputStream)
copyStream(ByteArrayInputStream(buffer), gzipOutputStream)
// IOUtils.copy(ByteArrayInputStream(ByteArrayInputStream(buffer)), gzipOutputStream)
gzipOutputStream.close()
xml.text(String(Base64.encode(byteArrayOutputStream.toByteArray(), BASE_64_FLAG)))
} else { } else {
xml.text(String(Base64.encode(buffer, BASE_64_FLAG))) xml.text(String(Base64.encode(buffer, BASE_64_FLAG)))
@@ -461,6 +416,23 @@ class PwDbV4Output(private val mDatabaseV4: PwDatabaseV4, outputStream: OutputSt
} }
} }
@Throws(IOException::class)
fun copyStream(inputStream: InputStream, out: OutputStream) {
val buffer = ByteArray(BUFFER_SIZE_BYTES)
try {
var read = inputStream.read(buffer)
while (read != -1) {
out.write(buffer, 0, read)
read = inputStream.read(buffer)
if (Thread.interrupted()) {
throw InterruptedException()
}
}
} catch (error: OutOfMemoryError) {
throw IOException(error)
}
}
@Throws(IllegalArgumentException::class, IllegalStateException::class, IOException::class) @Throws(IllegalArgumentException::class, IllegalStateException::class, IOException::class)
private fun writeObject(name: String, value: String, filterXmlChars: Boolean = false) { private fun writeObject(name: String, value: String, filterXmlChars: Boolean = false) {
var xmlString = value var xmlString = value
@@ -703,7 +675,7 @@ class PwDbV4Output(private val mDatabaseV4: PwDatabaseV4, outputStream: OutputSt
xml.startTag(null, PwDatabaseV4XML.ElemBinary) xml.startTag(null, PwDatabaseV4XML.ElemBinary)
xml.attribute(null, PwDatabaseV4XML.AttrId, key.toString()) xml.attribute(null, PwDatabaseV4XML.AttrId, key.toString())
subWriteValue(binary) writeBinary(binary)
xml.endTag(null, PwDatabaseV4XML.ElemBinary) xml.endTag(null, PwDatabaseV4XML.ElemBinary)
} }
@@ -733,16 +705,5 @@ class PwDbV4Output(private val mDatabaseV4: PwDatabaseV4, outputStream: OutputSt
companion object { companion object {
private val TAG = PwDbV4Output::class.java.name private val TAG = PwDbV4Output::class.java.name
@Throws(IOException::class)
fun pipe(inputStream: InputStream, outputStream: OutputStream, buf: ByteArray) {
while (true) {
val amt = inputStream.read(buf)
if (amt < 0) {
break
}
outputStream.write(buf, 0, amt)
}
}
} }
} }

View File

@@ -21,111 +21,9 @@ package com.kunzisoft.keepass.utils
import android.os.Parcel import android.os.Parcel
import android.os.Parcelable import android.os.Parcelable
import android.util.Log import java.util.*
import com.kunzisoft.keepass.stream.ActionReadBytes object ParcelableUtil {
import org.apache.commons.io.IOUtils
import java.io.*
import java.util.HashMap
import java.util.zip.GZIPInputStream
import java.util.zip.GZIPOutputStream
object MemoryUtil {
private val TAG = MemoryUtil::class.java.name
const val BUFFER_SIZE_BYTES = 3 * 128
@Throws(IOException::class)
fun copyStream(inputStream: InputStream, out: OutputStream) {
val buffer = ByteArray(BUFFER_SIZE_BYTES)
try {
var read = inputStream.read(buffer)
while (read != -1) {
out.write(buffer, 0, read)
read = inputStream.read(buffer)
if (Thread.interrupted()) {
throw InterruptedException()
}
}
} catch (error: OutOfMemoryError) {
throw IOException(error)
}
}
@Throws(IOException::class)
fun readBytes(inputStream: InputStream, actionReadBytes: ActionReadBytes) {
val buffer = ByteArray(BUFFER_SIZE_BYTES)
var read = 0
while (read != -1) {
read = inputStream.read(buffer, 0, buffer.size)
if (read != -1) {
val optimizedBuffer: ByteArray = if (buffer.size == read) {
buffer
} else {
buffer.copyOf(read)
}
actionReadBytes.doAction(optimizedBuffer)
}
}
}
@Throws(IOException::class)
fun decompress(input: ByteArray): ByteArray {
val bais = ByteArrayInputStream(input)
val gzis = GZIPInputStream(bais)
val baos = ByteArrayOutputStream()
copyStream(gzis, baos)
return baos.toByteArray()
}
@Throws(IOException::class)
fun compress(input: ByteArray): ByteArray {
val bais = ByteArrayInputStream(input)
val baos = ByteArrayOutputStream()
val gzos = GZIPOutputStream(baos)
copyStream(bais, gzos)
gzos.close()
return baos.toByteArray()
}
/**
* Compresses the input data using GZip and outputs the compressed data.
*
* @param input
* An [InputStream] containing the input raw data.
*
* @return An [InputStream] to the compressed data.
*/
fun compress(input: InputStream): InputStream {
val compressedDataStream = PipedInputStream(3 * 128)
Log.d(TAG, "About to compress input data using gzip asynchronously...")
val compressionOutput: PipedOutputStream
var gzipCompressedDataStream: GZIPOutputStream? = null
try {
compressionOutput = PipedOutputStream(compressedDataStream)
gzipCompressedDataStream = GZIPOutputStream(compressionOutput)
IOUtils.copy(input, gzipCompressedDataStream)
Log.e(TAG, "Successfully compressed input data using gzip.")
} catch (e: IOException) {
Log.e(TAG, "Failed to compress input data.", e)
} finally {
if (gzipCompressedDataStream != null) {
try {
gzipCompressedDataStream.close()
} catch (e: IOException) {
Log.e(TAG, "Failed to close gzip output stream.", e)
}
}
}
return compressedDataStream
}
// For writing to a Parcel // For writing to a Parcel
fun <K : Parcelable, V : Parcelable> writeParcelableMap( fun <K : Parcelable, V : Parcelable> writeParcelableMap(