Herbert Poul
5 years ago
9 changed files with 145 additions and 31 deletions
@ -0,0 +1,35 @@ |
|||||||
|
import 'package:kdbx/src/kdbx_xml.dart'; |
||||||
|
import 'package:xml/xml.dart' as xml; |
||||||
|
|
||||||
|
extension XmlElementExt on xml.XmlElement { |
||||||
|
xml.XmlElement singleElement(String nodeName, |
||||||
|
{xml.XmlElement Function() orElse}) { |
||||||
|
final elements = findElements(nodeName); |
||||||
|
if (elements.isEmpty) { |
||||||
|
if (orElse != null) { |
||||||
|
final ret = orElse(); |
||||||
|
children.add(ret); |
||||||
|
return ret; |
||||||
|
} else { |
||||||
|
return null; |
||||||
|
} |
||||||
|
} |
||||||
|
return elements.single; |
||||||
|
} |
||||||
|
|
||||||
|
String singleTextNode(String nodeName) { |
||||||
|
return findElements(nodeName).single.text; |
||||||
|
} |
||||||
|
|
||||||
|
/// If an element child with the given name already exists, |
||||||
|
/// it will be removed and the given element will be added. |
||||||
|
/// otherwise it will be only added. |
||||||
|
void replaceSingle(xml.XmlElement element) { |
||||||
|
XmlUtils.removeChildrenByName(this, element.name.local); |
||||||
|
children.add(element); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
extension ObjectExt<T> on T { |
||||||
|
R let<R>(R Function(T that) op) => op(this); |
||||||
|
} |
@ -0,0 +1,37 @@ |
|||||||
|
import 'package:kdbx/src/kdbx_object.dart'; |
||||||
|
import 'package:kdbx/src/kdbx_xml.dart'; |
||||||
|
import 'package:xml/xml.dart' as xml; |
||||||
|
import 'package:kdbx/src/internal/extension_utils.dart'; |
||||||
|
|
||||||
|
class KdbxCustomData extends KdbxNode { |
||||||
|
KdbxCustomData.create() |
||||||
|
: data = {}, |
||||||
|
super.create(TAG_NAME); |
||||||
|
|
||||||
|
KdbxCustomData.read(xml.XmlElement node) |
||||||
|
: data = Map.fromEntries( |
||||||
|
node.findElements(KdbxXml.NODE_CUSTOM_DATA_ITEM).map((el) { |
||||||
|
final key = el.singleTextNode(KdbxXml.NODE_KEY); |
||||||
|
final value = el.singleTextNode(KdbxXml.NODE_VALUE); |
||||||
|
return MapEntry(key, value); |
||||||
|
})), |
||||||
|
super.read(node); |
||||||
|
|
||||||
|
static const String TAG_NAME = 'CustomData'; |
||||||
|
|
||||||
|
final Map<String, String> data; |
||||||
|
|
||||||
|
@override |
||||||
|
xml.XmlElement toXml() { |
||||||
|
final el = super.toXml(); |
||||||
|
el.children.clear(); |
||||||
|
el.children.addAll( |
||||||
|
data.entries |
||||||
|
.map((e) => XmlUtils.createNode(KdbxXml.NODE_CUSTOM_DATA_ITEM, [ |
||||||
|
XmlUtils.createTextNode(KdbxXml.NODE_KEY, e.key), |
||||||
|
XmlUtils.createTextNode(KdbxXml.NODE_VALUE, e.value), |
||||||
|
])), |
||||||
|
); |
||||||
|
return el; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,42 @@ |
|||||||
|
import 'package:kdbx/src/internal/extension_utils.dart'; |
||||||
|
import 'package:kdbx/src/kdbx_custom_data.dart'; |
||||||
|
import 'package:kdbx/src/kdbx_object.dart'; |
||||||
|
import 'package:kdbx/src/kdbx_xml.dart'; |
||||||
|
import 'package:meta/meta.dart'; |
||||||
|
import 'package:xml/xml.dart' as xml; |
||||||
|
|
||||||
|
class KdbxMeta extends KdbxNode { |
||||||
|
KdbxMeta.create({ |
||||||
|
@required String databaseName, |
||||||
|
String generator = 'kdbx.dart', |
||||||
|
}) : customData = KdbxCustomData.create(), |
||||||
|
super.create('Meta') { |
||||||
|
this.databaseName.set(databaseName); |
||||||
|
this.generator.set(generator); |
||||||
|
} |
||||||
|
|
||||||
|
KdbxMeta.read(xml.XmlElement node) |
||||||
|
: customData = node |
||||||
|
.singleElement('CustomData') |
||||||
|
?.let((e) => KdbxCustomData.read(e)) ?? |
||||||
|
KdbxCustomData.create(), |
||||||
|
super.read(node); |
||||||
|
|
||||||
|
final KdbxCustomData customData; |
||||||
|
|
||||||
|
StringNode get generator => StringNode(this, 'Generator'); |
||||||
|
|
||||||
|
StringNode get databaseName => StringNode(this, 'DatabaseName'); |
||||||
|
|
||||||
|
Base64Node get headerHash => Base64Node(this, 'HeaderHash'); |
||||||
|
|
||||||
|
BooleanNode get recycleBinEnabled => BooleanNode(this, 'RecycleBinEnabled'); |
||||||
|
|
||||||
|
UuidNode get recycleBinUUID => UuidNode(this, 'RecycleBinUUID'); |
||||||
|
|
||||||
|
DateTimeUtcNode get recycleBinChanged => |
||||||
|
DateTimeUtcNode(this, 'RecycleBinChanged'); |
||||||
|
|
||||||
|
@override |
||||||
|
xml.XmlElement toXml() => super.toXml()..replaceSingle(customData.toXml()); |
||||||
|
} |
Loading…
Reference in new issue