mirror of
https://github.com/Kunzisoft/KeePassDX.git
synced 2025-12-04 15:49:33 +01:00
Write only attachments in header
Remove unlinked attachments Simpler compression
This commit is contained in:
@@ -333,9 +333,11 @@ class EntryActivity : LockingActivity() {
|
|||||||
entryContentsView?.setHiddenProtectedValue(!mShowPassword)
|
entryContentsView?.setHiddenProtectedValue(!mShowPassword)
|
||||||
|
|
||||||
// Manage attachments
|
// Manage attachments
|
||||||
entryContentsView?.assignAttachments(entry.getAttachments(), StreamDirection.DOWNLOAD) { attachmentItem ->
|
mDatabase?.binaryPool?.let { binaryPool ->
|
||||||
createDocument(this, attachmentItem.name)?.let { requestCode ->
|
entryContentsView?.assignAttachments(entry.getAttachments(binaryPool), StreamDirection.DOWNLOAD) { attachmentItem ->
|
||||||
mAttachmentsToDownload[requestCode] = attachmentItem
|
createDocument(this, attachmentItem.name)?.let { requestCode ->
|
||||||
|
mAttachmentsToDownload[requestCode] = attachmentItem
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -358,8 +358,11 @@ class EntryEditActivity : LockingActivity(),
|
|||||||
assignExtraFields(newEntry.customFields.mapTo(ArrayList()) {
|
assignExtraFields(newEntry.customFields.mapTo(ArrayList()) {
|
||||||
Field(it.key, it.value)
|
Field(it.key, it.value)
|
||||||
}, mFocusedEditExtraField)
|
}, mFocusedEditExtraField)
|
||||||
assignAttachments(newEntry.getAttachments(), StreamDirection.UPLOAD) { attachment ->
|
|
||||||
newEntry.removeAttachment(attachment)
|
mDatabase?.binaryPool?.let { binaryPool ->
|
||||||
|
assignAttachments(newEntry.getAttachments(binaryPool), StreamDirection.UPLOAD) { attachment ->
|
||||||
|
newEntry.removeAttachment(attachment, binaryPool)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -384,8 +387,10 @@ class EntryEditActivity : LockingActivity(),
|
|||||||
entryView.getExtraFields().forEach { customField ->
|
entryView.getExtraFields().forEach { customField ->
|
||||||
putExtraField(customField.name, customField.protectedValue)
|
putExtraField(customField.name, customField.protectedValue)
|
||||||
}
|
}
|
||||||
entryView.getAttachments().forEach {
|
mDatabase?.binaryPool?.let { binaryPool ->
|
||||||
putAttachment(it)
|
entryView.getAttachments().forEach {
|
||||||
|
putAttachment(it, binaryPool)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
mFocusedEditExtraField = entryView.getExtraFieldFocused()
|
mFocusedEditExtraField = entryView.getExtraFieldFocused()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -337,8 +337,10 @@ class NodeAdapter (private val context: Context)
|
|||||||
setTextSize(textSizeUnit, subtextDefaultDimension, prefSizeMultiplier)
|
setTextSize(textSizeUnit, subtextDefaultDimension, prefSizeMultiplier)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
holder.attachmentIcon?.visibility =
|
holder.attachmentIcon?.visibility =
|
||||||
if (entry.getAttachments().isNotEmpty()) View.VISIBLE else View.GONE
|
if (entry.getAttachments(mDatabase.binaryPool).isNotEmpty())
|
||||||
|
View.VISIBLE else View.GONE
|
||||||
|
|
||||||
mDatabase.stopManageEntry(entry)
|
mDatabase.stopManageEntry(entry)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ open class SaveDatabaseRunnable(protected var context: Context,
|
|||||||
override fun onStartRun() {}
|
override fun onStartRun() {}
|
||||||
|
|
||||||
override fun onActionRun() {
|
override fun onActionRun() {
|
||||||
|
database.removeUnlinkedAttachment()
|
||||||
if (saveDatabase && result.isSuccess) {
|
if (saveDatabase && result.isSuccess) {
|
||||||
try {
|
try {
|
||||||
database.saveData(context.contentResolver)
|
database.saveData(context.contentResolver)
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ class UpdateEntryRunnable constructor(
|
|||||||
|
|
||||||
// Create an entry history (an entry history don't have history)
|
// Create an entry history (an entry history don't have history)
|
||||||
mOldEntry.addEntryToHistory(Entry(mBackupEntryHistory, copyHistory = false))
|
mOldEntry.addEntryToHistory(Entry(mBackupEntryHistory, copyHistory = false))
|
||||||
database.removeOldestEntryHistory(mOldEntry)
|
database.removeOldestEntryHistory(mOldEntry, database.binaryPool)
|
||||||
|
|
||||||
// Only change data in index
|
// Only change data in index
|
||||||
database.updateEntry(mOldEntry)
|
database.updateEntry(mOldEntry)
|
||||||
|
|||||||
@@ -25,9 +25,7 @@ import android.net.Uri
|
|||||||
import android.util.Log
|
import android.util.Log
|
||||||
import com.kunzisoft.keepass.crypto.keyDerivation.KdfEngine
|
import com.kunzisoft.keepass.crypto.keyDerivation.KdfEngine
|
||||||
import com.kunzisoft.keepass.database.action.node.NodeHandler
|
import com.kunzisoft.keepass.database.action.node.NodeHandler
|
||||||
import com.kunzisoft.keepass.database.element.database.CompressionAlgorithm
|
import com.kunzisoft.keepass.database.element.database.*
|
||||||
import com.kunzisoft.keepass.database.element.database.DatabaseKDB
|
|
||||||
import com.kunzisoft.keepass.database.element.database.DatabaseKDBX
|
|
||||||
import com.kunzisoft.keepass.database.element.icon.IconImageFactory
|
import com.kunzisoft.keepass.database.element.icon.IconImageFactory
|
||||||
import com.kunzisoft.keepass.database.element.node.NodeId
|
import com.kunzisoft.keepass.database.element.node.NodeId
|
||||||
import com.kunzisoft.keepass.database.element.node.NodeIdInt
|
import com.kunzisoft.keepass.database.element.node.NodeIdInt
|
||||||
@@ -430,6 +428,11 @@ class Database {
|
|||||||
}, omitBackup, max)
|
}, omitBackup, max)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val binaryPool: BinaryPool
|
||||||
|
get() {
|
||||||
|
return mDatabaseKDBX?.binaryPool ?: BinaryPool()
|
||||||
|
}
|
||||||
|
|
||||||
val allowMultipleAttachments: Boolean
|
val allowMultipleAttachments: Boolean
|
||||||
get() {
|
get() {
|
||||||
if (mDatabaseKDB != null)
|
if (mDatabaseKDB != null)
|
||||||
@@ -441,7 +444,7 @@ class Database {
|
|||||||
|
|
||||||
fun buildNewBinary(cacheDirectory: File,
|
fun buildNewBinary(cacheDirectory: File,
|
||||||
enableProtection: Boolean = false,
|
enableProtection: Boolean = false,
|
||||||
compressed: Boolean? = null): BinaryAttachment? {
|
compressed: Boolean = false): BinaryAttachment? {
|
||||||
return mDatabaseKDB?.buildNewBinary(cacheDirectory)
|
return mDatabaseKDB?.buildNewBinary(cacheDirectory)
|
||||||
?: mDatabaseKDBX?.buildNewBinary(cacheDirectory, enableProtection, compressed)
|
?: mDatabaseKDBX?.buildNewBinary(cacheDirectory, enableProtection, compressed)
|
||||||
}
|
}
|
||||||
@@ -828,7 +831,7 @@ class Database {
|
|||||||
rootGroup?.doForEachChildAndForIt(
|
rootGroup?.doForEachChildAndForIt(
|
||||||
object : NodeHandler<Entry>() {
|
object : NodeHandler<Entry>() {
|
||||||
override fun operate(node: Entry): Boolean {
|
override fun operate(node: Entry): Boolean {
|
||||||
removeOldestEntryHistory(node)
|
removeOldestEntryHistory(node, binaryPool)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -836,7 +839,8 @@ class Database {
|
|||||||
override fun operate(node: Group): Boolean {
|
override fun operate(node: Group): Boolean {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun removeEachEntryHistory() {
|
fun removeEachEntryHistory() {
|
||||||
@@ -857,9 +861,8 @@ class Database {
|
|||||||
/**
|
/**
|
||||||
* Remove oldest history if more than max items or max memory
|
* Remove oldest history if more than max items or max memory
|
||||||
*/
|
*/
|
||||||
fun removeOldestEntryHistory(entry: Entry) {
|
fun removeOldestEntryHistory(entry: Entry, binaryPool: BinaryPool) {
|
||||||
mDatabaseKDBX?.let {
|
mDatabaseKDBX?.let {
|
||||||
|
|
||||||
val maxItems = historyMaxItems
|
val maxItems = historyMaxItems
|
||||||
if (maxItems >= 0) {
|
if (maxItems >= 0) {
|
||||||
while (entry.getHistory().size > maxItems) {
|
while (entry.getHistory().size > maxItems) {
|
||||||
@@ -872,7 +875,7 @@ class Database {
|
|||||||
while (true) {
|
while (true) {
|
||||||
var historySize: Long = 0
|
var historySize: Long = 0
|
||||||
for (entryHistory in entry.getHistory()) {
|
for (entryHistory in entry.getHistory()) {
|
||||||
historySize += entryHistory.getSize()
|
historySize += entryHistory.getSize(binaryPool)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (historySize > maxSize) {
|
if (historySize > maxSize) {
|
||||||
|
|||||||
@@ -21,6 +21,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.database.element.database.BinaryPool
|
||||||
import com.kunzisoft.keepass.database.element.database.DatabaseKDBX
|
import com.kunzisoft.keepass.database.element.database.DatabaseKDBX
|
||||||
import com.kunzisoft.keepass.database.element.entry.EntryKDB
|
import com.kunzisoft.keepass.database.element.entry.EntryKDB
|
||||||
import com.kunzisoft.keepass.database.element.entry.EntryKDBX
|
import com.kunzisoft.keepass.database.element.entry.EntryKDBX
|
||||||
@@ -316,38 +317,38 @@ class Entry : Node, EntryVersionedInterface<Group> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun startToManageFieldReferences(db: DatabaseKDBX) {
|
fun startToManageFieldReferences(database: DatabaseKDBX) {
|
||||||
entryKDBX?.startToManageFieldReferences(db)
|
entryKDBX?.startToManageFieldReferences(database)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun stopToManageFieldReferences() {
|
fun stopToManageFieldReferences() {
|
||||||
entryKDBX?.stopToManageFieldReferences()
|
entryKDBX?.stopToManageFieldReferences()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getAttachments(): ArrayList<Attachment> {
|
fun getAttachments(binaryPool: BinaryPool): ArrayList<Attachment> {
|
||||||
val attachments = ArrayList<Attachment>()
|
val attachments = ArrayList<Attachment>()
|
||||||
entryKDB?.getAttachments()?.let {
|
entryKDB?.getAttachments()?.let {
|
||||||
attachments.addAll(it)
|
attachments.addAll(it)
|
||||||
}
|
}
|
||||||
entryKDBX?.getAttachments()?.let {
|
entryKDBX?.getAttachments(binaryPool)?.let {
|
||||||
attachments.addAll(it)
|
attachments.addAll(it)
|
||||||
}
|
}
|
||||||
return attachments
|
return attachments
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun containsAttachment(attachment: Attachment): Boolean {
|
fun containsAttachment(attachment: Attachment, binaryPool: BinaryPool): Boolean {
|
||||||
return entryKDB?.containsAttachment(attachment) == true
|
return entryKDB?.containsAttachment(attachment) == true
|
||||||
|| entryKDBX?.containsAttachment(attachment) == true
|
|| entryKDBX?.containsAttachment(attachment, binaryPool) == true
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun putAttachment(attachment: Attachment) {
|
fun putAttachment(attachment: Attachment, binaryPool: BinaryPool) {
|
||||||
entryKDB?.putAttachment(attachment)
|
entryKDB?.putAttachment(attachment)
|
||||||
entryKDBX?.putAttachment(attachment)
|
entryKDBX?.putAttachment(attachment, binaryPool)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun removeAttachment(attachment: Attachment) {
|
fun removeAttachment(attachment: Attachment, binaryPool: BinaryPool) {
|
||||||
entryKDB?.removeAttachment(attachment)
|
entryKDB?.removeAttachment(attachment)
|
||||||
entryKDBX?.removeAttachment(attachment)
|
entryKDBX?.removeAttachment(attachment, binaryPool)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getHistory(): ArrayList<Entry> {
|
fun getHistory(): ArrayList<Entry> {
|
||||||
@@ -377,8 +378,8 @@ class Entry : Node, EntryVersionedInterface<Group> {
|
|||||||
entryKDBX?.removeOldestEntryFromHistory()
|
entryKDBX?.removeOldestEntryFromHistory()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getSize(): Long {
|
fun getSize(binaryPool: BinaryPool): Long {
|
||||||
return entryKDBX?.size ?: 0L
|
return entryKDBX?.getSize(binaryPool) ?: 0L
|
||||||
}
|
}
|
||||||
|
|
||||||
fun containsCustomData(): Boolean {
|
fun containsCustomData(): Boolean {
|
||||||
|
|||||||
@@ -19,26 +19,32 @@
|
|||||||
*/
|
*/
|
||||||
package com.kunzisoft.keepass.database.element.database
|
package com.kunzisoft.keepass.database.element.database
|
||||||
|
|
||||||
import android.util.SparseArray
|
|
||||||
import androidx.core.util.forEach
|
|
||||||
import com.kunzisoft.keepass.database.element.security.BinaryAttachment
|
import com.kunzisoft.keepass.database.element.security.BinaryAttachment
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
|
|
||||||
class BinaryPool {
|
class BinaryPool {
|
||||||
private val pool = SparseArray<BinaryAttachment>()
|
private val pool = LinkedHashMap<Int, BinaryAttachment>()
|
||||||
|
|
||||||
operator fun get(key: Int): BinaryAttachment? {
|
operator fun get(key: Int): BinaryAttachment? {
|
||||||
return pool[key]
|
return pool[key]
|
||||||
}
|
}
|
||||||
|
|
||||||
fun put(key: Int, value: BinaryAttachment) {
|
fun put(key: Int, value: BinaryAttachment) {
|
||||||
pool.put(key, value)
|
pool[key] = value
|
||||||
}
|
}
|
||||||
|
|
||||||
fun add(binaryAttachment: BinaryAttachment) {
|
/**
|
||||||
if (findKey(binaryAttachment) == null) {
|
* To put a [binaryAttachment] in the pool,
|
||||||
pool.put(findUnusedKey(), binaryAttachment)
|
* if already exists, replace the current one,
|
||||||
|
* else add it with a new key
|
||||||
|
*/
|
||||||
|
fun put(binaryAttachment: BinaryAttachment): Int {
|
||||||
|
var key = findKey(binaryAttachment)
|
||||||
|
if (key == null) {
|
||||||
|
key = findUnusedKey()
|
||||||
}
|
}
|
||||||
|
pool[key] = binaryAttachment
|
||||||
|
return key
|
||||||
}
|
}
|
||||||
|
|
||||||
@Throws(IOException::class)
|
@Throws(IOException::class)
|
||||||
@@ -57,26 +63,39 @@ class BinaryPool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return position of [binaryAttachmentToRetrieve] or null if not found
|
* Return key of [binaryAttachmentToRetrieve] or null if not found
|
||||||
*/
|
*/
|
||||||
fun findKey(binaryAttachmentToRetrieve: BinaryAttachment): Int? {
|
private fun findKey(binaryAttachmentToRetrieve: BinaryAttachment): Int? {
|
||||||
val index = pool.indexOfValue(binaryAttachmentToRetrieve)
|
val contains = pool.containsValue(binaryAttachmentToRetrieve)
|
||||||
return if (index < 0)
|
return if (!contains)
|
||||||
null
|
null
|
||||||
else
|
else {
|
||||||
pool.keyAt(index)
|
for ((key, binary) in pool) {
|
||||||
|
if (binary == binaryAttachmentToRetrieve) {
|
||||||
|
return key
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun doForEachBinary(action: (key: Int, binary: BinaryAttachment) -> Unit) {
|
/**
|
||||||
pool.forEach { key, binaryAttachment ->
|
* Warning 2 keys can point the same binary
|
||||||
action.invoke(key, binaryAttachment)
|
*/
|
||||||
|
fun doForEach(action: (key: Int, binary: BinaryAttachment) -> Unit) {
|
||||||
|
for ((key, binary) in pool) {
|
||||||
|
action.invoke(key, binary)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun doForEachBinary(action: (binary: BinaryAttachment) -> Unit) {
|
||||||
|
pool.values.toSet().forEach { action.invoke(it) }
|
||||||
|
}
|
||||||
|
|
||||||
@Throws(IOException::class)
|
@Throws(IOException::class)
|
||||||
fun clear() {
|
fun clear() {
|
||||||
pool.forEach { _, binary ->
|
doForEachBinary {
|
||||||
binary.clear()
|
it.clear()
|
||||||
}
|
}
|
||||||
pool.clear()
|
pool.clear()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -177,8 +177,7 @@ class DatabaseKDBX : DatabaseVersioned<UUID, UUID, GroupKDBX, EntryKDBX> {
|
|||||||
|
|
||||||
fun changeBinaryCompression(oldCompression: CompressionAlgorithm,
|
fun changeBinaryCompression(oldCompression: CompressionAlgorithm,
|
||||||
newCompression: CompressionAlgorithm) {
|
newCompression: CompressionAlgorithm) {
|
||||||
binaryPool.doForEachBinary { key, binary ->
|
binaryPool.doForEachBinary { binary ->
|
||||||
|
|
||||||
try {
|
try {
|
||||||
when (oldCompression) {
|
when (oldCompression) {
|
||||||
CompressionAlgorithm.None -> {
|
CompressionAlgorithm.None -> {
|
||||||
@@ -203,7 +202,7 @@ class DatabaseKDBX : DatabaseVersioned<UUID, UUID, GroupKDBX, EntryKDBX> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e(TAG, "Unable to change compression for $key", e)
|
Log.e(TAG, "Unable to change compression for $binary", e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -542,7 +541,7 @@ class DatabaseKDBX : DatabaseVersioned<UUID, UUID, GroupKDBX, EntryKDBX> {
|
|||||||
|
|
||||||
fun buildNewBinary(cacheDirectory: File,
|
fun buildNewBinary(cacheDirectory: File,
|
||||||
protection: Boolean,
|
protection: Boolean,
|
||||||
compression: Boolean?,
|
compression: Boolean,
|
||||||
cacheId: String? = null): BinaryAttachment {
|
cacheId: String? = null): BinaryAttachment {
|
||||||
// Unused cache key if needed
|
// Unused cache key if needed
|
||||||
val binaryId = cacheId ?: binaryPool.findUnusedKey().toString()
|
val binaryId = cacheId ?: binaryPool.findUnusedKey().toString()
|
||||||
@@ -558,12 +557,11 @@ class DatabaseKDBX : DatabaseVersioned<UUID, UUID, GroupKDBX, EntryKDBX> {
|
|||||||
removeUnlinkedAttachment(attachment.binaryAttachment)
|
removeUnlinkedAttachment(attachment.binaryAttachment)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO buf unlink right element
|
|
||||||
fun removeUnlinkedAttachment(vararg binaries: BinaryAttachment) {
|
fun removeUnlinkedAttachment(vararg binaries: BinaryAttachment) {
|
||||||
// Build binaries to remove with all binaries known
|
// Build binaries to remove with all binaries known
|
||||||
val binariesToRemove = ArrayList<BinaryAttachment>()
|
val binariesToRemove = ArrayList<BinaryAttachment>()
|
||||||
if (binaries.isEmpty()) {
|
if (binaries.isEmpty()) {
|
||||||
binaryPool.doForEachBinary { _, binary ->
|
binaryPool.doForEachBinary { binary ->
|
||||||
binariesToRemove.add(binary)
|
binariesToRemove.add(binary)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -572,7 +570,7 @@ class DatabaseKDBX : DatabaseVersioned<UUID, UUID, GroupKDBX, EntryKDBX> {
|
|||||||
// Remove binaries from the list
|
// Remove binaries from the list
|
||||||
rootGroup?.doForEachChild(object : NodeHandler<EntryKDBX>() {
|
rootGroup?.doForEachChild(object : NodeHandler<EntryKDBX>() {
|
||||||
override fun operate(node: EntryKDBX): Boolean {
|
override fun operate(node: EntryKDBX): Boolean {
|
||||||
node.getAttachments().forEach {
|
node.getAttachments(binaryPool).forEach {
|
||||||
binariesToRemove.remove(it.binaryAttachment)
|
binariesToRemove.remove(it.binaryAttachment)
|
||||||
}
|
}
|
||||||
return binariesToRemove.isNotEmpty()
|
return binariesToRemove.isNotEmpty()
|
||||||
|
|||||||
@@ -137,7 +137,7 @@ class EntryKDB : EntryVersioned<Int, UUID, GroupKDB, EntryKDB>, NodeKDBInterface
|
|||||||
override val type: Type
|
override val type: Type
|
||||||
get() = Type.ENTRY
|
get() = Type.ENTRY
|
||||||
|
|
||||||
override fun getAttachments(): ArrayList<Attachment> {
|
fun getAttachments(): ArrayList<Attachment> {
|
||||||
return ArrayList<Attachment>().apply {
|
return ArrayList<Attachment>().apply {
|
||||||
val binary = binaryData
|
val binary = binaryData
|
||||||
if (binary != null)
|
if (binary != null)
|
||||||
@@ -145,16 +145,16 @@ class EntryKDB : EntryVersioned<Int, UUID, GroupKDB, EntryKDB>, NodeKDBInterface
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun containsAttachment(attachment: Attachment): Boolean {
|
fun containsAttachment(attachment: Attachment): Boolean {
|
||||||
return binaryData != null
|
return binaryData != null
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun putAttachment(attachment: Attachment) {
|
fun putAttachment(attachment: Attachment) {
|
||||||
this.binaryDescription = attachment.name
|
this.binaryDescription = attachment.name
|
||||||
this.binaryData = attachment.binaryAttachment
|
this.binaryData = attachment.binaryAttachment
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun removeAttachment(attachment: Attachment) {
|
fun removeAttachment(attachment: Attachment) {
|
||||||
if (this.binaryDescription == attachment.name) {
|
if (this.binaryDescription == attachment.name) {
|
||||||
this.binaryDescription = ""
|
this.binaryDescription = ""
|
||||||
this.binaryData = null
|
this.binaryData = null
|
||||||
|
|||||||
@@ -31,9 +31,9 @@ import com.kunzisoft.keepass.database.element.node.NodeId
|
|||||||
import com.kunzisoft.keepass.database.element.node.NodeIdUUID
|
import com.kunzisoft.keepass.database.element.node.NodeIdUUID
|
||||||
import com.kunzisoft.keepass.database.element.node.NodeKDBXInterface
|
import com.kunzisoft.keepass.database.element.node.NodeKDBXInterface
|
||||||
import com.kunzisoft.keepass.database.element.node.Type
|
import com.kunzisoft.keepass.database.element.node.Type
|
||||||
import com.kunzisoft.keepass.database.element.security.BinaryAttachment
|
|
||||||
import com.kunzisoft.keepass.database.element.security.ProtectedString
|
import com.kunzisoft.keepass.database.element.security.ProtectedString
|
||||||
import com.kunzisoft.keepass.database.element.Attachment
|
import com.kunzisoft.keepass.database.element.Attachment
|
||||||
|
import com.kunzisoft.keepass.database.element.database.BinaryPool
|
||||||
import com.kunzisoft.keepass.utils.ParcelableUtil
|
import com.kunzisoft.keepass.utils.ParcelableUtil
|
||||||
import com.kunzisoft.keepass.utils.UnsignedLong
|
import com.kunzisoft.keepass.utils.UnsignedLong
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@@ -64,7 +64,7 @@ class EntryKDBX : EntryVersioned<UUID, UUID, GroupKDBX, EntryKDBX>, NodeKDBXInte
|
|||||||
private var customData = LinkedHashMap<String, String>()
|
private var customData = LinkedHashMap<String, String>()
|
||||||
// TODO Private
|
// TODO Private
|
||||||
var fields = LinkedHashMap<String, ProtectedString>()
|
var fields = LinkedHashMap<String, ProtectedString>()
|
||||||
private var binaries = LinkedHashMap<String, BinaryAttachment>()
|
var binaries = LinkedHashMap<String, Int>() // Map<Label, PoolId>
|
||||||
var foregroundColor = ""
|
var foregroundColor = ""
|
||||||
var backgroundColor = ""
|
var backgroundColor = ""
|
||||||
var overrideURL = ""
|
var overrideURL = ""
|
||||||
@@ -73,36 +73,32 @@ class EntryKDBX : EntryVersioned<UUID, UUID, GroupKDBX, EntryKDBX>, NodeKDBXInte
|
|||||||
var additional = ""
|
var additional = ""
|
||||||
var tags = ""
|
var tags = ""
|
||||||
|
|
||||||
val size: Long
|
fun getSize(binaryPool: BinaryPool): Long {
|
||||||
get() {
|
var size = FIXED_LENGTH_SIZE
|
||||||
var size = FIXED_LENGTH_SIZE
|
|
||||||
|
|
||||||
for (entry in fields.entries) {
|
for (entry in fields.entries) {
|
||||||
size += entry.key.length.toLong()
|
size += entry.key.length.toLong()
|
||||||
size += entry.value.length().toLong()
|
size += entry.value.length().toLong()
|
||||||
}
|
|
||||||
|
|
||||||
for ((key, value) in binaries) {
|
|
||||||
size += key.length.toLong()
|
|
||||||
size += value.length()
|
|
||||||
}
|
|
||||||
|
|
||||||
size += autoType.defaultSequence.length.toLong()
|
|
||||||
for ((key, value) in autoType.entrySet()) {
|
|
||||||
size += key.length.toLong()
|
|
||||||
size += value.length.toLong()
|
|
||||||
}
|
|
||||||
|
|
||||||
for (entry in history) {
|
|
||||||
size += entry.size
|
|
||||||
}
|
|
||||||
|
|
||||||
size += overrideURL.length.toLong()
|
|
||||||
size += tags.length.toLong()
|
|
||||||
|
|
||||||
return size
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size += getAttachmentsSize(binaryPool)
|
||||||
|
|
||||||
|
size += autoType.defaultSequence.length.toLong()
|
||||||
|
for ((key, value) in autoType.entrySet()) {
|
||||||
|
size += key.length.toLong()
|
||||||
|
size += value.length.toLong()
|
||||||
|
}
|
||||||
|
|
||||||
|
for (entry in history) {
|
||||||
|
size += entry.getSize(binaryPool)
|
||||||
|
}
|
||||||
|
|
||||||
|
size += overrideURL.length.toLong()
|
||||||
|
size += tags.length.toLong()
|
||||||
|
|
||||||
|
return size
|
||||||
|
}
|
||||||
|
|
||||||
override var expires: Boolean = false
|
override var expires: Boolean = false
|
||||||
|
|
||||||
constructor() : super()
|
constructor() : super()
|
||||||
@@ -113,7 +109,7 @@ class EntryKDBX : EntryVersioned<UUID, UUID, GroupKDBX, EntryKDBX>, NodeKDBXInte
|
|||||||
locationChanged = parcel.readParcelable(DateInstant::class.java.classLoader) ?: locationChanged
|
locationChanged = parcel.readParcelable(DateInstant::class.java.classLoader) ?: locationChanged
|
||||||
customData = ParcelableUtil.readStringParcelableMap(parcel)
|
customData = ParcelableUtil.readStringParcelableMap(parcel)
|
||||||
fields = ParcelableUtil.readStringParcelableMap(parcel, ProtectedString::class.java)
|
fields = ParcelableUtil.readStringParcelableMap(parcel, ProtectedString::class.java)
|
||||||
binaries = ParcelableUtil.readStringParcelableMap(parcel, BinaryAttachment::class.java)
|
binaries = ParcelableUtil.readStringIntMap(parcel)
|
||||||
foregroundColor = parcel.readString() ?: foregroundColor
|
foregroundColor = parcel.readString() ?: foregroundColor
|
||||||
backgroundColor = parcel.readString() ?: backgroundColor
|
backgroundColor = parcel.readString() ?: backgroundColor
|
||||||
overrideURL = parcel.readString() ?: overrideURL
|
overrideURL = parcel.readString() ?: overrideURL
|
||||||
@@ -131,7 +127,7 @@ class EntryKDBX : EntryVersioned<UUID, UUID, GroupKDBX, EntryKDBX>, NodeKDBXInte
|
|||||||
dest.writeParcelable(locationChanged, flags)
|
dest.writeParcelable(locationChanged, flags)
|
||||||
ParcelableUtil.writeStringParcelableMap(dest, customData)
|
ParcelableUtil.writeStringParcelableMap(dest, customData)
|
||||||
ParcelableUtil.writeStringParcelableMap(dest, flags, fields)
|
ParcelableUtil.writeStringParcelableMap(dest, flags, fields)
|
||||||
ParcelableUtil.writeStringParcelableMap(dest, flags, binaries)
|
ParcelableUtil.writeStringIntMap(dest, binaries)
|
||||||
dest.writeString(foregroundColor)
|
dest.writeString(foregroundColor)
|
||||||
dest.writeString(backgroundColor)
|
dest.writeString(backgroundColor)
|
||||||
dest.writeString(overrideURL)
|
dest.writeString(overrideURL)
|
||||||
@@ -170,8 +166,8 @@ class EntryKDBX : EntryVersioned<UUID, UUID, GroupKDBX, EntryKDBX>, NodeKDBXInte
|
|||||||
tags = source.tags
|
tags = source.tags
|
||||||
}
|
}
|
||||||
|
|
||||||
fun startToManageFieldReferences(db: DatabaseKDBX) {
|
fun startToManageFieldReferences(database: DatabaseKDBX) {
|
||||||
this.mDatabase = db
|
this.mDatabase = database
|
||||||
this.mDecodeRef = true
|
this.mDecodeRef = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -287,28 +283,40 @@ class EntryKDBX : EntryVersioned<UUID, UUID, GroupKDBX, EntryKDBX>, NodeKDBXInte
|
|||||||
fields[label] = value
|
fields[label] = value
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getAttachments(): ArrayList<Attachment> {
|
fun getAttachments(binaryPool: BinaryPool): ArrayList<Attachment> {
|
||||||
val entryAttachmentList = ArrayList<Attachment>()
|
val entryAttachmentList = ArrayList<Attachment>()
|
||||||
for ((key, value) in binaries) {
|
for ((label, poolId) in binaries) {
|
||||||
entryAttachmentList.add(Attachment(key, value))
|
binaryPool[poolId]?.let { binary ->
|
||||||
|
entryAttachmentList.add(Attachment(label, binary))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return entryAttachmentList
|
return entryAttachmentList
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun containsAttachment(attachment: Attachment): Boolean {
|
fun containsAttachment(attachment: Attachment, binaryPool: BinaryPool): Boolean {
|
||||||
for ((_, binary) in binaries) {
|
for ((_, poolId) in binaries) {
|
||||||
if (binary == attachment.binaryAttachment)
|
if (binaryPool[poolId] == attachment.binaryAttachment)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun putAttachment(attachment: Attachment) {
|
fun putAttachment(attachment: Attachment, binaryPool: BinaryPool) {
|
||||||
binaries[attachment.name] = attachment.binaryAttachment
|
binaries[attachment.name] = binaryPool.put(attachment.binaryAttachment)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun removeAttachment(attachment: Attachment) {
|
fun removeAttachment(attachment: Attachment, binaryPool: BinaryPool) {
|
||||||
binaries.remove(attachment.name)
|
binaries.remove(attachment.name)
|
||||||
|
binaryPool.remove(attachment.binaryAttachment)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getAttachmentsSize(binaryPool: BinaryPool): Long {
|
||||||
|
var size = 0L
|
||||||
|
for ((label, poolId) in binaries) {
|
||||||
|
size += label.length.toLong()
|
||||||
|
size += binaryPool[poolId]?.length() ?: 0
|
||||||
|
}
|
||||||
|
return size
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO Remove ?
|
// TODO Remove ?
|
||||||
|
|||||||
@@ -20,7 +20,6 @@
|
|||||||
package com.kunzisoft.keepass.database.element.entry
|
package com.kunzisoft.keepass.database.element.entry
|
||||||
|
|
||||||
import com.kunzisoft.keepass.database.element.node.NodeVersionedInterface
|
import com.kunzisoft.keepass.database.element.node.NodeVersionedInterface
|
||||||
import com.kunzisoft.keepass.database.element.Attachment
|
|
||||||
|
|
||||||
interface EntryVersionedInterface<ParentGroup> : NodeVersionedInterface<ParentGroup> {
|
interface EntryVersionedInterface<ParentGroup> : NodeVersionedInterface<ParentGroup> {
|
||||||
|
|
||||||
@@ -31,12 +30,4 @@ interface EntryVersionedInterface<ParentGroup> : NodeVersionedInterface<ParentGr
|
|||||||
var url: String
|
var url: String
|
||||||
|
|
||||||
var notes: String
|
var notes: String
|
||||||
|
|
||||||
fun getAttachments(): ArrayList<Attachment>
|
|
||||||
|
|
||||||
fun containsAttachment(attachment: Attachment): Boolean
|
|
||||||
|
|
||||||
fun putAttachment(attachment: Attachment)
|
|
||||||
|
|
||||||
fun removeAttachment(attachment: Attachment)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ import java.util.zip.GZIPOutputStream
|
|||||||
|
|
||||||
class BinaryAttachment : Parcelable {
|
class BinaryAttachment : Parcelable {
|
||||||
|
|
||||||
var isCompressed: Boolean? = null
|
var isCompressed: Boolean = false
|
||||||
private set
|
private set
|
||||||
var isProtected: Boolean = false
|
var isProtected: Boolean = false
|
||||||
private set
|
private set
|
||||||
@@ -44,20 +44,19 @@ class BinaryAttachment : Parcelable {
|
|||||||
* Empty protected binary
|
* Empty protected binary
|
||||||
*/
|
*/
|
||||||
constructor() {
|
constructor() {
|
||||||
this.isCompressed = null
|
this.isCompressed = false
|
||||||
this.isProtected = false
|
this.isProtected = false
|
||||||
this.dataFile = null
|
this.dataFile = null
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(dataFile: File, enableProtection: Boolean = false, compressed: Boolean? = null) {
|
constructor(dataFile: File, enableProtection: Boolean = false, compressed: Boolean = false) {
|
||||||
this.isCompressed = compressed
|
this.isCompressed = compressed
|
||||||
this.isProtected = enableProtection
|
this.isProtected = enableProtection
|
||||||
this.dataFile = dataFile
|
this.dataFile = dataFile
|
||||||
}
|
}
|
||||||
|
|
||||||
private constructor(parcel: Parcel) {
|
private constructor(parcel: Parcel) {
|
||||||
val compressedByte = parcel.readByte().toInt()
|
isCompressed = parcel.readByte().toInt() != 0
|
||||||
isCompressed = if (compressedByte == 2) null else compressedByte != 0
|
|
||||||
isProtected = parcel.readByte().toInt() != 0
|
isProtected = parcel.readByte().toInt() != 0
|
||||||
parcel.readString()?.let {
|
parcel.readString()?.let {
|
||||||
dataFile = File(it)
|
dataFile = File(it)
|
||||||
@@ -84,7 +83,7 @@ class BinaryAttachment : Parcelable {
|
|||||||
fun compress(bufferSize: Int = DEFAULT_BUFFER_SIZE) {
|
fun compress(bufferSize: Int = DEFAULT_BUFFER_SIZE) {
|
||||||
dataFile?.let { concreteDataFile ->
|
dataFile?.let { concreteDataFile ->
|
||||||
// To compress, create a new binary with file
|
// To compress, create a new binary with file
|
||||||
if (isCompressed != true) {
|
if (!isCompressed) {
|
||||||
val fileBinaryCompress = File(concreteDataFile.parent, concreteDataFile.name + "_temp")
|
val fileBinaryCompress = File(concreteDataFile.parent, concreteDataFile.name + "_temp")
|
||||||
GZIPOutputStream(FileOutputStream(fileBinaryCompress)).use { outputStream ->
|
GZIPOutputStream(FileOutputStream(fileBinaryCompress)).use { outputStream ->
|
||||||
getInputDataStream().use { inputStream ->
|
getInputDataStream().use { inputStream ->
|
||||||
@@ -100,8 +99,6 @@ class BinaryAttachment : Parcelable {
|
|||||||
isCompressed = true
|
isCompressed = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
isCompressed = true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -109,7 +106,7 @@ class BinaryAttachment : Parcelable {
|
|||||||
@Throws(IOException::class)
|
@Throws(IOException::class)
|
||||||
fun decompress(bufferSize: Int = DEFAULT_BUFFER_SIZE) {
|
fun decompress(bufferSize: Int = DEFAULT_BUFFER_SIZE) {
|
||||||
dataFile?.let { concreteDataFile ->
|
dataFile?.let { concreteDataFile ->
|
||||||
if (isCompressed != false) {
|
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 ->
|
GZIPInputStream(getInputDataStream()).use { inputStream ->
|
||||||
@@ -125,8 +122,6 @@ class BinaryAttachment : Parcelable {
|
|||||||
isCompressed = false
|
isCompressed = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
isCompressed = false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -157,7 +152,7 @@ class BinaryAttachment : Parcelable {
|
|||||||
override fun hashCode(): Int {
|
override fun hashCode(): Int {
|
||||||
|
|
||||||
var result = 0
|
var result = 0
|
||||||
result = 31 * result + if (isCompressed == null) 2 else if (isCompressed!!) 1 else 0
|
result = 31 * result + if (isCompressed) 1 else 0
|
||||||
result = 31 * result + if (isProtected) 1 else 0
|
result = 31 * result + if (isProtected) 1 else 0
|
||||||
result = 31 * result + dataFile!!.hashCode()
|
result = 31 * result + dataFile!!.hashCode()
|
||||||
return result
|
return result
|
||||||
@@ -172,7 +167,7 @@ class BinaryAttachment : Parcelable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun writeToParcel(dest: Parcel, flags: Int) {
|
override fun writeToParcel(dest: Parcel, flags: Int) {
|
||||||
dest.writeByte((if (isCompressed == null) 2 else 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.writeString(dataFile?.absolutePath)
|
dest.writeString(dataFile?.absolutePath)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -757,8 +757,9 @@ class DatabaseInputKDBX(cacheDirectory: File,
|
|||||||
|
|
||||||
return KdbContext.Entry
|
return KdbContext.Entry
|
||||||
} else if (ctx == KdbContext.EntryBinary && name.equals(DatabaseKDBXXML.ElemBinary, ignoreCase = true)) {
|
} else if (ctx == KdbContext.EntryBinary && name.equals(DatabaseKDBXXML.ElemBinary, ignoreCase = true)) {
|
||||||
if (ctxBinaryName != null && ctxBinaryValue != null)
|
if (ctxBinaryName != null && ctxBinaryValue != null) {
|
||||||
ctxEntry?.putAttachment(Attachment(ctxBinaryName!!, ctxBinaryValue!!))
|
ctxEntry?.putAttachment(Attachment(ctxBinaryName!!, ctxBinaryValue!!), mDatabase.binaryPool)
|
||||||
|
}
|
||||||
ctxBinaryName = null
|
ctxBinaryName = null
|
||||||
ctxBinaryValue = null
|
ctxBinaryValue = null
|
||||||
|
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ class DatabaseInnerHeaderOutputKDBX(private val database: DatabaseKDBX,
|
|||||||
dataOutputStream.writeInt(streamKeySize)
|
dataOutputStream.writeInt(streamKeySize)
|
||||||
dataOutputStream.write(header.innerRandomStreamKey)
|
dataOutputStream.write(header.innerRandomStreamKey)
|
||||||
|
|
||||||
database.binaryPool.doForEachBinary { _, protectedBinary ->
|
database.binaryPool.doForEachBinary { protectedBinary ->
|
||||||
var flag = DatabaseHeaderKDBX.KdbxBinaryFlags.None
|
var flag = DatabaseHeaderKDBX.KdbxBinaryFlags.None
|
||||||
if (protectedBinary.isProtected) {
|
if (protectedBinary.isProtected) {
|
||||||
flag = flag or DatabaseHeaderKDBX.KdbxBinaryFlags.Protected
|
flag = flag or DatabaseHeaderKDBX.KdbxBinaryFlags.Protected
|
||||||
|
|||||||
@@ -46,7 +46,6 @@ import com.kunzisoft.keepass.database.exception.UnknownKDF
|
|||||||
import com.kunzisoft.keepass.database.file.DatabaseHeaderKDBX
|
import com.kunzisoft.keepass.database.file.DatabaseHeaderKDBX
|
||||||
import com.kunzisoft.keepass.database.file.DatabaseKDBXXML
|
import com.kunzisoft.keepass.database.file.DatabaseKDBXXML
|
||||||
import com.kunzisoft.keepass.database.file.DateKDBXUtil
|
import com.kunzisoft.keepass.database.file.DateKDBXUtil
|
||||||
import com.kunzisoft.keepass.database.element.Attachment
|
|
||||||
import com.kunzisoft.keepass.stream.*
|
import com.kunzisoft.keepass.stream.*
|
||||||
import org.bouncycastle.crypto.StreamCipher
|
import org.bouncycastle.crypto.StreamCipher
|
||||||
import org.joda.time.DateTime
|
import org.joda.time.DateTime
|
||||||
@@ -360,7 +359,7 @@ class DatabaseOutputKDBX(private val mDatabaseKDBX: DatabaseKDBX,
|
|||||||
writeTimes(entry)
|
writeTimes(entry)
|
||||||
|
|
||||||
writeFields(entry.fields)
|
writeFields(entry.fields)
|
||||||
writeEntryBinaries(entry.getAttachments())
|
writeEntryBinaries(entry.binaries)
|
||||||
writeAutoType(entry.autoType)
|
writeAutoType(entry.autoType)
|
||||||
|
|
||||||
if (!isHistory) {
|
if (!isHistory) {
|
||||||
@@ -441,7 +440,7 @@ class DatabaseOutputKDBX(private val mDatabaseKDBX: DatabaseKDBX,
|
|||||||
|
|
||||||
// Force decompression in this specific case
|
// Force decompression in this specific case
|
||||||
val binaryInputStream = if (mDatabaseKDBX.compressionAlgorithm == CompressionAlgorithm.None
|
val binaryInputStream = if (mDatabaseKDBX.compressionAlgorithm == CompressionAlgorithm.None
|
||||||
&& binary.isCompressed == true) {
|
&& binary.isCompressed) {
|
||||||
GZIPInputStream(binary.getInputDataStream())
|
GZIPInputStream(binary.getInputDataStream())
|
||||||
} else {
|
} else {
|
||||||
binary.getInputDataStream()
|
binary.getInputDataStream()
|
||||||
@@ -460,7 +459,7 @@ class DatabaseOutputKDBX(private val mDatabaseKDBX: DatabaseKDBX,
|
|||||||
private fun writeMetaBinaries() {
|
private fun writeMetaBinaries() {
|
||||||
xml.startTag(null, DatabaseKDBXXML.ElemBinaries)
|
xml.startTag(null, DatabaseKDBXXML.ElemBinaries)
|
||||||
|
|
||||||
mDatabaseKDBX.binaryPool.doForEachBinary { key, binary ->
|
mDatabaseKDBX.binaryPool.doForEach { key, binary ->
|
||||||
xml.startTag(null, DatabaseKDBXXML.ElemBinary)
|
xml.startTag(null, DatabaseKDBXXML.ElemBinary)
|
||||||
xml.attribute(null, DatabaseKDBXXML.AttrId, key.toString())
|
xml.attribute(null, DatabaseKDBXXML.AttrId, key.toString())
|
||||||
writeBinary(binary)
|
writeBinary(binary)
|
||||||
@@ -560,20 +559,24 @@ class DatabaseOutputKDBX(private val mDatabaseKDBX: DatabaseKDBX,
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Throws(IllegalArgumentException::class, IllegalStateException::class, IOException::class)
|
@Throws(IllegalArgumentException::class, IllegalStateException::class, IOException::class)
|
||||||
private fun writeEntryBinaries(attachments: List<Attachment>) {
|
private fun writeEntryBinaries(binaries: LinkedHashMap<String, Int>) {
|
||||||
attachments.forEach {
|
binaries.forEach {
|
||||||
xml.startTag(null, DatabaseKDBXXML.ElemBinary)
|
xml.startTag(null, DatabaseKDBXXML.ElemBinary)
|
||||||
xml.startTag(null, DatabaseKDBXXML.ElemKey)
|
xml.startTag(null, DatabaseKDBXXML.ElemKey)
|
||||||
xml.text(safeXmlString(it.name))
|
xml.text(safeXmlString(it.key))
|
||||||
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())
|
||||||
|
/*
|
||||||
|
// By default use only pool data in head to save binaries
|
||||||
val ref = mDatabaseKDBX.binaryPool.findKey(it.binaryAttachment)
|
val ref = mDatabaseKDBX.binaryPool.findKey(it.binaryAttachment)
|
||||||
if (ref != null) {
|
if (ref != null) {
|
||||||
xml.attribute(null, DatabaseKDBXXML.AttrRef, ref.toString())
|
xml.attribute(null, DatabaseKDBXXML.AttrRef, ref.toString())
|
||||||
} else {
|
} else {
|
||||||
writeBinary(it.binaryAttachment)
|
writeBinary(it.binaryAttachment)
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
xml.endTag(null, DatabaseKDBXXML.ElemValue)
|
xml.endTag(null, DatabaseKDBXXML.ElemValue)
|
||||||
|
|
||||||
xml.endTag(null, DatabaseKDBXXML.ElemBinary)
|
xml.endTag(null, DatabaseKDBXXML.ElemBinary)
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ import java.util.zip.GZIPOutputStream
|
|||||||
class AttachmentFileNotificationService: LockNotificationService() {
|
class AttachmentFileNotificationService: LockNotificationService() {
|
||||||
|
|
||||||
override val notificationId: Int = 10000
|
override val notificationId: Int = 10000
|
||||||
private val attachmentNotificationList = ArrayList<AttachmentNotification>()
|
private val attachmentNotificationList = CopyOnWriteArrayList<AttachmentNotification>()
|
||||||
|
|
||||||
private var mActionTaskBinder = ActionTaskBinder()
|
private var mActionTaskBinder = ActionTaskBinder()
|
||||||
private var mActionTaskListeners = LinkedList<ActionTaskListener>()
|
private var mActionTaskListeners = LinkedList<ActionTaskListener>()
|
||||||
|
|||||||
@@ -60,6 +60,15 @@ object ParcelableUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For writing map with string key and Int value to a Parcel
|
||||||
|
fun writeStringIntMap(parcel: Parcel, map: LinkedHashMap<String, Int>) {
|
||||||
|
parcel.writeInt(map.size)
|
||||||
|
for ((key, value) in map) {
|
||||||
|
parcel.writeString(key)
|
||||||
|
parcel.writeInt(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// For reading map with string key from a Parcel
|
// For reading map with string key from a Parcel
|
||||||
fun <V : Parcelable> readStringParcelableMap(
|
fun <V : Parcelable> readStringParcelableMap(
|
||||||
parcel: Parcel, vClass: Class<V>): LinkedHashMap<String, V> {
|
parcel: Parcel, vClass: Class<V>): LinkedHashMap<String, V> {
|
||||||
@@ -74,6 +83,19 @@ object ParcelableUtil {
|
|||||||
return map
|
return map
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For reading map with string key and Int value from a Parcel
|
||||||
|
fun readStringIntMap(parcel: Parcel): LinkedHashMap<String, Int> {
|
||||||
|
val size = parcel.readInt()
|
||||||
|
val map = LinkedHashMap<String, Int>(size)
|
||||||
|
for (i in 0 until size) {
|
||||||
|
val key: String? = parcel.readString()
|
||||||
|
val value: Int? = parcel.readInt()
|
||||||
|
if (key != null && value != null)
|
||||||
|
map[key] = value
|
||||||
|
}
|
||||||
|
return map
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// For writing map with string key and string value to a Parcel
|
// For writing map with string key and string value to a Parcel
|
||||||
fun writeStringParcelableMap(dest: Parcel, map: LinkedHashMap<String, String>) {
|
fun writeStringParcelableMap(dest: Parcel, map: LinkedHashMap<String, String>) {
|
||||||
|
|||||||
Reference in New Issue
Block a user