Add Dirk Luetjen's ssphys libraries and command-line tool
[vss2svn.git] / ssphys / SSPhysLib / SSVersionObject.cpp
blobfcaaef8e67b9aae75792210fe62c78ce2d225726
1 // SSVersionObject.cpp: implementation of the SSVersionObject class.
2 //
3 //////////////////////////////////////////////////////////////////////
5 #include "stdafx.h"
6 #include "SSVersionObject.h"
7 #include "SSFiles.h"
8 #include "SSName.h"
10 //---------------------------------------------------------------------------
11 #include "LeakWatcher.h"
13 #ifdef _DEBUG
14 #define new DEBUG_NEW
15 #undef THIS_FILE
16 static char THIS_FILE[] = __FILE__;
17 #endif
20 //////////////////////////////////////////////////////////////////////
21 // Construction/Destruction
22 //////////////////////////////////////////////////////////////////////
23 SSVersionObject::SSVersionObject (SSRecordPtr pRecord)
24 : SSObject (pRecord, eHistoryRecord),
25 m_pAction (NULL)
27 if (pRecord)
29 if (pRecord->GetLen() < sizeof (VERSION_RECORD))
30 throw SSRecordException ("not enough data for version object");
32 m_pAction = SSAction::MakeAction (pRecord);
36 SSVersionObject::~SSVersionObject ()
38 delete m_pAction;
41 SSVersionObject::SSVersionObject (SSVersionObject& object)
42 : SSObject (object),
43 m_pAction (NULL)
45 m_pAction = SSAction::MakeAction (GetRecord());
48 SSVersionObject& SSVersionObject::operator= (SSVersionObject const & object)
50 if (&object != this)
52 *(SSObject*)this = object;
53 m_pAction = SSAction::MakeAction (GetRecord());
55 return *this;
58 std::string SSVersionObject::GetComment () const
60 if (GetOffsetToNextRecordOrComment() && GetLengthComment())
62 SSCommentObject comment (GetFile ()->GetRecord (GetOffsetToNextRecordOrComment()));
63 return comment.GetComment();
65 return "";
68 //std::string SSVersionObject::GetLabel () const
69 //{
70 // const SSLabeledAction* pLabeledAction = dynamic_cast<const SSLabeledAction*> (m_pAction);
71 // return pLabeledAction ? pLabeledAction->GetLabel () : "";
72 //}
73 std::string SSVersionObject::GetLabelComment () const
75 const SSLabeledAction* pLabeledAction = dynamic_cast<const SSLabeledAction*> (m_pAction);
76 return pLabeledAction ? pLabeledAction->GetLabelComment () : "";
79 SSVersionObject SSVersionObject::GetPreviousObject () const
81 if (GetPrevious () == 0)
82 return SSVersionObject (SSRecordPtr());
84 return SSVersionObject (GetFile ()->GetRecord (GetPrevious ()));
87 bool SSVersionObject::Validate ()
89 bool retval = true;
91 SSRecordPtr pLabelCommentRecord;
92 SSRecordPtr pNext;
93 SSRecordPtr pPrevious;
95 const VERSION_RECORD* pVersion = GetData ();
96 if (pVersion->OffsetToLabelComment)
97 pLabelCommentRecord = GetFile ()->GetRecord (pVersion->OffsetToLabelComment);
98 if (pVersion->OffsetToNextRecordOrComment)
99 pNext = GetFile ()->GetRecord (pVersion->OffsetToNextRecordOrComment);
100 if (pVersion->Previous)
101 pPrevious = GetFile ()->GetRecord (pVersion->Previous);
103 if ( (pVersion->LengthLabelComment == 0 && pVersion->OffsetToLabelComment != 0)
104 || (pVersion->LengthLabelComment != 0 && pVersion->OffsetToLabelComment == 0) )
106 Warning ("invalid length and offset combination");
107 retval &= false;
110 if (pVersion->LengthLabelComment)
112 retval &= warn_with_msg_if (!pLabelCommentRecord, "the expected comment record is invalid")
114 retval &= warn_with_msg_if (pLabelCommentRecord->GetType () != eCommentRecord,
115 "the record pointed to by offsetToLabelComment is expected to be a comment record");
116 return false;
119 if (pVersion->LengthComment)
121 retval &= warn_with_msg_if (!pNext, "the expected comment record is invalid");
123 retval &= warn_with_msg_if (pNext->GetType () != eCommentRecord,
124 "the record pointed to by offsetToNextRecordOrComment is expected to be a comment record");
127 if (pVersion->Previous && !pPrevious)
129 Warning ("a previous record is specified, but the record could not be read");
130 retval &= false;
133 if (pPrevious)
135 retval = warn_with_msg_if (pPrevious->GetType () != eHistoryRecord,
136 "the record pointed to by previous is expected to be a history record");
139 return retval;
141 // ---------------------------------------------------------------
142 class ActionNode : public XMLNode
144 public:
145 ActionNode (XMLNode* pParent, eAction actionid)
146 : XMLNode (pParent, "Action", ToAttribMap(actionid))
150 static AttribMap ToAttribMap (eAction actionid)
152 std::string actionString = CAction::ActionToString (actionid);
153 actionString.erase (std::remove (actionString.begin (), actionString.end (), ' '));
155 return ToAttribMap (actionString);
157 static AttribMap ToAttribMap (std::string actionString)
159 AttribMap map;
160 map["ActionId"] = actionString;
161 return map;
166 void SSVersionObject::ToXml (XMLNode* pParent) const
168 XMLElement versionNumber (pParent, "VersionNumber", GetVersionNumber());
169 XMLElement useName (pParent, "UserName", GetUsername());
170 XMLElement date (pParent, "Date", GetDate());
171 if (!GetComment ().empty ())
173 XMLElement date (pParent, "Comment", GetComment());
176 if (GetAction ())
178 SSAction* pAction = GetAction ();
179 ActionNode node (pParent, pAction->GetActionID());
181 pAction->ToXml (&node);
185 void SSVersionObject::Dump (std::ostream& os) const
187 SSRecordPtr pLabelCommentRecord;
188 SSRecordPtr pNext;
189 const VERSION_RECORD* pVersion = GetData ();
191 if (pVersion->OffsetToLabelComment)
192 pLabelCommentRecord = GetFile ()->GetRecord (pVersion->OffsetToLabelComment);
193 if (pVersion->OffsetToNextRecordOrComment)
194 pNext = GetFile ()->GetRecord (pVersion->OffsetToNextRecordOrComment);
196 // dump basic information
197 SSObject::Dump (os);
199 SSVersionObject previous = GetPreviousObject ();
200 os << "Previous: ";
201 if (previous)
203 os << "Type " << SSRecord::TypeToString (previous.GetType ()) << ", ";
204 os << "Offset 0x" << std::hex << previous.GetOffset () << std::dec;
205 os << std::endl;
207 else
208 os << "NULL" << std::endl;
210 os << "Action " << GetActionID() << " : " << CAction::ActionToString (GetActionID()) << std::endl;
211 os << "ActionStr: " << GetActionString () << std::endl;
212 os << "Version: " << GetVersionNumber () << std::endl;
213 // os << "Date" << std::endl;
214 os << "User: " << GetUsername () << std::endl;
215 os << "Comment: " << GetComment () << std::endl;
217 os << "Comment Offset 0x" << std::hex << pVersion->OffsetToNextRecordOrComment << std::dec << ", Length " << pVersion->LengthComment;
218 if (pNext)
219 os << ", Type " << pNext->GetRecordType ();
220 os << std::endl;
222 os << "LabelComment Offset 0x" << std::hex << pVersion->OffsetToLabelComment << std::dec << ", Length " << pVersion->LengthLabelComment;
223 if (pLabelCommentRecord)
224 os << ", Type " << pLabelCommentRecord->GetRecordType ();
225 os << std::endl;
227 SSAction* pAction = GetAction ();
228 if (pAction)
229 pAction->Dump (os);
232 //---------------------------------------------------------------------------
233 SSAction::SSAction (SSRecordPtr pRecord)
235 const VERSION_RECORD* pVersion = GetHistoryRecordPtr (pRecord);
237 m_ActionId = static_cast <eAction> (pVersion->ActionID);
240 SSAction::~SSAction ()
244 SSAction* SSAction::MakeAction (SSRecordPtr pRecord)
246 if (!pRecord)
247 return NULL;
249 if (pRecord->GetLen () < sizeof (VERSION_RECORD))
250 throw SSException ("not enough bytes for Version Header in record");
252 const VERSION_RECORD* pVersion = reinterpret_cast<const VERSION_RECORD*> (pRecord->GetBuffer ());
254 if (pVersion->ActionID == Labeled)
255 return new SSLabeledAction (pRecord);
256 else if (pVersion->ActionID == Created_Project)
257 return new SSCreatedProjectAction (pRecord);
258 else if (pVersion->ActionID == Added_Project)
259 return new SSAddedProjectAction (pRecord);
260 else if (pVersion->ActionID == Added_File)
261 return new SSAddedFileAction (pRecord);
262 else if (pVersion->ActionID == Destroyed_Project)
263 return new SSDestroyedProjectAction(pRecord);
264 else if (pVersion->ActionID == Destroyed_File)
265 return new SSDestroyedFileAction (pRecord);
266 else if (pVersion->ActionID == Deleted_Project)
267 return new SSDeletedProjectAction (pRecord);
268 else if (pVersion->ActionID == Deleted_File)
269 return new SSDeletedFileAction (pRecord);
270 else if (pVersion->ActionID == Recovered_Project)
271 return new SSRecoveredProjectAction (pRecord);
272 else if (pVersion->ActionID == Recovered_File)
273 return new SSRecoveredFileAction (pRecord);
274 else if (pVersion->ActionID == Renamed_Project)
275 return new SSRenamedProjectAction (pRecord);
276 else if (pVersion->ActionID == Renamed_File)
277 return new SSRenamedFileAction (pRecord);
278 // else if (pVersion->ActionID == missing action 12)
279 // return new SSVersionObject (pRecord);
280 // else if (pVersion->ActionID == missing action 13)
281 // return new SSVersionObject (pRecord);
282 else if (pVersion->ActionID == Shared_File)
283 return new SSSharedAction (pRecord);
284 else if (pVersion->ActionID == Branch_File)
285 return new SSRollbackAction (pRecord);
286 else if (pVersion->ActionID == Created_File)
287 return new SSCreatedFileAction (pRecord);
288 else if (pVersion->ActionID == Checked_in)
289 return new SSCheckedInAction (pRecord);
290 // else if (pVersion->ActionID == // missing action 18)
291 // return new SSVersionObject (pRecord);
292 else if (pVersion->ActionID == RollBack)
293 return new SSRollbackAction (pRecord);
294 else
295 throw SSUnknownActionException (pVersion->ActionID, pRecord);
297 return NULL;
300 const VERSION_RECORD* SSAction::GetHistoryRecordPtr (SSRecordPtr pRecord) const
302 assert (pRecord->GetBuffer ());
303 return reinterpret_cast<const VERSION_RECORD*> (pRecord->GetBuffer ());
306 void SSAction::Dump (std::ostream& os) const
310 //---------------------------------------------------------------------------
311 SSLabeledAction::SSLabeledAction (SSRecordPtr pRecord)
312 : SSActionEx<SSLabeledAction> (pRecord)
314 const VERSION_RECORD* pVersion = GetHistoryRecordPtr (pRecord);
316 m_Label = std::string (pVersion->Label);
318 if (pVersion->OffsetToLabelComment && pVersion->LengthLabelComment > 0)
320 try {
321 SSCommentObject commentObject (pRecord->GetFileImp ()->GetRecord (pVersion->OffsetToLabelComment));
322 m_LabelComment = commentObject.GetComment();
324 catch (SSRecordException&)
330 SSLabeledAction::~SSLabeledAction ()
334 std::string SSLabeledAction::FormatActionString ()
336 return "Labeled " + m_Label;
339 void SSLabeledAction::ToXml (XMLNode* pParent) const
341 XMLElement label (pParent, "Label", GetLabel());
342 XMLElement comment (pParent, "LabelComment", GetLabelComment());
346 void SSLabeledAction::Dump (std::ostream& os) const
348 SSActionEx<SSLabeledAction>::Dump (os);
351 //---------------------------------------------------------------------------
352 template <class ACTION, class STRUCT>
353 SSItemAction<ACTION, STRUCT>::SSItemAction (SSRecordPtr pRecord, std::string actionString)
354 : SSActionEx<ACTION> (pRecord),
355 m_ActionString (actionString)
357 memcpy (&m_Action, pRecord->GetBuffer()+sizeof(VERSION_RECORD), sizeof(STRUCT));
360 template <class T, class ACTION>
361 std::string SSItemAction<T, ACTION>::FormatActionString ()
363 return m_ActionString + GetName ();
366 template <class T, class ACTION>
367 void SSItemAction<T, ACTION>::ToXml (XMLNode* pParent) const
369 XMLElement physical (pParent, "Physical", GetPhysical());
370 GetSSName().ToXml (pParent);
373 template <class T, class ACTION>
374 void SSItemAction<T, ACTION>::Dump (std::ostream& os) const
376 SSActionEx<T>::Dump (os);
379 //---------------------------------------------------------------------------
380 template <class ACTION>
381 SSDestroyedAction<ACTION>::SSDestroyedAction (SSRecordPtr pRecord, std::string prefix)
382 : SSItemAction<ACTION, DESTROYED_ACTION> (pRecord, ""),
383 m_Prefix (prefix)
387 template <class ACTION>
388 std::string SSDestroyedAction<ACTION>::FormatActionString ()
390 std::string action (m_Prefix);
391 action += GetName () + " Destroyed";
392 return action;
395 //---------------------------------------------------------------------------
396 template <class ACTION>
397 SSRenamedAction<ACTION>::SSRenamedAction (SSRecordPtr pRecord, std::string prefix)
398 : SSItemAction<ACTION, RENAMED_ACTION> (pRecord, ""),
399 m_Prefix (prefix)
403 template <class ACTION>
404 std::string SSRenamedAction<ACTION>::FormatActionString ()
406 SSName ssOldName (GetSSName ());
407 SSName ssNewName (m_Action.newName);
408 std::string action (m_Prefix);
409 action += ssOldName.GetFullName ();
410 action += " renamedto " + m_Prefix;
411 action += ssNewName.GetFullName ();
412 return action;
415 template <class ACTION>
416 void SSRenamedAction<ACTION>::ToXml (XMLNode* pParent) const
418 SSItemAction<ACTION,RENAMED_ACTION>::ToXml (pParent);
420 GetNewSSName().ToXml (pParent, "NewSSName");
423 template <class ACTION>
424 void SSRenamedAction<ACTION>::Dump (std::ostream& os) const
426 SSItemAction<ACTION, RENAMED_ACTION>::Dump (os);
429 //---------------------------------------------------------------------------
430 SSCheckedInAction::SSCheckedInAction (SSRecordPtr pRecord)
431 : SSActionEx<SSCheckedInAction> (pRecord),
432 m_FilePtr (pRecord->GetFileImp ())
434 memcpy (&m_Action, pRecord->GetBuffer()+sizeof(VERSION_RECORD), sizeof(CHECKED_IN_ACTION));
437 SSCheckedInAction::~SSCheckedInAction ()
441 std::string SSCheckedInAction::FormatActionString ()
443 std::string action = "Checked In ";
444 action += std::string (m_Action.checkInSpec);
445 return action;
448 SSRecordPtr SSCheckedInAction::GetFileDelta () const
450 if (!m_pFileDelta && m_Action.offsetFileDelta)
452 m_pFileDelta = m_FilePtr->GetRecord (m_Action.offsetFileDelta);
455 return m_pFileDelta;
458 void SSCheckedInAction::ToXml (XMLNode* pParent) const
460 XMLElement checkInNode (pParent, "CheckInSpec", GetFileSepc());
461 XMLElement offsetNode (pParent, "Offset", GetOffset());
464 void SSCheckedInAction::Dump (std::ostream& os) const
466 SSActionEx<SSCheckedInAction>::Dump (os);
469 //---------------------------------------------------------------------------
470 SSSharedAction::SSSharedAction (SSRecordPtr pRecord)
471 : SSItemAction<SSSharedAction, SHARED_FILE_ACTION> (pRecord, "")
475 SSSharedAction::~SSSharedAction ()
479 std::string SSSharedAction::FormatActionString ()
481 std::ostringstream str;
482 SSName name (m_Action.name);
483 if (m_Action.pinnedToVersion == -1)
484 str << m_Action.srcPathSpec << "/" << name.GetFullName() << ";" << m_Action.version << " shared";
485 else if (m_Action.pinnedToVersion == 0)
486 str << m_Action.srcPathSpec << "/" << name.GetFullName() << " pinned to version " << m_Action.version;
487 else if (m_Action.version == 0)
488 str << m_Action.srcPathSpec << "/" << name.GetFullName() << " unpinned";
489 else
490 throw SSException ("bad share/pin/unpin action: version should be 0");
492 return str.str();
496 void SSSharedAction::ToXml (XMLNode* pParent) const
498 SSItemAction<SSSharedAction, SHARED_FILE_ACTION>::ToXml(pParent);
500 XMLElement srcPathNode (pParent, "SrcPath", GetSrcPathSpec ());
501 XMLElement pinnedNode (pParent, "PinnedToVersion", GetPinnedToVersion ());
502 XMLElement versionNode (pParent, "Version", GetVersion ());
505 void SSSharedAction::Dump (std::ostream& os) const
507 SSItemAction<SSSharedAction, SHARED_FILE_ACTION>::Dump(os);
510 //---------------------------------------------------------------------------
511 void SSRollbackAction::ToXml (XMLNode* pParent) const
513 SSItemAction<SSRollbackAction, ROLLBACK_ACTION>::ToXml (pParent);
515 XMLElement parentNode (pParent, "Parent", GetParent());
518 void SSRollbackAction::Dump (std::ostream& os) const
520 SSItemAction<SSRollbackAction, ROLLBACK_ACTION>::Dump (os);