Change save binaries compression for database 3.1 & 4

This commit is contained in:
J-Jamet
2020-08-27 13:49:48 +02:00
parent 2191a4a848
commit dd8d114711
6 changed files with 46 additions and 57 deletions

View File

@@ -72,6 +72,14 @@ class BinaryAttachment : Parcelable {
}
}
@Throws(IOException::class)
fun getUnGzipInputDataStream(): InputStream {
return if (isCompressed)
GZIPInputStream(getInputDataStream())
else
getInputDataStream()
}
@Throws(IOException::class)
fun getOutputDataStream(): OutputStream {
return when {
@@ -110,7 +118,7 @@ class BinaryAttachment : Parcelable {
if (isCompressed) {
val fileBinaryDecompress = File(concreteDataFile.parent, concreteDataFile.name + "_temp")
FileOutputStream(fileBinaryDecompress).use { outputStream ->
GZIPInputStream(getInputDataStream()).use { inputStream ->
getUnGzipInputDataStream().use { inputStream ->
inputStream.readBytes(bufferSize) { buffer ->
outputStream.write(buffer)
}

View File

@@ -57,7 +57,7 @@ class BinaryPool {
binaryAttachment.clear()
}
fun findUnusedKey(): Int {
private fun findUnusedKey(): Int {
var unusedKey = 0
while (pool[unusedKey] != null)
unusedKey++

View File

@@ -233,9 +233,11 @@ class DatabaseInputKDBX(cacheDirectory: File,
var data = ByteArray(0)
if (size > 0) {
if (fieldId != DatabaseHeaderKDBX.PwDbInnerHeaderV4Fields.Binary)
if (fieldId != DatabaseHeaderKDBX.PwDbInnerHeaderV4Fields.Binary) {
// TODO OOM here
data = dataInputStream.readBytes(size)
}
}
var result = true
when (fieldId) {
@@ -249,12 +251,11 @@ class DatabaseInputKDBX(cacheDirectory: File,
header.innerRandomStreamKey = data
}
DatabaseHeaderKDBX.PwDbInnerHeaderV4Fields.Binary -> {
val byteLength = size - 1
// Read in a file
val protectedFlag = dataInputStream.readBytes(1)[0].toInt() != 0
// Unknown compression at this level
val compression = mDatabase.compressionAlgorithm == CompressionAlgorithm.GZip
val protectedBinary = mDatabase.buildNewBinary(cacheDirectory, protectedFlag, compression)
val byteLength = size - 1
// No compression at this level
val protectedBinary = mDatabase.buildNewBinary(cacheDirectory, protectedFlag, false)
protectedBinary.getOutputDataStream().use { outputStream ->
dataInputStream.readBytes(byteLength, DatabaseKDBX.BUFFER_SIZE_BYTES) { buffer ->
outputStream.write(buffer)
@@ -940,27 +941,28 @@ class DatabaseInputKDBX(cacheDirectory: File,
// Reference Id to a binary already present in binary pool
val ref = xpp.getAttributeValue(null, DatabaseKDBXXML.AttrRef)
if (ref != null) {
xpp.next() // Consume end tag
val id = Integer.parseInt(ref)
return mDatabase.binaryPool[id]
}
// New id to a binary
val key = xpp.getAttributeValue(null, DatabaseKDBXXML.AttrId)
return if (key != null) {
return when {
ref != null -> {
xpp.next() // Consume end tag
val id = Integer.parseInt(ref)
mDatabase.binaryPool[id]
}
key != null -> {
createBinary(key.toIntOrNull(), xpp)
}
else -> {
// New binary to retrieve
else {
createBinary(null, xpp)
}
}
}
@Throws(IOException::class, XmlPullParserException::class)
private fun createBinary(binaryId: Int?, xpp: XmlPullParser): BinaryAttachment? {
var compressed: Boolean = mDatabase.compressionAlgorithm == CompressionAlgorithm.GZip
var compressed = false
var protected = false
if (xpp.attributeCount > 0) {
@@ -980,7 +982,7 @@ class DatabaseInputKDBX(cacheDirectory: File,
return null
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)
binaryAttachment.getOutputDataStream().use { outputStream ->
outputStream.write(data)

View File

@@ -54,13 +54,16 @@ class DatabaseInnerHeaderOutputKDBX(private val database: DatabaseKDBX,
}
dataOutputStream.write(DatabaseHeaderKDBX.PwDbInnerHeaderV4Fields.Binary.toInt())
dataOutputStream.writeInt(protectedBinary.length().toInt() + 1) // TODO verify
dataOutputStream.writeInt(protectedBinary.length().toInt() + 1)
dataOutputStream.write(flag.toInt())
protectedBinary.getInputDataStream().readBytes(BUFFER_SIZE_BYTES) { buffer ->
// if was compressed in cache, uncompress it
protectedBinary.getUnGzipInputDataStream().use { inputStream ->
inputStream.readBytes(BUFFER_SIZE_BYTES) { buffer ->
dataOutputStream.write(buffer)
}
}
}
dataOutputStream.write(DatabaseHeaderKDBX.PwDbInnerHeaderV4Fields.EndOfHeader.toInt())
dataOutputStream.writeInt(0)

View File

@@ -55,7 +55,6 @@ import java.io.OutputStream
import java.security.NoSuchAlgorithmException
import java.security.SecureRandom
import java.util.*
import java.util.zip.GZIPInputStream
import java.util.zip.GZIPOutputStream
import javax.crypto.Cipher
import javax.crypto.CipherOutputStream
@@ -422,7 +421,6 @@ class DatabaseOutputKDBX(private val mDatabaseKDBX: DatabaseKDBX,
private fun writeBinary(binary : BinaryAttachment) {
val binaryLength = binary.length()
if (binaryLength > 0) {
if (binary.isProtected) {
xml.attribute(null, DatabaseKDBXXML.AttrProtected, DatabaseKDBXXML.ValTrue)
@@ -433,21 +431,11 @@ class DatabaseOutputKDBX(private val mDatabaseKDBX: DatabaseKDBX,
xml.text(charArray, 0, charArray.size)
}
} else {
// Force binary compression from database (compression was harmonized during import)
if (mDatabaseKDBX.compressionAlgorithm === CompressionAlgorithm.GZip) {
if (binary.isCompressed) {
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
binaryInputStream.readBytes(BUFFER_SIZE_BYTES) { buffer ->
binary.getInputDataStream().readBytes(BUFFER_SIZE_BYTES) { buffer ->
val charArray = String(Base64.encode(buffer, BASE_64_FLAG)).toCharArray()
xml.text(charArray, 0, charArray.size)
}
@@ -560,23 +548,15 @@ class DatabaseOutputKDBX(private val mDatabaseKDBX: DatabaseKDBX,
@Throws(IllegalArgumentException::class, IllegalStateException::class, IOException::class)
private fun writeEntryBinaries(binaries: LinkedHashMap<String, Int>) {
binaries.forEach {
for ((label, poolId) in binaries) {
xml.startTag(null, DatabaseKDBXXML.ElemBinary)
xml.startTag(null, DatabaseKDBXXML.ElemKey)
xml.text(safeXmlString(it.key))
xml.text(safeXmlString(label))
xml.endTag(null, DatabaseKDBXXML.ElemKey)
xml.startTag(null, DatabaseKDBXXML.ElemValue)
xml.attribute(null, DatabaseKDBXXML.AttrRef, it.value.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)
}
*/
// Use only pool data in Meta to save binaries
xml.attribute(null, DatabaseKDBXXML.AttrRef, poolId.toString())
xml.endTag(null, DatabaseKDBXXML.ElemValue)
xml.endTag(null, DatabaseKDBXXML.ElemBinary)

View File

@@ -362,11 +362,7 @@ class AttachmentFileNotificationService: LockNotificationService() {
var dataDownloaded = 0L
val fileSize = binaryAttachment.length()
UriUtil.getUriOutputStream(contentResolver, attachmentToUploadUri)?.use { outputStream ->
if (binaryAttachment.isCompressed) {
GZIPInputStream(binaryAttachment.getInputDataStream())
} else {
binaryAttachment.getInputDataStream()
}.use { inputStream ->
binaryAttachment.getUnGzipInputDataStream().use { inputStream ->
inputStream.readBytes(bufferSize) { buffer ->
outputStream.write(buffer)
dataDownloaded += buffer.size