mirror of
https://github.com/Kunzisoft/KeePassDX.git
synced 2025-12-04 15:49:33 +01:00
Change save binaries compression for database 3.1 & 4
This commit is contained in:
@@ -72,6 +72,14 @@ class BinaryAttachment : Parcelable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Throws(IOException::class)
|
||||||
|
fun getUnGzipInputDataStream(): InputStream {
|
||||||
|
return if (isCompressed)
|
||||||
|
GZIPInputStream(getInputDataStream())
|
||||||
|
else
|
||||||
|
getInputDataStream()
|
||||||
|
}
|
||||||
|
|
||||||
@Throws(IOException::class)
|
@Throws(IOException::class)
|
||||||
fun getOutputDataStream(): OutputStream {
|
fun getOutputDataStream(): OutputStream {
|
||||||
return when {
|
return when {
|
||||||
@@ -110,7 +118,7 @@ class BinaryAttachment : Parcelable {
|
|||||||
if (isCompressed) {
|
if (isCompressed) {
|
||||||
val fileBinaryDecompress = File(concreteDataFile.parent, concreteDataFile.name + "_temp")
|
val fileBinaryDecompress = File(concreteDataFile.parent, concreteDataFile.name + "_temp")
|
||||||
FileOutputStream(fileBinaryDecompress).use { outputStream ->
|
FileOutputStream(fileBinaryDecompress).use { outputStream ->
|
||||||
GZIPInputStream(getInputDataStream()).use { inputStream ->
|
getUnGzipInputDataStream().use { inputStream ->
|
||||||
inputStream.readBytes(bufferSize) { buffer ->
|
inputStream.readBytes(bufferSize) { buffer ->
|
||||||
outputStream.write(buffer)
|
outputStream.write(buffer)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ class BinaryPool {
|
|||||||
binaryAttachment.clear()
|
binaryAttachment.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun findUnusedKey(): Int {
|
private fun findUnusedKey(): Int {
|
||||||
var unusedKey = 0
|
var unusedKey = 0
|
||||||
while (pool[unusedKey] != null)
|
while (pool[unusedKey] != null)
|
||||||
unusedKey++
|
unusedKey++
|
||||||
|
|||||||
@@ -233,8 +233,10 @@ class DatabaseInputKDBX(cacheDirectory: File,
|
|||||||
|
|
||||||
var data = ByteArray(0)
|
var data = ByteArray(0)
|
||||||
if (size > 0) {
|
if (size > 0) {
|
||||||
if (fieldId != DatabaseHeaderKDBX.PwDbInnerHeaderV4Fields.Binary)
|
if (fieldId != DatabaseHeaderKDBX.PwDbInnerHeaderV4Fields.Binary) {
|
||||||
|
// TODO OOM here
|
||||||
data = dataInputStream.readBytes(size)
|
data = dataInputStream.readBytes(size)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var result = true
|
var result = true
|
||||||
@@ -249,12 +251,11 @@ class DatabaseInputKDBX(cacheDirectory: File,
|
|||||||
header.innerRandomStreamKey = data
|
header.innerRandomStreamKey = data
|
||||||
}
|
}
|
||||||
DatabaseHeaderKDBX.PwDbInnerHeaderV4Fields.Binary -> {
|
DatabaseHeaderKDBX.PwDbInnerHeaderV4Fields.Binary -> {
|
||||||
val byteLength = size - 1
|
|
||||||
// Read in a file
|
// Read in a file
|
||||||
val protectedFlag = dataInputStream.readBytes(1)[0].toInt() != 0
|
val protectedFlag = dataInputStream.readBytes(1)[0].toInt() != 0
|
||||||
// Unknown compression at this level
|
val byteLength = size - 1
|
||||||
val compression = mDatabase.compressionAlgorithm == CompressionAlgorithm.GZip
|
// No compression at this level
|
||||||
val protectedBinary = mDatabase.buildNewBinary(cacheDirectory, protectedFlag, compression)
|
val protectedBinary = mDatabase.buildNewBinary(cacheDirectory, protectedFlag, false)
|
||||||
protectedBinary.getOutputDataStream().use { outputStream ->
|
protectedBinary.getOutputDataStream().use { outputStream ->
|
||||||
dataInputStream.readBytes(byteLength, DatabaseKDBX.BUFFER_SIZE_BYTES) { buffer ->
|
dataInputStream.readBytes(byteLength, DatabaseKDBX.BUFFER_SIZE_BYTES) { buffer ->
|
||||||
outputStream.write(buffer)
|
outputStream.write(buffer)
|
||||||
@@ -940,27 +941,28 @@ class DatabaseInputKDBX(cacheDirectory: File,
|
|||||||
|
|
||||||
// Reference Id to a binary already present in binary pool
|
// Reference Id to a binary already present in binary pool
|
||||||
val ref = xpp.getAttributeValue(null, DatabaseKDBXXML.AttrRef)
|
val ref = xpp.getAttributeValue(null, DatabaseKDBXXML.AttrRef)
|
||||||
if (ref != null) {
|
// New id to a binary
|
||||||
xpp.next() // Consume end tag
|
|
||||||
|
|
||||||
val id = Integer.parseInt(ref)
|
|
||||||
return mDatabase.binaryPool[id]
|
|
||||||
}
|
|
||||||
|
|
||||||
val key = xpp.getAttributeValue(null, DatabaseKDBXXML.AttrId)
|
val key = xpp.getAttributeValue(null, DatabaseKDBXXML.AttrId)
|
||||||
return if (key != null) {
|
|
||||||
createBinary(key.toIntOrNull(), xpp)
|
|
||||||
}
|
|
||||||
|
|
||||||
// New binary to retrieve
|
return when {
|
||||||
else {
|
ref != null -> {
|
||||||
createBinary(null, xpp)
|
xpp.next() // Consume end tag
|
||||||
|
val id = Integer.parseInt(ref)
|
||||||
|
mDatabase.binaryPool[id]
|
||||||
|
}
|
||||||
|
key != null -> {
|
||||||
|
createBinary(key.toIntOrNull(), xpp)
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
// New binary to retrieve
|
||||||
|
createBinary(null, xpp)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Throws(IOException::class, XmlPullParserException::class)
|
@Throws(IOException::class, XmlPullParserException::class)
|
||||||
private fun createBinary(binaryId: Int?, xpp: XmlPullParser): BinaryAttachment? {
|
private fun createBinary(binaryId: Int?, xpp: XmlPullParser): BinaryAttachment? {
|
||||||
var compressed: Boolean = mDatabase.compressionAlgorithm == CompressionAlgorithm.GZip
|
var compressed = false
|
||||||
var protected = false
|
var protected = false
|
||||||
|
|
||||||
if (xpp.attributeCount > 0) {
|
if (xpp.attributeCount > 0) {
|
||||||
@@ -980,10 +982,10 @@ class DatabaseInputKDBX(cacheDirectory: File,
|
|||||||
return null
|
return null
|
||||||
val data = Base64.decode(base64, BASE_64_FLAG)
|
val data = Base64.decode(base64, BASE_64_FLAG)
|
||||||
|
|
||||||
// Force compression in this specific case
|
// Build the new binary and compress
|
||||||
val binaryAttachment = mDatabase.buildNewBinary(cacheDirectory, protected, compressed, binaryId)
|
val binaryAttachment = mDatabase.buildNewBinary(cacheDirectory, protected, compressed, binaryId)
|
||||||
binaryAttachment.getOutputDataStream().use { outputStream ->
|
binaryAttachment.getOutputDataStream().use { outputStream ->
|
||||||
outputStream.write(data)
|
outputStream.write(data)
|
||||||
}
|
}
|
||||||
return binaryAttachment
|
return binaryAttachment
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,11 +54,14 @@ class DatabaseInnerHeaderOutputKDBX(private val database: DatabaseKDBX,
|
|||||||
}
|
}
|
||||||
|
|
||||||
dataOutputStream.write(DatabaseHeaderKDBX.PwDbInnerHeaderV4Fields.Binary.toInt())
|
dataOutputStream.write(DatabaseHeaderKDBX.PwDbInnerHeaderV4Fields.Binary.toInt())
|
||||||
dataOutputStream.writeInt(protectedBinary.length().toInt() + 1) // TODO verify
|
dataOutputStream.writeInt(protectedBinary.length().toInt() + 1)
|
||||||
dataOutputStream.write(flag.toInt())
|
dataOutputStream.write(flag.toInt())
|
||||||
|
|
||||||
protectedBinary.getInputDataStream().readBytes(BUFFER_SIZE_BYTES) { buffer ->
|
// if was compressed in cache, uncompress it
|
||||||
dataOutputStream.write(buffer)
|
protectedBinary.getUnGzipInputDataStream().use { inputStream ->
|
||||||
|
inputStream.readBytes(BUFFER_SIZE_BYTES) { buffer ->
|
||||||
|
dataOutputStream.write(buffer)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -55,7 +55,6 @@ 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.*
|
||||||
import java.util.zip.GZIPInputStream
|
|
||||||
import java.util.zip.GZIPOutputStream
|
import java.util.zip.GZIPOutputStream
|
||||||
import javax.crypto.Cipher
|
import javax.crypto.Cipher
|
||||||
import javax.crypto.CipherOutputStream
|
import javax.crypto.CipherOutputStream
|
||||||
@@ -422,7 +421,6 @@ class DatabaseOutputKDBX(private val mDatabaseKDBX: DatabaseKDBX,
|
|||||||
private fun writeBinary(binary : BinaryAttachment) {
|
private fun writeBinary(binary : BinaryAttachment) {
|
||||||
val binaryLength = binary.length()
|
val binaryLength = binary.length()
|
||||||
if (binaryLength > 0) {
|
if (binaryLength > 0) {
|
||||||
|
|
||||||
if (binary.isProtected) {
|
if (binary.isProtected) {
|
||||||
xml.attribute(null, DatabaseKDBXXML.AttrProtected, DatabaseKDBXXML.ValTrue)
|
xml.attribute(null, DatabaseKDBXXML.AttrProtected, DatabaseKDBXXML.ValTrue)
|
||||||
|
|
||||||
@@ -433,21 +431,11 @@ class DatabaseOutputKDBX(private val mDatabaseKDBX: DatabaseKDBX,
|
|||||||
xml.text(charArray, 0, charArray.size)
|
xml.text(charArray, 0, charArray.size)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Force binary compression from database (compression was harmonized during import)
|
if (binary.isCompressed) {
|
||||||
if (mDatabaseKDBX.compressionAlgorithm === CompressionAlgorithm.GZip) {
|
|
||||||
xml.attribute(null, DatabaseKDBXXML.AttrCompressed, DatabaseKDBXXML.ValTrue)
|
xml.attribute(null, DatabaseKDBXXML.AttrCompressed, DatabaseKDBXXML.ValTrue)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Force decompression in this specific case
|
|
||||||
val binaryInputStream = if (mDatabaseKDBX.compressionAlgorithm == CompressionAlgorithm.None
|
|
||||||
&& binary.isCompressed) {
|
|
||||||
GZIPInputStream(binary.getInputDataStream())
|
|
||||||
} else {
|
|
||||||
binary.getInputDataStream()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write the XML
|
// Write the XML
|
||||||
binaryInputStream.readBytes(BUFFER_SIZE_BYTES) { buffer ->
|
binary.getInputDataStream().readBytes(BUFFER_SIZE_BYTES) { buffer ->
|
||||||
val charArray = String(Base64.encode(buffer, BASE_64_FLAG)).toCharArray()
|
val charArray = String(Base64.encode(buffer, BASE_64_FLAG)).toCharArray()
|
||||||
xml.text(charArray, 0, charArray.size)
|
xml.text(charArray, 0, charArray.size)
|
||||||
}
|
}
|
||||||
@@ -560,23 +548,15 @@ class DatabaseOutputKDBX(private val mDatabaseKDBX: DatabaseKDBX,
|
|||||||
|
|
||||||
@Throws(IllegalArgumentException::class, IllegalStateException::class, IOException::class)
|
@Throws(IllegalArgumentException::class, IllegalStateException::class, IOException::class)
|
||||||
private fun writeEntryBinaries(binaries: LinkedHashMap<String, Int>) {
|
private fun writeEntryBinaries(binaries: LinkedHashMap<String, Int>) {
|
||||||
binaries.forEach {
|
for ((label, poolId) in binaries) {
|
||||||
xml.startTag(null, DatabaseKDBXXML.ElemBinary)
|
xml.startTag(null, DatabaseKDBXXML.ElemBinary)
|
||||||
xml.startTag(null, DatabaseKDBXXML.ElemKey)
|
xml.startTag(null, DatabaseKDBXXML.ElemKey)
|
||||||
xml.text(safeXmlString(it.key))
|
xml.text(safeXmlString(label))
|
||||||
xml.endTag(null, DatabaseKDBXXML.ElemKey)
|
xml.endTag(null, DatabaseKDBXXML.ElemKey)
|
||||||
|
|
||||||
xml.startTag(null, DatabaseKDBXXML.ElemValue)
|
xml.startTag(null, DatabaseKDBXXML.ElemValue)
|
||||||
xml.attribute(null, DatabaseKDBXXML.AttrRef, it.value.toString())
|
// Use only pool data in Meta to save binaries
|
||||||
/*
|
xml.attribute(null, DatabaseKDBXXML.AttrRef, poolId.toString())
|
||||||
// By default use only pool data in head to save binaries
|
|
||||||
val ref = mDatabaseKDBX.binaryPool.findKey(it.binaryAttachment)
|
|
||||||
if (ref != null) {
|
|
||||||
xml.attribute(null, DatabaseKDBXXML.AttrRef, ref.toString())
|
|
||||||
} else {
|
|
||||||
writeBinary(it.binaryAttachment)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
xml.endTag(null, DatabaseKDBXXML.ElemValue)
|
xml.endTag(null, DatabaseKDBXXML.ElemValue)
|
||||||
|
|
||||||
xml.endTag(null, DatabaseKDBXXML.ElemBinary)
|
xml.endTag(null, DatabaseKDBXXML.ElemBinary)
|
||||||
|
|||||||
@@ -362,11 +362,7 @@ class AttachmentFileNotificationService: LockNotificationService() {
|
|||||||
var dataDownloaded = 0L
|
var dataDownloaded = 0L
|
||||||
val fileSize = binaryAttachment.length()
|
val fileSize = binaryAttachment.length()
|
||||||
UriUtil.getUriOutputStream(contentResolver, attachmentToUploadUri)?.use { outputStream ->
|
UriUtil.getUriOutputStream(contentResolver, attachmentToUploadUri)?.use { outputStream ->
|
||||||
if (binaryAttachment.isCompressed) {
|
binaryAttachment.getUnGzipInputDataStream().use { inputStream ->
|
||||||
GZIPInputStream(binaryAttachment.getInputDataStream())
|
|
||||||
} else {
|
|
||||||
binaryAttachment.getInputDataStream()
|
|
||||||
}.use { inputStream ->
|
|
||||||
inputStream.readBytes(bufferSize) { buffer ->
|
inputStream.readBytes(bufferSize) { buffer ->
|
||||||
outputStream.write(buffer)
|
outputStream.write(buffer)
|
||||||
dataDownloaded += buffer.size
|
dataDownloaded += buffer.size
|
||||||
|
|||||||
Reference in New Issue
Block a user