internal void MergeInDbProperties(PwDatabase pwSource, PwMergeMethod mm) { if(pwSource == null) { Debug.Assert(false); return; } if((mm == PwMergeMethod.KeepExisting) || (mm == PwMergeMethod.None)) return; bool bForce = (mm == PwMergeMethod.OverwriteExisting); if(bForce || (pwSource.m_dtNameChanged > m_dtNameChanged)) { m_strName = pwSource.m_strName; m_dtNameChanged = pwSource.m_dtNameChanged; } if(bForce || (pwSource.m_dtDescChanged > m_dtDescChanged)) { m_strDesc = pwSource.m_strDesc; m_dtDescChanged = pwSource.m_dtDescChanged; } if(bForce || (pwSource.m_dtDefaultUserChanged > m_dtDefaultUserChanged)) { m_strDefaultUserName = pwSource.m_strDefaultUserName; m_dtDefaultUserChanged = pwSource.m_dtDefaultUserChanged; } PwUuid pwPrefBin = m_pwRecycleBin, pwAltBin = pwSource.m_pwRecycleBin; if(bForce || (pwSource.m_dtRecycleBinChanged > m_dtRecycleBinChanged)) { pwPrefBin = pwSource.m_pwRecycleBin; pwAltBin = m_pwRecycleBin; m_bUseRecycleBin = pwSource.m_bUseRecycleBin; m_dtRecycleBinChanged = pwSource.m_dtRecycleBinChanged; } if(m_pgRootGroup.FindGroup(pwPrefBin, true) != null) m_pwRecycleBin = pwPrefBin; else if(m_pgRootGroup.FindGroup(pwAltBin, true) != null) m_pwRecycleBin = pwAltBin; else m_pwRecycleBin = PwUuid.Zero; // Debug.Assert(false); PwUuid pwPrefTmp = m_pwEntryTemplatesGroup, pwAltTmp = pwSource.m_pwEntryTemplatesGroup; if(bForce || (pwSource.m_dtEntryTemplatesChanged > m_dtEntryTemplatesChanged)) { pwPrefTmp = pwSource.m_pwEntryTemplatesGroup; pwAltTmp = m_pwEntryTemplatesGroup; m_dtEntryTemplatesChanged = pwSource.m_dtEntryTemplatesChanged; } if(m_pgRootGroup.FindGroup(pwPrefTmp, true) != null) m_pwEntryTemplatesGroup = pwPrefTmp; else if(m_pgRootGroup.FindGroup(pwAltTmp, true) != null) m_pwEntryTemplatesGroup = pwAltTmp; else m_pwEntryTemplatesGroup = PwUuid.Zero; // Debug.Assert(false); }
private void OnBtnOK(object sender, EventArgs e) { if(m_radioCreateNew.Checked) m_mmSelected = PwMergeMethod.CreateNewUuids; else if(m_radioKeepExisting.Checked) m_mmSelected = PwMergeMethod.KeepExisting; else if(m_radioOverwrite.Checked) m_mmSelected = PwMergeMethod.OverwriteExisting; else if(m_radioOverwriteIfNewer.Checked) m_mmSelected = PwMergeMethod.OverwriteIfNewer; else if(m_radioSynchronize.Checked) m_mmSelected = PwMergeMethod.Synchronize; }
public static bool?Import(PwDatabase pd, FileFormatProvider fmtImp, IOConnectionInfo iocImp, PwMergeMethod mm, CompositeKey cmpKey) { if (pd == null) { Debug.Assert(false); return(false); } if (fmtImp == null) { Debug.Assert(false); return(false); } if (iocImp == null) { Debug.Assert(false); return(false); } if (cmpKey == null) { cmpKey = new CompositeKey(); } if (!AppPolicy.Try(AppPolicyId.Import)) { return(false); } if (!fmtImp.TryBeginImport()) { return(false); } PwDatabase pdImp = new PwDatabase(); pdImp.New(new IOConnectionInfo(), cmpKey); pdImp.MemoryProtection = pd.MemoryProtection.CloneDeep(); Stream s = IOConnection.OpenRead(iocImp); if (s == null) { throw new FileNotFoundException(iocImp.GetDisplayName() + MessageService.NewLine + KPRes.FileNotFoundError); } try { fmtImp.Import(pdImp, s, null); } finally { s.Close(); } pd.MergeIn(pdImp, mm); return(true); }
internal void MergeEntryHistory(PwEntry pe, PwEntry peSource, PwMergeMethod mm) { if(!pe.Uuid.EqualsValue(peSource.Uuid)) { Debug.Assert(false); return; } if(pe.History.UCount == peSource.History.UCount) { bool bEqual = true; for(uint uEnum = 0; uEnum < pe.History.UCount; ++uEnum) { if(pe.History.GetAt(uEnum).LastModificationTime != peSource.History.GetAt(uEnum).LastModificationTime) { bEqual = false; break; } } if(bEqual) return; } if((m_slStatus != null) && !m_slStatus.ContinueWork()) return; SortedList<DateTime, PwEntry> list = new SortedList<DateTime, PwEntry>(); foreach(PwEntry peOrg in pe.History) list[peOrg.LastModificationTime] = peOrg; foreach(PwEntry peSrc in peSource.History) { DateTime dt = peSrc.LastModificationTime; if(list.ContainsKey(dt)) { if(mm == PwMergeMethod.OverwriteExisting) list[dt] = peSrc.CloneDeep(); } else list[dt] = peSrc.CloneDeep(); } pe.History.Clear(); foreach(KeyValuePair<DateTime, PwEntry> kvpCur in list) { Debug.Assert(kvpCur.Value.Uuid.EqualsValue(pe.Uuid)); Debug.Assert(kvpCur.Value.History.UCount == 0); pe.History.Add(kvpCur.Value); } }
private void OTPDB_Synchronize(PwDatabase targetdb, FileFormatProvider fmtImp, byte[] bDecrypted, string text) { IStatusLogger dlgStatus = new OnDemandStatusDialog(true, Program.MainForm); dlgStatus.StartLogging(text, false); try { dlgStatus.SetText(text, LogStatusType.Info); PwDatabase pwImp; pwImp = new PwDatabase(); pwImp.New(new IOConnectionInfo(), targetdb.MasterKey); pwImp.MemoryProtection = targetdb.MemoryProtection.CloneDeep(); pwImp.MasterKey = targetdb.MasterKey; dlgStatus.SetText(text, LogStatusType.Info); using (var s = new MemoryStream(bDecrypted)) { fmtImp.Import(pwImp, s, null); } targetdb.KdfParameters = pwImp.KdfParameters; targetdb.DataCipherUuid = pwImp.DataCipherUuid; targetdb.HistoryMaxItems = pwImp.HistoryMaxItems; targetdb.HistoryMaxSize = pwImp.HistoryMaxSize; PwMergeMethod mm = PwMergeMethod.Synchronize; targetdb.RootGroup.Uuid = pwImp.RootGroup.Uuid; targetdb.MergeIn(pwImp, mm, dlgStatus); CleanupSyncedDB(targetdb); } catch (Exception ex) { PluginDebug.AddError("Error loading OTP db", 0, ex.Message); throw ex; } finally { dlgStatus.EndLogging(); } }
private void OnBtnOK(object sender, EventArgs e) { if (m_radioCreateNew.Checked) { m_mmSelected = PwMergeMethod.CreateNewUuids; } else if (m_radioKeepExisting.Checked) { m_mmSelected = PwMergeMethod.KeepExisting; } else if (m_radioOverwrite.Checked) { m_mmSelected = PwMergeMethod.OverwriteExisting; } else if (m_radioOverwriteIfNewer.Checked) { m_mmSelected = PwMergeMethod.OverwriteIfNewer; } else if (m_radioSynchronize.Checked) { m_mmSelected = PwMergeMethod.Synchronize; } }
/// <summary> /// Synchronize the current database with another one. /// </summary> /// <param name="pwSource">Input database to synchronize with. This input /// database is used to update the current one, but is not modified! You /// must copy the current object if you want a second instance of the /// synchronized database. The input database must not be seen as valid /// database any more after calling <c>Synchronize</c>.</param> /// <param name="mm">Merge method.</param> /// <param name="slStatus">Logger to report status messages to. /// May be <c>null</c>.</param> public void MergeIn(PwDatabase pwSource, PwMergeMethod mm, IStatusLogger slStatus) { if(pwSource == null) throw new ArgumentNullException("pwSource"); PwGroup pgOrgStructure = m_pgRootGroup.CloneStructure(); PwGroup pgSrcStructure = pwSource.m_pgRootGroup.CloneStructure(); if(mm == PwMergeMethod.CreateNewUuids) pwSource.RootGroup.CreateNewItemUuids(true, true, true); GroupHandler gh = delegate(PwGroup pg) { if(pg == pwSource.m_pgRootGroup) return true; PwGroup pgLocal = m_pgRootGroup.FindGroup(pg.Uuid, true); if(pgLocal == null) { PwGroup pgSourceParent = pg.ParentGroup; PwGroup pgLocalContainer; if(pgSourceParent == pwSource.m_pgRootGroup) pgLocalContainer = m_pgRootGroup; else pgLocalContainer = m_pgRootGroup.FindGroup(pgSourceParent.Uuid, true); Debug.Assert(pgLocalContainer != null); if(pgLocalContainer == null) pgLocalContainer = m_pgRootGroup; PwGroup pgNew = new PwGroup(false, false); pgNew.Uuid = pg.Uuid; pgNew.AssignProperties(pg, false, true); pgLocalContainer.AddGroup(pgNew, true); } else // pgLocal != null { Debug.Assert(mm != PwMergeMethod.CreateNewUuids); if(mm == PwMergeMethod.OverwriteExisting) pgLocal.AssignProperties(pg, false, false); else if((mm == PwMergeMethod.OverwriteIfNewer) || (mm == PwMergeMethod.Synchronize)) { pgLocal.AssignProperties(pg, true, false); } // else if(mm == PwMergeMethod.KeepExisting) ... } return ((slStatus != null) ? slStatus.ContinueWork() : true); }; EntryHandler eh = delegate(PwEntry pe) { PwEntry peLocal = m_pgRootGroup.FindEntry(pe.Uuid, true); if(peLocal == null) { PwGroup pgSourceParent = pe.ParentGroup; PwGroup pgLocalContainer; if(pgSourceParent == pwSource.m_pgRootGroup) pgLocalContainer = m_pgRootGroup; else pgLocalContainer = m_pgRootGroup.FindGroup(pgSourceParent.Uuid, true); Debug.Assert(pgLocalContainer != null); if(pgLocalContainer == null) pgLocalContainer = m_pgRootGroup; PwEntry peNew = new PwEntry(false, false); peNew.Uuid = pe.Uuid; peNew.AssignProperties(pe, false, true, true); pgLocalContainer.AddEntry(peNew, true); } else // peLocal != null { Debug.Assert(mm != PwMergeMethod.CreateNewUuids); bool bEquals = peLocal.EqualsEntry(pe, true, false, true, true, false); bool bOrgBackup = !bEquals; if(mm != PwMergeMethod.OverwriteExisting) bOrgBackup &= (pe.LastModificationTime > peLocal.LastModificationTime); bOrgBackup &= !pe.HasBackupOfData(peLocal, false, true); if(bOrgBackup) peLocal.CreateBackup(); bool bSrcBackup = !bEquals && (mm != PwMergeMethod.OverwriteExisting); bSrcBackup &= (peLocal.LastModificationTime > pe.LastModificationTime); bSrcBackup &= !peLocal.HasBackupOfData(pe, false, true); if(bSrcBackup) pe.CreateBackup(); if(mm == PwMergeMethod.OverwriteExisting) peLocal.AssignProperties(pe, false, false, false); else if((mm == PwMergeMethod.OverwriteIfNewer) || (mm == PwMergeMethod.Synchronize)) { peLocal.AssignProperties(pe, true, false, false); } // else if(mm == PwMergeMethod.KeepExisting) ... MergeEntryHistory(peLocal, pe, mm); } return ((slStatus != null) ? slStatus.ContinueWork() : true); }; if(!pwSource.RootGroup.TraverseTree(TraversalMethod.PreOrder, gh, eh)) throw new InvalidOperationException(); IStatusLogger slPrevStatus = m_slStatus; m_slStatus = slStatus; if(mm == PwMergeMethod.Synchronize) { ApplyDeletions(pwSource.m_vDeletedObjects, true); ApplyDeletions(m_vDeletedObjects, false); PwObjectPool ppOrgGroups = PwObjectPool.FromGroupRecursive( pgOrgStructure, false); PwObjectPool ppSrcGroups = PwObjectPool.FromGroupRecursive( pgSrcStructure, false); PwObjectPool ppOrgEntries = PwObjectPool.FromGroupRecursive( pgOrgStructure, true); PwObjectPool ppSrcEntries = PwObjectPool.FromGroupRecursive( pgSrcStructure, true); RelocateGroups(ppOrgGroups, ppSrcGroups); ReorderGroups(ppOrgGroups, ppSrcGroups); RelocateEntries(ppOrgEntries, ppSrcEntries); ReorderEntries(ppOrgEntries, ppSrcEntries); Debug.Assert(ValidateUuidUniqueness()); } // Must be called *after* merging groups, because group UUIDs // are required for recycle bin and entry template UUIDs MergeInDbProperties(pwSource, mm); MergeInCustomIcons(pwSource); m_slStatus = slPrevStatus; }
public void MergeIn(PwDatabase pwSource, PwMergeMethod mm) { MergeIn(pwSource, mm, null); }
private static void ImportIntoCurrentDatabase(EcasAction a, EcasContext ctx) { PwDatabase pd = Program.MainForm.ActiveDatabase; if ((pd == null) || !pd.IsOpen) { return; } string strPath = EcasUtil.GetParamString(a.Parameters, 0, true); if (string.IsNullOrEmpty(strPath)) { return; } IOConnectionInfo ioc = IOConnectionInfo.FromPath(strPath); string strFormat = EcasUtil.GetParamString(a.Parameters, 1, true); if (string.IsNullOrEmpty(strFormat)) { return; } FileFormatProvider ff = Program.FileFormatPool.Find(strFormat); if (ff == null) { throw new Exception(KPRes.Unknown + ": " + strFormat); } uint uMethod = EcasUtil.GetParamUInt(a.Parameters, 2); Type tMM = Enum.GetUnderlyingType(typeof(PwMergeMethod)); object oMethod = Convert.ChangeType(uMethod, tMM); PwMergeMethod mm = PwMergeMethod.None; if (Enum.IsDefined(typeof(PwMergeMethod), oMethod)) { mm = (PwMergeMethod)oMethod; } else { Debug.Assert(false); } if (mm == PwMergeMethod.None) { mm = PwMergeMethod.CreateNewUuids; } CompositeKey cmpKey = KeyFromParams(a, 3, 4, 5); if ((cmpKey == null) && ff.RequiresKey) { KeyPromptForm kpf = new KeyPromptForm(); kpf.InitEx(ioc, false, true); if (UIUtil.ShowDialogNotValue(kpf, DialogResult.OK)) { return; } cmpKey = kpf.CompositeKey; UIUtil.DestroyForm(kpf); } bool?b = true; try { b = ImportUtil.Import(pd, ff, ioc, mm, cmpKey); } finally { if (b.GetValueOrDefault(false)) { Program.MainForm.UpdateUI(false, null, true, null, true, null, true); } } }
public static bool? Import(PwDatabase pd, FileFormatProvider fmtImp, IOConnectionInfo iocImp, PwMergeMethod mm, CompositeKey cmpKey) { if(pd == null) { Debug.Assert(false); return false; } if(fmtImp == null) { Debug.Assert(false); return false; } if(iocImp == null) { Debug.Assert(false); return false; } if(cmpKey == null) cmpKey = new CompositeKey(); if(!AppPolicy.Try(AppPolicyId.Import)) return false; if(!fmtImp.TryBeginImport()) return false; PwDatabase pdImp = new PwDatabase(); pdImp.New(new IOConnectionInfo(), cmpKey); pdImp.MemoryProtection = pd.MemoryProtection.CloneDeep(); Stream s = IOConnection.OpenRead(iocImp); if(s == null) throw new FileNotFoundException(iocImp.GetDisplayName() + MessageService.NewLine + KPRes.FileNotFoundError); try { fmtImp.Import(pdImp, s, null); } finally { s.Close(); } pd.MergeIn(pdImp, mm); return true; }
/// <summary> /// Synchronize the current database with another one. /// </summary> /// <param name="pwSource">Input database to synchronize with. This input /// database is used to update the current one, but is not modified! You /// must copy the current object if you want a second instance of the /// synchronized database. The input database must not be seen as valid /// database any more after calling <c>Synchronize</c>.</param> /// <param name="mm">Merge method.</param> public void MergeIn(PwDatabase pwSource, PwMergeMethod mm) { if(mm == PwMergeMethod.CreateNewUuids) { pwSource.RootGroup.CreateNewItemUuids(true, true, true); } GroupHandler gh = delegate(PwGroup pg) { if(pg == pwSource.m_pgRootGroup) return true; PwGroup pgLocal = m_pgRootGroup.FindGroup(pg.Uuid, true); if(pgLocal == null) { PwGroup pgSourceParent = pg.ParentGroup; PwGroup pgLocalContainer; if(pgSourceParent == pwSource.m_pgRootGroup) pgLocalContainer = m_pgRootGroup; else pgLocalContainer = m_pgRootGroup.FindGroup(pgSourceParent.Uuid, true); Debug.Assert(pgLocalContainer != null); PwGroup pgNew = new PwGroup(); pgNew.Uuid = pg.Uuid; pgNew.AssignProperties(pg, false); pgLocalContainer.AddGroup(pgNew, true); } else // pgLocal != null { Debug.Assert(mm != PwMergeMethod.CreateNewUuids); if(mm == PwMergeMethod.OverwriteExisting) pgLocal.AssignProperties(pg, false); else if((mm == PwMergeMethod.OverwriteIfNewer) || (mm == PwMergeMethod.Synchronize)) { pgLocal.AssignProperties(pg, true); } // else if(mm == PwMergeMethod.KeepExisting) ... } return true; }; EntryHandler eh = delegate(PwEntry pe) { PwEntry peLocal = m_pgRootGroup.FindEntry(pe.Uuid, true); if(peLocal == null) { PwGroup pgSourceParent = pe.ParentGroup; PwGroup pgLocalContainer; if(pgSourceParent == pwSource.m_pgRootGroup) pgLocalContainer = m_pgRootGroup; else pgLocalContainer = m_pgRootGroup.FindGroup(pgSourceParent.Uuid, true); Debug.Assert(pgLocalContainer != null); PwEntry peNew = new PwEntry(false, false); peNew.Uuid = pe.Uuid; peNew.AssignProperties(pe, false, true); pgLocalContainer.AddEntry(peNew, true); } else // peLocal == null { Debug.Assert(mm != PwMergeMethod.CreateNewUuids); if(mm == PwMergeMethod.OverwriteExisting) peLocal.AssignProperties(pe, false, true); else if((mm == PwMergeMethod.OverwriteIfNewer) || (mm == PwMergeMethod.Synchronize)) { peLocal.AssignProperties(pe, true, true); } // else if(mm == PwMergeMethod.KeepExisting) ... } return true; }; if(!pwSource.RootGroup.TraverseTree(TraversalMethod.PreOrder, gh, eh)) throw new InvalidOperationException(); if(mm == PwMergeMethod.Synchronize) { ApplyDeletions(pwSource.m_vDeletedObjects, true); ApplyDeletions(m_vDeletedObjects, false); } }
private static bool PerformImport(PwDatabase pwDb, CommandLineArgs args) { string strFile = args["file"]; if (string.IsNullOrEmpty(strFile)) { KPScript.Program.WriteLineColored("E: No file specified to import!", ConsoleColor.Red); return(false); } IOConnectionInfo ioc = IOConnectionInfo.FromPath(strFile); FileFormatProvider prov = GetFormatProv(args); if (prov == null) { return(false); } if (!prov.SupportsImport) { KPScript.Program.WriteLineColored("E: No import support for this format!", ConsoleColor.Red); return(false); } if (!prov.TryBeginImport()) { KPScript.Program.WriteLineColored("E: Format initialization failed!", ConsoleColor.Red); return(false); } PwMergeMethod mm = PwMergeMethod.CreateNewUuids; string strMM = args["mm"]; if (!string.IsNullOrEmpty(strMM)) { if (strMM.Equals("CreateNewUuids", StrUtil.CaseIgnoreCmp)) { mm = PwMergeMethod.CreateNewUuids; } else if (strMM.Equals("KeepExisting", StrUtil.CaseIgnoreCmp)) { mm = PwMergeMethod.KeepExisting; } else if (strMM.Equals("OverwriteExisting", StrUtil.CaseIgnoreCmp)) { mm = PwMergeMethod.OverwriteExisting; } else if (strMM.Equals("OverwriteIfNewer", StrUtil.CaseIgnoreCmp)) { mm = PwMergeMethod.OverwriteIfNewer; } else if (strMM.Equals("Sync", StrUtil.CaseIgnoreCmp)) { mm = PwMergeMethod.Synchronize; } } CompositeKey cmpKey = KpsUtil.GetMasterKey(args, "imp_", ioc); if ((cmpKey == null) || (cmpKey.UserKeyCount == 0)) { cmpKey = pwDb.MasterKey; } bool? b = false; string strError = "Import failed!"; try { b = ImportUtil.Import(pwDb, prov, ioc, mm, cmpKey); } catch (Exception ex) { if ((ex != null) && !string.IsNullOrEmpty(ex.Message)) { strError = ex.Message; } } bool r = (b.HasValue && b.Value); if (r) { KPScript.Program.WriteLineColored("OK: Import succeeded!", ConsoleColor.Green); } else { KPScript.Program.WriteLineColored("E: " + strError, ConsoleColor.Red); } return(r); }
/// <summary> /// Synchronize the current database with another one. /// </summary> /// <param name="pwSource">Input database to synchronize with. This input /// database is used to update the current one, but is not modified! You /// must copy the current object if you want a second instance of the /// synchronized database. The input database must not be seen as valid /// database any more after calling <c>Synchronize</c>.</param> /// <param name="mm">Merge method.</param> public void MergeIn(PwDatabase pwSource, PwMergeMethod mm) { if (mm == PwMergeMethod.CreateNewUuids) { pwSource.RootGroup.CreateNewItemUuids(true, true, true); } GroupHandler gh = delegate(PwGroup pg) { if (pg == pwSource.m_pgRootGroup) { return(true); } PwGroup pgLocal = m_pgRootGroup.FindGroup(pg.Uuid, true); if (pgLocal == null) { PwGroup pgSourceParent = pg.ParentGroup; PwGroup pgLocalContainer; if (pgSourceParent == pwSource.m_pgRootGroup) { pgLocalContainer = m_pgRootGroup; } else { pgLocalContainer = m_pgRootGroup.FindGroup(pgSourceParent.Uuid, true); } Debug.Assert(pgLocalContainer != null); PwGroup pgNew = new PwGroup(); pgNew.Uuid = pg.Uuid; pgNew.AssignProperties(pg, false); pgLocalContainer.AddGroup(pgNew, true); } else // pgLocal != null { Debug.Assert(mm != PwMergeMethod.CreateNewUuids); if (mm == PwMergeMethod.OverwriteExisting) { pgLocal.AssignProperties(pg, false); } else if ((mm == PwMergeMethod.OverwriteIfNewer) || (mm == PwMergeMethod.Synchronize)) { pgLocal.AssignProperties(pg, true); } // else if(mm == PwMergeMethod.KeepExisting) ... } return(true); }; EntryHandler eh = delegate(PwEntry pe) { PwEntry peLocal = m_pgRootGroup.FindEntry(pe.Uuid, true); if (peLocal == null) { PwGroup pgSourceParent = pe.ParentGroup; PwGroup pgLocalContainer; if (pgSourceParent == pwSource.m_pgRootGroup) { pgLocalContainer = m_pgRootGroup; } else { pgLocalContainer = m_pgRootGroup.FindGroup(pgSourceParent.Uuid, true); } Debug.Assert(pgLocalContainer != null); PwEntry peNew = new PwEntry(false, false); peNew.Uuid = pe.Uuid; peNew.AssignProperties(pe, false, true); pgLocalContainer.AddEntry(peNew, true); } else // peLocal == null { Debug.Assert(mm != PwMergeMethod.CreateNewUuids); if (mm == PwMergeMethod.OverwriteExisting) { peLocal.AssignProperties(pe, false, true); } else if ((mm == PwMergeMethod.OverwriteIfNewer) || (mm == PwMergeMethod.Synchronize)) { peLocal.AssignProperties(pe, true, true); } // else if(mm == PwMergeMethod.KeepExisting) ... } return(true); }; if (!pwSource.RootGroup.TraverseTree(TraversalMethod.PreOrder, gh, eh)) { throw new InvalidOperationException(); } if (mm == PwMergeMethod.Synchronize) { ApplyDeletions(pwSource.m_vDeletedObjects, true); ApplyDeletions(m_vDeletedObjects, false); } }