mirror of
https://github.com/Kunzisoft/KeePassDX.git
synced 2025-12-04 15:49:33 +01:00
Refactor binary class
This commit is contained in:
@@ -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) {
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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(
|
||||||
Reference in New Issue
Block a user