private KdbContext EndXmlElement(KdbContext ctx, XmlPullParser xpp) throws XmlPullParserException { assert (xpp.getEventType() == XmlPullParser.END_TAG); String name = xpp.getName(); if (ctx == KdbContext.KeePassFile && name.equalsIgnoreCase(ElemDocNode)) { return KdbContext.Null; } else if (ctx == KdbContext.Meta && name.equalsIgnoreCase(ElemMeta)) { return KdbContext.KeePassFile; } else if (ctx == KdbContext.Root && name.equalsIgnoreCase(ElemRoot)) { return KdbContext.KeePassFile; } else if (ctx == KdbContext.MemoryProtection && name.equalsIgnoreCase(ElemMemoryProt)) { return KdbContext.Meta; } else if (ctx == KdbContext.CustomIcons && name.equalsIgnoreCase(ElemCustomIcons)) { return KdbContext.Meta; } else if (ctx == KdbContext.CustomIcon && name.equalsIgnoreCase(ElemCustomIconItem)) { if (!customIconID.equals(PwDatabaseV4.UUID_ZERO)) { PwIconCustom icon = new PwIconCustom(customIconID, customIconData); db.customIcons.add(icon); db.iconFactory.put(icon); } else assert (false); customIconID = PwDatabaseV4.UUID_ZERO; customIconData = null; return KdbContext.CustomIcons; } else if (ctx == KdbContext.Binaries && name.equalsIgnoreCase(ElemBinaries)) { return KdbContext.Meta; } else if (ctx == KdbContext.CustomData && name.equalsIgnoreCase(ElemCustomData)) { return KdbContext.Meta; } else if (ctx == KdbContext.CustomDataItem && name.equalsIgnoreCase(ElemStringDictExItem)) { if (customDataKey != null && customDataValue != null) { db.customData.put(customDataKey, customDataValue); } else assert (false); customDataKey = null; customDataValue = null; return KdbContext.CustomData; } else if (ctx == KdbContext.Group && name.equalsIgnoreCase(ElemGroup)) { if (ctxGroup.uuid == null || ctxGroup.uuid.equals(PwDatabaseV4.UUID_ZERO)) { ctxGroup.uuid = UUID.randomUUID(); } ctxGroups.pop(); if (ctxGroups.size() == 0) { ctxGroup = null; return KdbContext.Root; } else { ctxGroup = ctxGroups.peek(); return KdbContext.Group; } } else if (ctx == KdbContext.GroupTimes && name.equalsIgnoreCase(ElemTimes)) { return KdbContext.Group; } else if (ctx == KdbContext.Entry && name.equalsIgnoreCase(ElemEntry)) { if (ctxEntry.uuid == null || ctxEntry.uuid.equals(PwDatabaseV4.UUID_ZERO)) { ctxEntry.uuid = UUID.randomUUID(); } if (entryInHistory) { ctxEntry = ctxHistoryBase; return KdbContext.EntryHistory; } return KdbContext.Group; } else if (ctx == KdbContext.EntryTimes && name.equalsIgnoreCase(ElemTimes)) { return KdbContext.Entry; } else if (ctx == KdbContext.EntryString && name.equalsIgnoreCase(ElemString)) { ctxEntry.strings.put(ctxStringName, ctxStringValue); ctxStringName = null; ctxStringValue = null; return KdbContext.Entry; } else if (ctx == KdbContext.EntryBinary && name.equalsIgnoreCase(ElemBinary)) { ctxEntry.binaries.put(ctxBinaryName, ctxBinaryValue); ctxBinaryName = null; ctxBinaryValue = null; return KdbContext.Entry; } else if (ctx == KdbContext.EntryAutoType && name.equalsIgnoreCase(ElemAutoType)) { return KdbContext.Entry; } else if (ctx == KdbContext.EntryAutoTypeItem && name.equalsIgnoreCase(ElemAutoTypeItem)) { ctxEntry.autoType.put(ctxATName, ctxATSeq); ctxATName = null; ctxATSeq = null; return KdbContext.EntryAutoType; } else if (ctx == KdbContext.EntryHistory && name.equalsIgnoreCase(ElemHistory)) { entryInHistory = false; return KdbContext.Entry; } else if (ctx == KdbContext.RootDeletedObjects && name.equalsIgnoreCase(ElemDeletedObjects)) { return KdbContext.Root; } else if (ctx == KdbContext.DeletedObject && name.equalsIgnoreCase(ElemDeletedObject)) { ctxDeletedObject = null; return KdbContext.RootDeletedObjects; } else { assert (false); throw new RuntimeException("Invalid end element"); } }
private KdbContext ReadXmlElement(KdbContext ctx, XmlPullParser xpp) throws XmlPullParserException, IOException, InvalidDBException { String name = xpp.getName(); switch (ctx) { case Null: if (name.equalsIgnoreCase(ElemDocNode)) { return SwitchContext(ctx, KdbContext.KeePassFile, xpp); } else ReadUnknown(xpp); break; case KeePassFile: if (name.equalsIgnoreCase(ElemMeta)) { return SwitchContext(ctx, KdbContext.Meta, xpp); } else if (name.equalsIgnoreCase(ElemRoot)) { return SwitchContext(ctx, KdbContext.Root, xpp); } else { ReadUnknown(xpp); } break; case Meta: if (name.equalsIgnoreCase(ElemGenerator)) { ReadString(xpp); // Ignore } else if (name.equalsIgnoreCase(ElemHeaderHash)) { String encodedHash = ReadString(xpp); if (!EmptyUtils.isNullOrEmpty(encodedHash) && (hashOfHeader != null)) { byte[] hash = Base64Coder.decode(encodedHash); if (!Arrays.equals(hash, hashOfHeader)) { throw new InvalidDBException(); } } } else if (name.equalsIgnoreCase(ElemDbName)) { db.name = ReadString(xpp); } else if (name.equalsIgnoreCase(ElemDbNameChanged)) { db.nameChanged = ReadTime(xpp); } else if (name.equalsIgnoreCase(ElemDbDesc)) { db.description = ReadString(xpp); } else if (name.equalsIgnoreCase(ElemDbDescChanged)) { db.descriptionChanged = ReadTime(xpp); } else if (name.equalsIgnoreCase(ElemDbDefaultUser)) { db.defaultUserName = ReadString(xpp); } else if (name.equalsIgnoreCase(ElemDbDefaultUserChanged)) { db.defaultUserNameChanged = ReadTime(xpp); } else if (name.equalsIgnoreCase(ElemDbColor)) { // TODO: Add support to interpret the color if we want to allow changing the database // color db.color = ReadString(xpp); } else if (name.equalsIgnoreCase(ElemDbMntncHistoryDays)) { db.maintenanceHistoryDays = ReadUInt(xpp, DEFAULT_HISTORY_DAYS); } else if (name.equalsIgnoreCase(ElemDbKeyChanged)) { db.keyLastChanged = ReadTime(xpp); } else if (name.equalsIgnoreCase(ElemDbKeyChangeRec)) { db.keyChangeRecDays = ReadLong(xpp, -1); } else if (name.equalsIgnoreCase(ElemDbKeyChangeForce)) { db.keyChangeForceDays = ReadLong(xpp, -1); } else if (name.equalsIgnoreCase(ElemMemoryProt)) { return SwitchContext(ctx, KdbContext.MemoryProtection, xpp); } else if (name.equalsIgnoreCase(ElemCustomIcons)) { return SwitchContext(ctx, KdbContext.CustomIcons, xpp); } else if (name.equalsIgnoreCase(ElemRecycleBinEnabled)) { db.recycleBinEnabled = ReadBool(xpp, true); } else if (name.equalsIgnoreCase(ElemRecycleBinUuid)) { db.recycleBinUUID = ReadUuid(xpp); } else if (name.equalsIgnoreCase(ElemRecycleBinChanged)) { db.recycleBinChanged = ReadTime(xpp); } else if (name.equalsIgnoreCase(ElemEntryTemplatesGroup)) { db.entryTemplatesGroup = ReadUuid(xpp); } else if (name.equalsIgnoreCase(ElemEntryTemplatesGroupChanged)) { db.entryTemplatesGroupChanged = ReadTime(xpp); } else if (name.equalsIgnoreCase(ElemHistoryMaxItems)) { db.historyMaxItems = ReadInt(xpp, -1); } else if (name.equalsIgnoreCase(ElemHistoryMaxSize)) { db.historyMaxSize = ReadLong(xpp, -1); } else if (name.equalsIgnoreCase(ElemEntryTemplatesGroupChanged)) { db.entryTemplatesGroupChanged = ReadTime(xpp); } else if (name.equalsIgnoreCase(ElemLastSelectedGroup)) { db.lastSelectedGroup = ReadUuid(xpp); } else if (name.equalsIgnoreCase(ElemLastTopVisibleGroup)) { db.lastTopVisibleGroup = ReadUuid(xpp); } else if (name.equalsIgnoreCase(ElemBinaries)) { return SwitchContext(ctx, KdbContext.Binaries, xpp); } else if (name.equalsIgnoreCase(ElemCustomData)) { return SwitchContext(ctx, KdbContext.CustomData, xpp); } break; case MemoryProtection: if (name.equalsIgnoreCase(ElemProtTitle)) { db.memoryProtection.protectTitle = ReadBool(xpp, false); } else if (name.equalsIgnoreCase(ElemProtUserName)) { db.memoryProtection.protectUserName = ReadBool(xpp, false); } else if (name.equalsIgnoreCase(ElemProtPassword)) { db.memoryProtection.protectPassword = ReadBool(xpp, false); } else if (name.equalsIgnoreCase(ElemProtURL)) { db.memoryProtection.protectUrl = ReadBool(xpp, false); } else if (name.equalsIgnoreCase(ElemProtNotes)) { db.memoryProtection.protectNotes = ReadBool(xpp, false); } else if (name.equalsIgnoreCase(ElemProtAutoHide)) { db.memoryProtection.autoEnableVisualHiding = ReadBool(xpp, false); } else { ReadUnknown(xpp); } break; case CustomIcons: if (name.equalsIgnoreCase(ElemCustomIconItem)) { return SwitchContext(ctx, KdbContext.CustomIcon, xpp); } else { ReadUnknown(xpp); } break; case CustomIcon: if (name.equalsIgnoreCase(ElemCustomIconItemID)) { customIconID = ReadUuid(xpp); } else if (name.equalsIgnoreCase(ElemCustomIconItemData)) { String strData = ReadString(xpp); if (strData != null && strData.length() > 0) { customIconData = Base64Coder.decode(strData); } else { assert (false); } } else { ReadUnknown(xpp); } break; case Binaries: if (name.equalsIgnoreCase(ElemBinary)) { String key = xpp.getAttributeValue(null, AttrId); if (key != null) { ProtectedBinary pbData = ReadProtectedBinary(xpp); binPool.put(key, pbData); } else { ReadUnknown(xpp); } } else { ReadUnknown(xpp); } break; case CustomData: if (name.equalsIgnoreCase(ElemStringDictExItem)) { return SwitchContext(ctx, KdbContext.CustomDataItem, xpp); } else { ReadUnknown(xpp); } break; case CustomDataItem: if (name.equalsIgnoreCase(ElemKey)) { customDataKey = ReadString(xpp); } else if (name.equalsIgnoreCase(ElemValue)) { customDataValue = ReadString(xpp); } else { ReadUnknown(xpp); } break; case Root: if (name.equalsIgnoreCase(ElemGroup)) { assert (ctxGroups.size() == 0); if (ctxGroups.size() != 0) throw new IOException("Group list should be empty."); db.rootGroup = new PwGroupV4(); ctxGroups.push((PwGroupV4) db.rootGroup); ctxGroup = ctxGroups.peek(); return SwitchContext(ctx, KdbContext.Group, xpp); } else if (name.equalsIgnoreCase(ElemDeletedObjects)) { return SwitchContext(ctx, KdbContext.RootDeletedObjects, xpp); } else { ReadUnknown(xpp); } break; case Group: if (name.equalsIgnoreCase(ElemUuid)) { ctxGroup.uuid = ReadUuid(xpp); } else if (name.equalsIgnoreCase(ElemName)) { ctxGroup.name = ReadString(xpp); } else if (name.equalsIgnoreCase(ElemNotes)) { ctxGroup.notes = ReadString(xpp); } else if (name.equalsIgnoreCase(ElemIcon)) { ctxGroup.icon = db.iconFactory.getIcon((int) ReadUInt(xpp, 0)); } else if (name.equalsIgnoreCase(ElemCustomIconID)) { ctxGroup.customIcon = db.iconFactory.getIcon(ReadUuid(xpp)); } else if (name.equalsIgnoreCase(ElemTimes)) { return SwitchContext(ctx, KdbContext.GroupTimes, xpp); } else if (name.equalsIgnoreCase(ElemIsExpanded)) { ctxGroup.isExpanded = ReadBool(xpp, true); } else if (name.equalsIgnoreCase(ElemGroupDefaultAutoTypeSeq)) { ctxGroup.defaultAutoTypeSequence = ReadString(xpp); } else if (name.equalsIgnoreCase(ElemEnableAutoType)) { ctxGroup.enableAutoType = StringToBoolean(ReadString(xpp)); } else if (name.equalsIgnoreCase(ElemEnableSearching)) { ctxGroup.enableSearching = StringToBoolean(ReadString(xpp)); } else if (name.equalsIgnoreCase(ElemLastTopVisibleEntry)) { ctxGroup.lastTopVisibleEntry = ReadUuid(xpp); } else if (name.equalsIgnoreCase(ElemGroup)) { ctxGroup = new PwGroupV4(); ctxGroups.peek().AddGroup(ctxGroup, true); ctxGroups.push(ctxGroup); return SwitchContext(ctx, KdbContext.Group, xpp); } else if (name.equalsIgnoreCase(ElemEntry)) { ctxEntry = new PwEntryV4(); ctxGroup.AddEntry(ctxEntry, true); entryInHistory = false; return SwitchContext(ctx, KdbContext.Entry, xpp); } else { ReadUnknown(xpp); } break; case Entry: if (name.equalsIgnoreCase(ElemUuid)) { ctxEntry.setUUID(ReadUuid(xpp)); } else if (name.equalsIgnoreCase(ElemIcon)) { ctxEntry.icon = db.iconFactory.getIcon((int) ReadUInt(xpp, 0)); } else if (name.equalsIgnoreCase(ElemCustomIconID)) { ctxEntry.customIcon = db.iconFactory.getIcon(ReadUuid(xpp)); } else if (name.equalsIgnoreCase(ElemFgColor)) { ctxEntry.foregroundColor = ReadString(xpp); } else if (name.equalsIgnoreCase(ElemBgColor)) { ctxEntry.backgroupColor = ReadString(xpp); } else if (name.equalsIgnoreCase(ElemOverrideUrl)) { ctxEntry.overrideURL = ReadString(xpp); } else if (name.equalsIgnoreCase(ElemTags)) { ctxEntry.tags = ReadString(xpp); } else if (name.equalsIgnoreCase(ElemTimes)) { return SwitchContext(ctx, KdbContext.EntryTimes, xpp); } else if (name.equalsIgnoreCase(ElemString)) { return SwitchContext(ctx, KdbContext.EntryString, xpp); } else if (name.equalsIgnoreCase(ElemBinary)) { return SwitchContext(ctx, KdbContext.EntryBinary, xpp); } else if (name.equalsIgnoreCase(ElemAutoType)) { return SwitchContext(ctx, KdbContext.EntryAutoType, xpp); } else if (name.equalsIgnoreCase(ElemHistory)) { assert (!entryInHistory); if (!entryInHistory) { ctxHistoryBase = ctxEntry; return SwitchContext(ctx, KdbContext.EntryHistory, xpp); } else { ReadUnknown(xpp); } } else { ReadUnknown(xpp); } break; case GroupTimes: case EntryTimes: ITimeLogger tl; if (ctx == KdbContext.GroupTimes) { tl = ctxGroup; } else { tl = ctxEntry; } if (name.equalsIgnoreCase(ElemLastModTime)) { tl.setLastModificationTime(ReadTime(xpp)); } else if (name.equalsIgnoreCase(ElemCreationTime)) { tl.setCreationTime(ReadTime(xpp)); } else if (name.equalsIgnoreCase(ElemLastAccessTime)) { tl.setLastAccessTime(ReadTime(xpp)); } else if (name.equalsIgnoreCase(ElemExpiryTime)) { tl.setExpiryTime(ReadTime(xpp)); } else if (name.equalsIgnoreCase(ElemExpires)) { tl.setExpires(ReadBool(xpp, false)); } else if (name.equalsIgnoreCase(ElemUsageCount)) { tl.setUsageCount(ReadULong(xpp, 0)); } else if (name.equalsIgnoreCase(ElemLocationChanged)) { tl.setLocationChanged(ReadTime(xpp)); } else { ReadUnknown(xpp); } break; case EntryString: if (name.equalsIgnoreCase(ElemKey)) { ctxStringName = ReadString(xpp); } else if (name.equalsIgnoreCase(ElemValue)) { ctxStringValue = ReadProtectedString(xpp); } else { ReadUnknown(xpp); } break; case EntryBinary: if (name.equalsIgnoreCase(ElemKey)) { ctxBinaryName = ReadString(xpp); } else if (name.equalsIgnoreCase(ElemValue)) { ctxBinaryValue = ReadProtectedBinary(xpp); } break; case EntryAutoType: if (name.equalsIgnoreCase(ElemAutoTypeEnabled)) { ctxEntry.autoType.enabled = ReadBool(xpp, true); } else if (name.equalsIgnoreCase(ElemAutoTypeObfuscation)) { ctxEntry.autoType.obfuscationOptions = ReadUInt(xpp, 0); } else if (name.equalsIgnoreCase(ElemAutoTypeDefaultSeq)) { ctxEntry.autoType.defaultSequence = ReadString(xpp); } else if (name.equalsIgnoreCase(ElemAutoTypeItem)) { return SwitchContext(ctx, KdbContext.EntryAutoTypeItem, xpp); } else { ReadUnknown(xpp); } break; case EntryAutoTypeItem: if (name.equalsIgnoreCase(ElemWindow)) { ctxATName = ReadString(xpp); } else if (name.equalsIgnoreCase(ElemKeystrokeSequence)) { ctxATSeq = ReadString(xpp); } else { ReadUnknown(xpp); } break; case EntryHistory: if (name.equalsIgnoreCase(ElemEntry)) { ctxEntry = new PwEntryV4(); ctxHistoryBase.history.add(ctxEntry); entryInHistory = true; return SwitchContext(ctx, KdbContext.Entry, xpp); } else { ReadUnknown(xpp); } break; case RootDeletedObjects: if (name.equalsIgnoreCase(ElemDeletedObject)) { ctxDeletedObject = new PwDeletedObject(); db.deletedObjects.add(ctxDeletedObject); return SwitchContext(ctx, KdbContext.DeletedObject, xpp); } else { ReadUnknown(xpp); } break; case DeletedObject: if (name.equalsIgnoreCase(ElemUuid)) { ctxDeletedObject.uuid = ReadUuid(xpp); } else if (name.equalsIgnoreCase(ElemDeletionTime)) { ctxDeletedObject.setDeletionTime(ReadTime(xpp)); } else { ReadUnknown(xpp); } break; default: ReadUnknown(xpp); break; } return ctx; }