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