Merge branch 'feature/Dynamic_Memory' into feature/Dynamic_Memory_And_Encrypt_Module

This commit is contained in:
J-Jamet
2021-03-23 21:00:40 +01:00
11 changed files with 81 additions and 102 deletions

View File

@@ -229,7 +229,7 @@ class IconPickerActivity : LockingActivity() {
if (documentFile.length() > MAX_ICON_SIZE) { if (documentFile.length() > MAX_ICON_SIZE) {
iconCustomState.errorStringId = R.string.error_file_to_big iconCustomState.errorStringId = R.string.error_file_to_big
} else { } else {
mDatabase?.buildNewCustomIcon() { customIcon, binary -> mDatabase?.buildNewCustomIcon { customIcon, binary ->
if (customIcon != null) { if (customIcon != null) {
iconCustomState.iconCustom = customIcon iconCustomState.iconCustom = customIcon
mDatabase?.let { database -> mDatabase?.let { database ->
@@ -241,7 +241,7 @@ class IconPickerActivity : LockingActivity() {
when { when {
binary == null -> { binary == null -> {
} }
binary.getSize(database.binaryCache) <= 0 -> { binary.getSize() <= 0 -> {
} }
database.isCustomIconBinaryDuplicate(binary) -> { database.isCustomIconBinaryDuplicate(binary) -> {
iconCustomState.errorStringId = R.string.error_duplicate_file iconCustomState.errorStringId = R.string.error_duplicate_file

View File

@@ -69,9 +69,7 @@ class ImageViewerActivity : LockingActivity() {
supportActionBar?.title = attachment.name supportActionBar?.title = attachment.name
val size = mDatabase?.binaryCache?.let { val size = attachment.binaryData.getSize()
attachment.binaryData.getSize(it)
} ?: 0L
supportActionBar?.subtitle = Formatter.formatFileSize(this, size) supportActionBar?.subtitle = Formatter.formatFileSize(this, size)
mDatabase?.let { database -> mDatabase?.let { database ->

View File

@@ -126,9 +126,7 @@ class EntryAttachmentsItemsAdapter(context: Context)
holder.binaryFileTitle.setTextColor(mTitleColor) holder.binaryFileTitle.setTextColor(mTitleColor)
} }
val size = database?.binaryCache?.let { val size = entryAttachmentState.attachment.binaryData.getSize()
entryAttachmentState.attachment.binaryData.getSize(it)
} ?: 0L
holder.binaryFileSize.text = Formatter.formatFileSize(context, size) holder.binaryFileSize.text = Formatter.formatFileSize(context, size)
holder.binaryFileCompression.apply { holder.binaryFileCompression.apply {
if (entryAttachmentState.attachment.binaryData.isCompressed) { if (entryAttachmentState.attachment.binaryData.isCompressed) {

View File

@@ -60,17 +60,12 @@ class BinaryByte : BinaryData {
@Throws(IOException::class) @Throws(IOException::class)
override fun getInputDataStream(binaryCache: BinaryCache): InputStream { override fun getInputDataStream(binaryCache: BinaryCache): InputStream {
return when { return Base64InputStream(ByteArrayInputStream(getByteArray(binaryCache)), Base64.NO_WRAP)
getSize(binaryCache) > 0 -> {
Base64InputStream(ByteArrayInputStream(getByteArray(binaryCache)), Base64.NO_WRAP)
}
else -> ByteArrayInputStream(ByteArray(0))
}
} }
@Throws(IOException::class) @Throws(IOException::class)
override fun getOutputDataStream(binaryCache: BinaryCache): OutputStream { override fun getOutputDataStream(binaryCache: BinaryCache): OutputStream {
return Base64OutputStream(ByteOutputStream(binaryCache), Base64.NO_WRAP) return BinaryCountingOutputStream(Base64OutputStream(ByteOutputStream(binaryCache), Base64.NO_WRAP))
} }
@Throws(IOException::class) @Throws(IOException::class)
@@ -105,14 +100,6 @@ class BinaryByte : BinaryData {
return getByteArray(binaryCache).isNotEmpty() return getByteArray(binaryCache).isNotEmpty()
} }
override fun getSize(binaryCache: BinaryCache): Long {
return getByteArray(binaryCache).size.toLong()
}
override fun binaryHash(binaryCache: BinaryCache): Int {
return getByteArray(binaryCache).contentHashCode()
}
@Throws(IOException::class) @Throws(IOException::class)
override fun clear(binaryCache: BinaryCache) { override fun clear(binaryCache: BinaryCache) {
binaryCache.removeByteArray(mDataByteId) binaryCache.removeByteArray(mDataByteId)

View File

@@ -23,9 +23,12 @@ import android.app.ActivityManager
import android.content.Context import android.content.Context
import android.os.Parcel import android.os.Parcel
import android.os.Parcelable import android.os.Parcelable
import org.apache.commons.io.output.CountingOutputStream
import java.io.IOException import java.io.IOException
import java.io.InputStream import java.io.InputStream
import java.io.OutputStream import java.io.OutputStream
import java.nio.ByteBuffer
import java.security.MessageDigest
import java.util.zip.GZIPInputStream import java.util.zip.GZIPInputStream
import java.util.zip.GZIPOutputStream import java.util.zip.GZIPOutputStream
@@ -36,22 +39,30 @@ abstract class BinaryData : Parcelable {
var isProtected: Boolean = false var isProtected: Boolean = false
protected set protected set
var isCorrupted: Boolean = false var isCorrupted: Boolean = false
private var mLength: Long = 0
private var mBinaryHash = 0
protected constructor(compressed: Boolean = false, protected: Boolean = false) { protected constructor(compressed: Boolean = false, protected: Boolean = false) {
this.isCompressed = compressed this.isCompressed = compressed
this.isProtected = protected this.isProtected = protected
this.mLength = 0
this.mBinaryHash = 0
} }
protected constructor(parcel: Parcel) { protected constructor(parcel: Parcel) {
isCompressed = parcel.readByte().toInt() != 0 isCompressed = parcel.readByte().toInt() != 0
isProtected = parcel.readByte().toInt() != 0 isProtected = parcel.readByte().toInt() != 0
isCorrupted = parcel.readByte().toInt() != 0 isCorrupted = parcel.readByte().toInt() != 0
mLength = parcel.readLong()
mBinaryHash = parcel.readInt()
} }
override fun writeToParcel(dest: Parcel, flags: Int) { override fun writeToParcel(dest: Parcel, flags: Int) {
dest.writeByte((if (isCompressed) 1 else 0).toByte()) dest.writeByte((if (isCompressed) 1 else 0).toByte())
dest.writeByte((if (isProtected) 1 else 0).toByte()) dest.writeByte((if (isProtected) 1 else 0).toByte())
dest.writeByte((if (isCorrupted) 1 else 0).toByte()) dest.writeByte((if (isCorrupted) 1 else 0).toByte())
dest.writeLong(mLength)
dest.writeInt(mBinaryHash)
} }
@Throws(IOException::class) @Throws(IOException::class)
@@ -85,13 +96,19 @@ abstract class BinaryData : Parcelable {
abstract fun decompress(binaryCache: BinaryCache) abstract fun decompress(binaryCache: BinaryCache)
@Throws(IOException::class) @Throws(IOException::class)
abstract fun dataExists(binaryCache: BinaryCache): Boolean open fun dataExists(binaryCache: BinaryCache): Boolean {
return mLength > 0
}
@Throws(IOException::class) @Throws(IOException::class)
abstract fun getSize(binaryCache: BinaryCache): Long fun getSize(): Long {
return mLength
}
@Throws(IOException::class) @Throws(IOException::class)
abstract fun binaryHash(binaryCache: BinaryCache): Int fun binaryHash(): Int {
return mBinaryHash
}
@Throws(IOException::class) @Throws(IOException::class)
abstract fun clear(binaryCache: BinaryCache) abstract fun clear(binaryCache: BinaryCache)
@@ -115,9 +132,52 @@ abstract class BinaryData : Parcelable {
var result = isCompressed.hashCode() var result = isCompressed.hashCode()
result = 31 * result + isProtected.hashCode() result = 31 * result + isProtected.hashCode()
result = 31 * result + isCorrupted.hashCode() result = 31 * result + isCorrupted.hashCode()
result = 31 * result + mLength.hashCode()
result = 31 * result + mBinaryHash
return result return result
} }
/**
* Custom OutputStream to calculate the size and hash of binary file
*/
protected inner class BinaryCountingOutputStream(out: OutputStream): CountingOutputStream(out) {
private val mMessageDigest: MessageDigest
init {
mLength = 0
mMessageDigest = MessageDigest.getInstance("MD5")
mBinaryHash = 0
}
override fun beforeWrite(n: Int) {
super.beforeWrite(n)
mLength = byteCount
}
override fun write(idx: Int) {
super.write(idx)
mMessageDigest.update(idx.toByte())
}
override fun write(bts: ByteArray) {
super.write(bts)
mMessageDigest.update(bts)
}
override fun write(bts: ByteArray, st: Int, end: Int) {
super.write(bts, st, end)
mMessageDigest.update(bts, st, end)
}
override fun close() {
super.close()
mLength = byteCount
val bytes = mMessageDigest.digest()
mBinaryHash = ByteBuffer.wrap(bytes).int
}
}
companion object { companion object {
private val TAG = BinaryData::class.java.name private val TAG = BinaryData::class.java.name

View File

@@ -25,10 +25,7 @@ import android.util.Base64
import android.util.Base64InputStream import android.util.Base64InputStream
import android.util.Base64OutputStream import android.util.Base64OutputStream
import com.kunzisoft.keepass.stream.readAllBytes import com.kunzisoft.keepass.stream.readAllBytes
import org.apache.commons.io.output.CountingOutputStream
import java.io.* import java.io.*
import java.nio.ByteBuffer
import java.security.MessageDigest
import java.util.zip.GZIPOutputStream import java.util.zip.GZIPOutputStream
import javax.crypto.Cipher import javax.crypto.Cipher
import javax.crypto.CipherInputStream import javax.crypto.CipherInputStream
@@ -37,8 +34,6 @@ import javax.crypto.spec.IvParameterSpec
class BinaryFile : BinaryData { class BinaryFile : BinaryData {
private var mLength: Long = 0
private var mBinaryHash = 0
private var mDataFile: File? = null private var mDataFile: File? = null
// Cipher to encrypt temp file // Cipher to encrypt temp file
@@ -50,14 +45,10 @@ class BinaryFile : BinaryData {
constructor(dataFile: File, constructor(dataFile: File,
compressed: Boolean = false, compressed: Boolean = false,
protected: Boolean = false) : super(compressed, protected) { protected: Boolean = false) : super(compressed, protected) {
this.mLength = 0
this.mBinaryHash = 0
this.mDataFile = dataFile this.mDataFile = dataFile
} }
constructor(parcel: Parcel) : super(parcel) { constructor(parcel: Parcel) : super(parcel) {
mLength = parcel.readLong()
mBinaryHash = parcel.readInt()
parcel.readString()?.let { parcel.readString()?.let {
mDataFile = File(it) mDataFile = File(it)
} }
@@ -65,8 +56,6 @@ class BinaryFile : BinaryData {
override fun writeToParcel(dest: Parcel, flags: Int) { override fun writeToParcel(dest: Parcel, flags: Int) {
super.writeToParcel(dest, flags) super.writeToParcel(dest, flags)
dest.writeLong(mLength)
dest.writeInt(mBinaryHash)
dest.writeString(mDataFile?.absolutePath) dest.writeString(mDataFile?.absolutePath)
} }
@@ -154,15 +143,7 @@ class BinaryFile : BinaryData {
} }
override fun dataExists(binaryCache: BinaryCache): Boolean { override fun dataExists(binaryCache: BinaryCache): Boolean {
return mDataFile != null && mLength > 0 return mDataFile != null && super.dataExists(binaryCache)
}
override fun getSize(binaryCache: BinaryCache): Long {
return mLength
}
override fun binaryHash(binaryCache: BinaryCache): Int {
return mBinaryHash
} }
override fun clear(binaryCache: BinaryCache) { override fun clear(binaryCache: BinaryCache) {
@@ -185,51 +166,9 @@ class BinaryFile : BinaryData {
override fun hashCode(): Int { override fun hashCode(): Int {
var result = super.hashCode() var result = super.hashCode()
result = 31 * result + (mDataFile?.hashCode() ?: 0) result = 31 * result + (mDataFile?.hashCode() ?: 0)
result = 31 * result + mLength.hashCode()
result = 31 * result + mBinaryHash
return result return result
} }
/**
* Custom OutputStream to calculate the size and hash of binary file
*/
private inner class BinaryCountingOutputStream(out: OutputStream): CountingOutputStream(out) {
private val mMessageDigest: MessageDigest
init {
mLength = 0
mMessageDigest = MessageDigest.getInstance("MD5")
mBinaryHash = 0
}
override fun beforeWrite(n: Int) {
super.beforeWrite(n)
mLength = byteCount
}
override fun write(idx: Int) {
super.write(idx)
mMessageDigest.update(idx.toByte())
}
override fun write(bts: ByteArray) {
super.write(bts)
mMessageDigest.update(bts)
}
override fun write(bts: ByteArray, st: Int, end: Int) {
super.write(bts, st, end)
mMessageDigest.update(bts, st, end)
}
override fun close() {
super.close()
mLength = byteCount
val bytes = mMessageDigest.digest()
mBinaryHash = ByteBuffer.wrap(bytes).int
}
}
companion object { companion object {
private val TAG = BinaryFile::class.java.name private val TAG = BinaryFile::class.java.name

View File

@@ -120,11 +120,11 @@ abstract class BinaryPool<T>(private val mBinaryCache: BinaryCache) {
fun isBinaryDuplicate(binaryData: BinaryData?): Boolean { fun isBinaryDuplicate(binaryData: BinaryData?): Boolean {
try { try {
binaryData?.let { binaryData?.let {
if (it.getSize(mBinaryCache) > 0) { if (it.getSize() > 0) {
val searchBinaryMD5 = it.binaryHash(mBinaryCache) val searchBinaryMD5 = it.binaryHash()
var i = 0 var i = 0
for ((_, binary) in pool) { for ((_, binary) in pool) {
if (binary.binaryHash(mBinaryCache) == searchBinaryMD5) { if (binary.binaryHash() == searchBinaryMD5) {
i++ i++
if (i > 1) if (i > 1)
return true return true
@@ -164,10 +164,10 @@ abstract class BinaryPool<T>(private val mBinaryCache: BinaryCache) {
// Don't deduplicate // Don't deduplicate
val existentBinary = val existentBinary =
try { try {
if (binary.getSize(mBinaryCache) > 0) { if (binary.getSize() > 0) {
keyBinaryList.find { keyBinaryList.find {
val hash0 = it.binary.binaryHash(mBinaryCache) val hash0 = it.binary.binaryHash()
val hash1 = binary.binaryHash(mBinaryCache) val hash1 = binary.binaryHash()
hash0 != 0 && hash1 != 0 && hash0 == hash1 hash0 != 0 && hash1 != 0 && hash0 == hash1
} }
} else { } else {

View File

@@ -297,10 +297,7 @@ class EntryKDBX : EntryVersioned<UUID, UUID, GroupKDBX, EntryKDBX>, NodeKDBXInte
var size = 0L var size = 0L
for ((label, poolId) in binaries) { for ((label, poolId) in binaries) {
size += label.length.toLong() size += label.length.toLong()
val binarySize = mDatabase?.binaryCache?.let { size += attachmentPool[poolId]?.getSize() ?: 0
attachmentPool[poolId]?.getSize(it)
}
size += binarySize ?: 0
} }
return size return size
} }

View File

@@ -144,7 +144,7 @@ class DatabaseOutputKDBX(private val mDatabaseKDBX: DatabaseKDBX,
// Write type binary // Write type binary
dataOutputStream.writeByte(DatabaseHeaderKDBX.PwDbInnerHeaderV4Fields.Binary) dataOutputStream.writeByte(DatabaseHeaderKDBX.PwDbInnerHeaderV4Fields.Binary)
// Write size // Write size
dataOutputStream.writeUInt(UnsignedInt.fromKotlinLong(binary.getSize(binaryCache) + 1)) dataOutputStream.writeUInt(UnsignedInt.fromKotlinLong(binary.getSize() + 1))
// Write protected flag // Write protected flag
var flag = DatabaseHeaderKDBX.KdbxBinaryFlags.None var flag = DatabaseHeaderKDBX.KdbxBinaryFlags.None
if (binary.isProtected) { if (binary.isProtected) {
@@ -498,7 +498,7 @@ class DatabaseOutputKDBX(private val mDatabaseKDBX: DatabaseKDBX,
mDatabaseKDBX.attachmentPool.doForEachOrderedBinaryWithoutDuplication { index, binary -> mDatabaseKDBX.attachmentPool.doForEachOrderedBinaryWithoutDuplication { index, binary ->
xml.startTag(null, DatabaseKDBXXML.ElemBinary) xml.startTag(null, DatabaseKDBXXML.ElemBinary)
xml.attribute(null, DatabaseKDBXXML.AttrId, index.toString()) xml.attribute(null, DatabaseKDBXXML.AttrId, index.toString())
if (binary.getSize(binaryCache) > 0) { if (binary.getSize() > 0) {
if (binary.isCompressed) { if (binary.isCompressed) {
xml.attribute(null, DatabaseKDBXXML.AttrCompressed, DatabaseKDBXXML.ValTrue) xml.attribute(null, DatabaseKDBXXML.AttrCompressed, DatabaseKDBXXML.ValTrue)
} }

View File

@@ -95,7 +95,7 @@ class EntryOutputKDB(private val mDatabase: DatabaseKDB,
// Binary // Binary
mOutputStream.write(BINARY_DATA_FIELD_TYPE) mOutputStream.write(BINARY_DATA_FIELD_TYPE)
val binaryData = mEntry.getBinary(mDatabase.attachmentPool) val binaryData = mEntry.getBinary(mDatabase.attachmentPool)
val binaryDataLength = binaryData?.getSize(mDatabase.binaryCache) ?: 0L val binaryDataLength = binaryData?.getSize() ?: 0L
// Write data length // Write data length
mOutputStream.write(uIntTo4Bytes(UnsignedInt.fromKotlinLong(binaryDataLength))) mOutputStream.write(uIntTo4Bytes(UnsignedInt.fromKotlinLong(binaryDataLength)))
// Write data // Write data

View File

@@ -40,7 +40,7 @@ object BinaryDatabaseManager {
update: ((percent: Int)->Unit)? = null, update: ((percent: Int)->Unit)? = null,
canceled: ()-> Boolean = { false }, canceled: ()-> Boolean = { false },
bufferSize: Int = DEFAULT_BUFFER_SIZE) { bufferSize: Int = DEFAULT_BUFFER_SIZE) {
val fileSize = binaryData.getSize(binaryCache) val fileSize = binaryData.getSize()
var dataDownloaded = 0L var dataDownloaded = 0L
binaryData.getUnGzipInputDataStream(binaryCache).use { inputStream -> binaryData.getUnGzipInputDataStream(binaryCache).use { inputStream ->
inputStream.readAllBytes(bufferSize, canceled) { buffer -> inputStream.readAllBytes(bufferSize, canceled) { buffer ->