1 /*  $Id: objectio.cpp 529139 2017-03-01 17:43:15Z gouriano $
2 * ===========================================================================
3 *
4 *                            PUBLIC DOMAIN NOTICE
5 *               National Center for Biotechnology Information
6 *
7 *  This software/database is a "United States Government Work" under the
8 *  terms of the United States Copyright Act.  It was written as part of
9 *  the author's official duties as a United States Government employee and
10 *  thus cannot be copyrighted.  This software/database is freely available
11 *  to the public for use. The National Library of Medicine and the U.S.
12 *  Government have not placed any restriction on its use or reproduction.
13 *
14 *  Although all reasonable efforts have been taken to ensure the accuracy
15 *  and reliability of the software and data, the NLM and the U.S.
16 *  Government do not and cannot warrant the performance or results that
17 *  may be obtained by using this software or data. The NLM and the U.S.
18 *  Government disclaim all warranties, express or implied, including
19 *  warranties of performance, merchantability or fitness for any particular
20 *  purpose.
21 *
22 *  Please cite the author in any work or product based on this material.
23 *
24 * ===========================================================================
25 *
26 * Author: Eugene Vasilchenko
27 *
28 * File Description:
29 *   !!! PUT YOUR DESCRIPTION HERE !!!
30 */
31 
32 #include <ncbi_pch.hpp>
33 #include <corelib/ncbistd.hpp>
34 #include <serial/objectio.hpp>
35 #include <serial/objistr.hpp>
36 #include <serial/objostr.hpp>
37 #include <serial/objcopy.hpp>
38 #include <serial/objhook.hpp>
39 
40 BEGIN_NCBI_SCOPE
41 
42 
43 // readers
ReadContainer(CObjectIStream & in,CReadContainerElementHook & hook)44 void CObjectInfo::ReadContainer(CObjectIStream& in,
45                                 CReadContainerElementHook& hook)
46 {
47     const CContainerTypeInfo* containerType = GetContainerTypeInfo();
48     BEGIN_OBJECT_FRAME_OF2(in, eFrameArray, containerType);
49     in.BeginContainer(containerType);
50 
51     TTypeInfo elementType = containerType->GetElementType();
52     BEGIN_OBJECT_FRAME_OF2(in, eFrameArrayElement, elementType);
53 
54     while ( in.BeginContainerElement(elementType) ) {
55         hook.ReadContainerElement(in, *this);
56         in.EndContainerElement();
57     }
58 
59     END_OBJECT_FRAME_OF(in);
60 
61     in.EndContainer();
62     END_OBJECT_FRAME_OF(in);
63 }
64 
65 inline
CIStreamFrame(CObjectIStream & stream)66 CIStreamFrame::CIStreamFrame(CObjectIStream& stream)
67     : m_Stream(stream), m_Depth(stream.GetStackDepth())
68 {
69 }
70 
~CIStreamFrame(void)71 CIStreamFrame::~CIStreamFrame(void)
72 {
73     if ( GetStream().GetStackDepth() != m_Depth ) {
74         try {
75             GetStream().PopErrorFrame();
76         }
77         catch (...) {
78             GetStream().SetFailFlags(CObjectIStream::fIllegalCall,
79                 "object stack frame error");
80         }
81     }
82 }
83 
84 inline
Good(void) const85 bool CIStreamFrame::Good(void) const
86 {
87     return GetStream().InGoodState();
88 }
89 
90 inline
COStreamFrame(CObjectOStream & stream)91 COStreamFrame::COStreamFrame(CObjectOStream& stream)
92     : m_Stream(stream), m_Depth(stream.GetStackDepth())
93 {
94 }
95 
96 inline
Good(void) const97 bool COStreamFrame::Good(void) const
98 {
99     return GetStream().InGoodState();
100 }
101 
~COStreamFrame(void)102 COStreamFrame::~COStreamFrame(void)
103 {
104     if ( GetStream().GetStackDepth() != m_Depth ) {
105         try {
106             GetStream().PopErrorFrame();
107         }
108         catch (...) {
109             GetStream().SetFailFlags(CObjectOStream::fIllegalCall,
110                 "object stack frame error");
111         }
112     }
113 }
114 
115 #ifdef NCBI_COMPILER_ICC
operator new(size_t size)116 void* COStreamFrame::operator new(size_t size)
117 {
118     return ::operator new(size);
119 }
120 
operator new[](size_t size)121 void* COStreamFrame::operator new[](size_t size)
122 {
123     return ::operator new[](size);
124 }
125 
operator new(size_t size)126 void* CIStreamFrame::operator new(size_t size)
127 {
128     return ::operator new(size);
129 }
130 
operator new[](size_t size)131 void* CIStreamFrame::operator new[](size_t size)
132 {
133     return ::operator new[](size);
134 }
135 #endif
136 
137 
138 /////////////////////////////////////////////////////////////////////////////
139 // read/write classMember
140 
141 inline
GetMemberInfo(void) const142 const CMemberInfo* CIStreamClassMemberIterator::GetMemberInfo(void) const
143 {
144     return m_ClassType.GetClassTypeInfo()->GetMemberInfo(m_MemberIndex);
145 }
146 
147 inline
BeginClassMember(void)148 void CIStreamClassMemberIterator::BeginClassMember(void)
149 {
150     if ( m_ClassType.GetClassTypeInfo()->RandomOrder() ) {
151         m_MemberIndex =
152             GetStream().BeginClassMember(m_ClassType.GetClassTypeInfo());
153     } else {
154         m_MemberIndex =
155             GetStream().BeginClassMember(m_ClassType.GetClassTypeInfo(),
156                                          m_MemberIndex + 1);
157     }
158     if ( *this )
159         GetStream().SetTopMemberId(GetMemberInfo()->GetId());
160 }
161 
162 inline
IllegalCall(const char * message) const163 void CIStreamClassMemberIterator::IllegalCall(const char* message) const
164 {
165     GetStream().ThrowError(CObjectIStream::fIllegalCall, message);
166 }
167 
168 inline
BadState(void) const169 void CIStreamClassMemberIterator::BadState(void) const
170 {
171     IllegalCall("bad CIStreamClassMemberIterator state");
172 }
173 
CIStreamClassMemberIterator(CObjectIStream & in,const CObjectTypeInfo & classType)174 CIStreamClassMemberIterator::CIStreamClassMemberIterator(CObjectIStream& in,
175                                      const CObjectTypeInfo& classType)
176     : CParent(in), m_ClassType(classType)
177 {
178     const CClassTypeInfo* classTypeInfo = classType.GetClassTypeInfo();
179     in.PushFrame(CObjectStackFrame::eFrameClass, classTypeInfo);
180     in.BeginClass(classTypeInfo);
181 
182     in.PushFrame(CObjectStackFrame::eFrameClassMember);
183     m_MemberIndex = kFirstMemberIndex - 1;
184     BeginClassMember();
185 }
186 
~CIStreamClassMemberIterator(void)187 CIStreamClassMemberIterator::~CIStreamClassMemberIterator(void)
188 {
189     if ( Good() ) {
190         try {
191             if ( *this )
192                 GetStream().EndClassMember();
193             GetStream().PopFrame();
194             GetStream().EndClass();
195             GetStream().PopFrame();
196         }
197         catch (...) {
198             GetStream().SetFailFlags(CObjectIStream::fIllegalCall,
199                 "class member iterator error");
200         }
201     }
202 }
203 
204 inline
CheckState(void)205 void CIStreamClassMemberIterator::CheckState(void)
206 {
207     if ( m_MemberIndex == kInvalidMember )
208         BadState();
209 }
210 
NextClassMember(void)211 void CIStreamClassMemberIterator::NextClassMember(void)
212 {
213     CheckState();
214     GetStream().EndClassMember();
215     BeginClassMember();
216 }
217 
ReadClassMember(const CObjectInfo & member)218 void CIStreamClassMemberIterator::ReadClassMember(const CObjectInfo& member)
219 {
220     CheckState();
221     GetMemberInfo()->ReadMember(GetStream(), member.GetObjectPtr());
222 }
223 
SkipClassMember(const CObjectTypeInfo & member)224 void CIStreamClassMemberIterator::SkipClassMember(const CObjectTypeInfo& member)
225 {
226     CheckState();
227     GetStream().SkipObject(member.GetTypeInfo());
228 }
229 
SkipClassMember(void)230 void CIStreamClassMemberIterator::SkipClassMember(void)
231 {
232     CheckState();
233     GetStream().SkipObject(GetMemberInfo()->GetTypeInfo());
234 }
235 
236 
237 /////////////////////////////////////////////////////////////////////////////
238 // read/write class member
239 
COStreamClassMember(CObjectOStream & out,const CObjectTypeInfoMI & member)240 COStreamClassMember::COStreamClassMember(CObjectOStream& out,
241                                          const CObjectTypeInfoMI& member)
242     : CParent(out)
243 {
244     const CMemberInfo* memberInfo = member.GetMemberInfo();
245     out.PushFrame(CObjectStackFrame::eFrameClassMember, memberInfo->GetId());
246     out.BeginClassMember(memberInfo->GetId());
247 }
248 
~COStreamClassMember(void)249 COStreamClassMember::~COStreamClassMember(void)
250 {
251     if ( Good() ) {
252         try {
253             GetStream().EndClassMember();
254             GetStream().PopFrame();
255         }
256         catch (...) {
257             GetStream().SetFailFlags(CObjectIStream::fIllegalCall,
258                 "class member write error");
259         }
260     }
261 }
262 
263 // read/write container
264 inline
BeginElement(void)265 void CIStreamContainerIterator::BeginElement(void)
266 {
267     _ASSERT(m_State == eElementEnd);
268     if ( GetStream().BeginContainerElement(m_ElementTypeInfo) )
269         m_State = eElementBegin;
270     else
271         m_State = eNoMoreElements;
272 }
273 
274 inline
IllegalCall(const char * message) const275 void CIStreamContainerIterator::IllegalCall(const char* message) const
276 {
277     GetStream().ThrowError(CObjectIStream::fIllegalCall, message);
278     // GetStream().SetFailFlags(CObjectIStream::fIllegalCall, message);
279 }
280 
281 inline
BadState(void) const282 void CIStreamContainerIterator::BadState(void) const
283 {
284     IllegalCall("bad CIStreamContainerIterator state");
285 }
286 
CIStreamContainerIterator(CObjectIStream & in,const CObjectTypeInfo & containerType)287 CIStreamContainerIterator::CIStreamContainerIterator(CObjectIStream& in,
288                                      const CObjectTypeInfo& containerType)
289     : CParent(in), m_ContainerType(containerType), m_State(eElementEnd)
290 {
291     const CContainerTypeInfo* containerTypeInfo;
292     if (m_ContainerType.GetTypeFamily() == eTypeFamilyClass) {
293         const CClassTypeInfo* classType =
294             CTypeConverter<CClassTypeInfo>::SafeCast(m_ContainerType.GetTypeInfo());
295         const CItemInfo* itemInfo =
296             classType->GetItems().GetItemInfo(classType->GetItems().FirstIndex());
297         _ASSERT(itemInfo->GetTypeInfo()->GetTypeFamily() == eTypeFamilyContainer);
298         m_Container = itemInfo;
299         containerTypeInfo =
300             CTypeConverter<CContainerTypeInfo>::SafeCast(itemInfo->GetTypeInfo());
301         in.PushFrame(CObjectStackFrame::eFrameNamed, m_ContainerType.GetTypeInfo());
302         in.BeginNamedType(m_ContainerType.GetTypeInfo());
303     } else {
304         m_Container = nullptr;
305         containerTypeInfo = GetContainerType().GetContainerTypeInfo();
306     }
307     m_ContainerTypeInfo = containerTypeInfo;
308 
309     in.PushFrame(CObjectStackFrame::eFrameArray, containerTypeInfo);
310     in.BeginContainer(containerTypeInfo);
311 
312     TTypeInfo elementTypeInfo = m_ElementTypeInfo =
313         containerTypeInfo->GetElementType();
314     in.PushFrame(CObjectStackFrame::eFrameArrayElement, elementTypeInfo);
315     BeginElement();
316     if ( m_State == eNoMoreElements ) {
317         in.PopFrame();
318         in.EndContainer();
319         in.PopFrame();
320         if (m_ContainerType.GetTypeFamily() == eTypeFamilyClass) {
321             in.EndNamedType();
322             in.PopFrame();
323         }
324     }
325 }
326 
~CIStreamContainerIterator(void)327 CIStreamContainerIterator::~CIStreamContainerIterator(void)
328 {
329     if ( Good() ) {
330         switch ( m_State ) {
331         case eNoMoreElements:
332             // normal state
333             return;
334         case eElementBegin:
335         case eElementEnd:
336             // not read element(s)
337             m_State = eError;
338             GetStream().SetFailFlags(CObjectIStream::fIllegalCall,
339                 "not all elements read");
340             break;
341         default:
342             // error -> do nothing
343             return;
344         }
345     }
346 }
347 
348 inline
CheckState(EState state)349 void CIStreamContainerIterator::CheckState(EState state)
350 {
351     bool ok = (m_State == state);
352     if ( !ok ) {
353         m_State = eError;
354         BadState();
355     }
356 }
357 
358 
NextElement(void)359 void CIStreamContainerIterator::NextElement(void)
360 {
361     CheckState(eElementBegin);
362     GetStream().EndContainerElement();
363     m_State = eElementEnd;
364     BeginElement();
365     if ( m_State == eNoMoreElements ) {
366         GetStream().PopFrame();
367         GetStream().EndContainer();
368         GetStream().PopFrame();
369         if (m_ContainerType.GetTypeFamily() == eTypeFamilyClass) {
370             GetStream().EndNamedType();
371             GetStream().PopFrame();
372         }
373     }
374     if (m_State != eNoMoreElements) {
375         m_State = eElementEnd;
376     }
377 }
378 
379 inline
BeginElementData(void)380 void CIStreamContainerIterator::BeginElementData(void)
381 {
382     CheckState(eElementBegin);
383 }
384 
385 inline
BeginElementData(const CObjectTypeInfo &)386 void CIStreamContainerIterator::BeginElementData(const CObjectTypeInfo& )
387 {
388     //if ( elementType.GetTypeInfo() != GetElementTypeInfo() )
389     //    IllegalCall("wrong element type");
390     BeginElementData();
391 }
392 
ReadElement(TObjectPtr container)393 CObjectInfo CIStreamContainerIterator::ReadElement(TObjectPtr container)
394 {
395     BeginElementData(GetElementType());
396     TObjectPtr cont = m_Container ? m_Container->GetItemPtr(container) : container;
397     TObjectPtr elem = m_ContainerTypeInfo->AddElement(cont, GetStream());
398     NextElement();
399     return CObjectInfo(elem, m_ElementTypeInfo);
400 }
401 
ReadElement(const CObjectInfo & element)402 void CIStreamContainerIterator::ReadElement(const CObjectInfo& element)
403 {
404     BeginElementData(element);
405     GetStream().ReadSeparateObject(element);
406     NextElement();
407 }
408 
SkipElement(const CObjectTypeInfo & elementType)409 void CIStreamContainerIterator::SkipElement(const CObjectTypeInfo& elementType)
410 {
411     BeginElementData(elementType);
412     GetStream().SkipObject(elementType.GetTypeInfo());
413     NextElement();
414 }
415 
SkipElement(void)416 void CIStreamContainerIterator::SkipElement(void)
417 {
418     BeginElementData();
419     GetStream().SkipObject(m_ElementTypeInfo);
420     NextElement();
421 }
422 
CopyElement(CObjectStreamCopier & copier,COStreamContainer & out)423 void CIStreamContainerIterator::CopyElement(CObjectStreamCopier& copier,
424                                             COStreamContainer& out)
425 {
426     BeginElementData();
427     out.GetStream().BeginContainerElement(m_ElementTypeInfo);
428     copier.CopyObject(m_ElementTypeInfo);
429     out.GetStream().EndContainerElement();
430     NextElement();
431 }
432 
operator ++(void)433 CIStreamContainerIterator& CIStreamContainerIterator::operator++(void)
434 {
435     if (m_State == eElementBegin) {
436         SkipElement();
437     }
438     if (m_State != eNoMoreElements) {
439         CheckState(eElementEnd);
440         m_State = eElementBegin;
441     }
442     else {
443         m_State = eFinished;
444     }
445     return *this;
446 }
447 
448 
COStreamContainer(CObjectOStream & out,const CObjectTypeInfo & containerType)449 COStreamContainer::COStreamContainer(CObjectOStream& out,
450                                      const CObjectTypeInfo& containerType)
451     : CParent(out), m_ContainerType(containerType)
452 {
453     const CContainerTypeInfo* containerTypeInfo;
454     if (m_ContainerType.GetTypeFamily() == eTypeFamilyClass) {
455         const CClassTypeInfo* classType =
456             CTypeConverter<CClassTypeInfo>::SafeCast(m_ContainerType.GetTypeInfo());
457         const CItemInfo* itemInfo =
458             classType->GetItems().GetItemInfo(classType->GetItems().FirstIndex());
459         _ASSERT(itemInfo->GetTypeInfo()->GetTypeFamily() == eTypeFamilyContainer);
460         containerTypeInfo =
461             CTypeConverter<CContainerTypeInfo>::SafeCast(itemInfo->GetTypeInfo());
462         out.PushFrame(CObjectStackFrame::eFrameNamed, m_ContainerType.GetTypeInfo());
463         out.BeginNamedType(m_ContainerType.GetTypeInfo());
464     } else {
465         containerTypeInfo = GetContainerType().GetContainerTypeInfo();
466     }
467     out.PushFrame(CObjectStackFrame::eFrameArray, containerTypeInfo);
468     out.BeginContainer(containerTypeInfo);
469 
470     TTypeInfo elementTypeInfo = m_ElementTypeInfo =
471         containerTypeInfo->GetElementType();
472     out.PushFrame(CObjectStackFrame::eFrameArrayElement, elementTypeInfo);
473 }
474 
~COStreamContainer(void)475 COStreamContainer::~COStreamContainer(void)
476 {
477     if ( Good() ) {
478         try {
479             GetStream().PopFrame();
480             GetStream().EndContainer();
481             GetStream().PopFrame();
482             if (m_ContainerType.GetTypeFamily() == eTypeFamilyClass) {
483                 GetStream().EndNamedType();
484                 GetStream().PopFrame();
485             }
486         }
487         catch (...) {
488             GetStream().SetFailFlags(CObjectOStream::fIllegalCall,
489                 "container write error");
490         }
491     }
492 }
493 
WriteElement(const CConstObjectInfo & element)494 void COStreamContainer::WriteElement(const CConstObjectInfo& element)
495 {
496     GetStream().BeginContainerElement(m_ElementTypeInfo);
497     GetStream().WriteSeparateObject(element);
498     GetStream().EndContainerElement();
499 }
500 
WriteElement(CObjectStreamCopier & copier,CObjectIStream &)501 void COStreamContainer::WriteElement(CObjectStreamCopier& copier,
502                                      CObjectIStream& /*in*/)
503 {
504     GetStream().BeginContainerElement(m_ElementTypeInfo);
505     copier.CopyObject(m_ElementTypeInfo);
506     GetStream().EndContainerElement();
507 }
508 
509 
510 END_NCBI_SCOPE
511