1 /*  $Id: serialobject.cpp 554977 2018-01-11 14:18:53Z 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:  Aleksey Grichenko
27 *
28 * File Description:
29 *   Base class for serializable objects
30 *
31 */
32 
33 #include <ncbi_pch.hpp>
34 #include <corelib/ncbi_safe_static.hpp>
35 #include <corelib/ncbimtx.hpp>
36 #include <corelib/ncbithr.hpp>
37 #include <corelib/ncbi_param.hpp>
38 #include <serial/serialbase.hpp>
39 #include <serial/typeinfo.hpp>
40 
41 #include <serial/objostr.hpp>
42 #include <serial/objistr.hpp>
43 #include <serial/objostrxml.hpp>
44 #include <serial/objistrxml.hpp>
45 
46 #include <serial/impl/classinfob.hpp>
47 #include <serial/error_codes.hpp>
48 
49 
50 #define NCBI_USE_ERRCODE_X   Serial_Core
51 
52 
53 BEGIN_NCBI_SCOPE
54 
IsSameTypeInfo(const CSerialObject & obj1,const CSerialObject & obj2)55 static bool IsSameTypeInfo( const CSerialObject& obj1,
56                             const CSerialObject& obj2 )
57 {
58     TTypeInfo type1 = obj1.GetThisTypeInfo();
59     while (type1->GetTypeFamily() == eTypeFamilyPointer) {
60         const CPointerTypeInfo* t = dynamic_cast<const CPointerTypeInfo*>(type1);
61         type1 = t->GetPointedType();
62     }
63     TTypeInfo type2 = obj2.GetThisTypeInfo();
64     while (type2->GetTypeFamily() == eTypeFamilyPointer) {
65         const CPointerTypeInfo* t = dynamic_cast<const CPointerTypeInfo*>(type2);
66         type2 = t->GetPointedType();
67     }
68     return (type1 == type2);
69 }
70 
71 
CSerialObject(void)72 CSerialObject::CSerialObject(void)
73 {
74 }
75 
~CSerialObject()76 CSerialObject::~CSerialObject()
77 {
78 }
79 
Assign(const CSerialObject & source,ESerialRecursionMode how)80 void CSerialObject::Assign(const CSerialObject& source, ESerialRecursionMode how)
81 {
82     if (this == &source) {
83         ERR_POST_X(3, Warning <<
84             "CSerialObject::Assign(): an attempt to assign a serial object to itself");
85         return;
86     }
87     if ( typeid(source) != typeid(*this) && !IsSameTypeInfo(source, *this) ) {
88         string msg("Assignment of incompatible types: ");
89         msg += typeid(*this).name();
90         msg += " = ";
91         msg += typeid(source).name();
92         NCBI_THROW(CSerialException,eIllegalCall, msg);
93     }
94     GetThisTypeInfo()->Assign(this, &source, how);
95 }
96 
97 
Equals(const CSerialObject & object,ESerialRecursionMode how) const98 bool CSerialObject::Equals(const CSerialObject& object, ESerialRecursionMode how) const
99 {
100     if ( typeid(object) != typeid(*this)  && !IsSameTypeInfo(object, *this) ) {
101         string msg("Cannot compare types: ");
102         msg += typeid(*this).name();
103         msg += " == ";
104         msg += typeid(object).name();
105         NCBI_THROW(CSerialException,eIllegalCall, msg);
106     }
107     return GetThisTypeInfo()->Equals(this, &object, how);
108 }
109 
DebugDump(CDebugDumpContext ddc,unsigned int depth) const110 void CSerialObject::DebugDump(CDebugDumpContext ddc, unsigned int depth) const
111 {
112     ddc.SetFrame("CSerialObject");
113     CObject::DebugDump( ddc, depth);
114 // this is not good, but better than nothing
115     CNcbiOstrstream ostr;
116     ostr << "\n****** begin ASN dump ******\n";
117     {{
118         unique_ptr<CObjectOStream> oos(CObjectOStream::Open(eSerial_AsnText,
119                                                           ostr));
120         oos->SetAutoSeparator(false);
121         oos->SetVerifyData(eSerialVerifyData_No);
122         oos->Write(this, GetThisTypeInfo());
123     }}
124     ostr << "\n****** end   ASN dump ******\n";
125     ddc.Log( "Serial_AsnText", CNcbiOstrstreamToString(ostr));
126 }
127 
128 /////////////////////////////////////////////////////////////////////////////
129 // data verification setup
130 
131 const char* CSerialObject::ms_UnassignedStr = "<*unassigned*>";
132 const char  CSerialObject::ms_UnassignedByte = char(0xcd);
133 
NCBI_PARAM_ENUM_ARRAY(ESerialVerifyData,SERIAL,VERIFY_DATA_GET)134 NCBI_PARAM_ENUM_ARRAY(ESerialVerifyData, SERIAL, VERIFY_DATA_GET)
135 {
136     {"NO",              eSerialVerifyData_No},
137     {"NEVER",           eSerialVerifyData_Never},
138     {"YES",             eSerialVerifyData_Yes},
139     {"ALWAYS",          eSerialVerifyData_Always},
140     {"DEFVALUE",        eSerialVerifyData_DefValue},
141     {"DEFVALUE_ALWAYS", eSerialVerifyData_DefValueAlways}
142 };
143 NCBI_PARAM_ENUM_DECL(ESerialVerifyData, SERIAL, VERIFY_DATA_GET);
144 NCBI_PARAM_ENUM_DEF(ESerialVerifyData, SERIAL, VERIFY_DATA_GET, eSerialVerifyData_Default);
145 typedef NCBI_PARAM_TYPE(SERIAL, VERIFY_DATA_GET) TSerialVerifyData;
146 
147 
SetVerifyDataThread(ESerialVerifyData verify)148 void CSerialObject::SetVerifyDataThread(ESerialVerifyData verify)
149 {
150     ESerialVerifyData now = TSerialVerifyData::GetThreadDefault();
151     if (now != eSerialVerifyData_Never &&
152         now != eSerialVerifyData_Always &&
153         now != eSerialVerifyData_DefValueAlways) {
154         if (verify == eSerialVerifyData_Default) {
155             TSerialVerifyData::ResetThreadDefault();
156         } else {
157             TSerialVerifyData::SetThreadDefault(verify);
158         }
159     }
160 }
161 
SetVerifyDataGlobal(ESerialVerifyData verify)162 void CSerialObject::SetVerifyDataGlobal(ESerialVerifyData verify)
163 {
164     ESerialVerifyData now = TSerialVerifyData::GetDefault();
165     if (now != eSerialVerifyData_Never &&
166         now != eSerialVerifyData_Always &&
167         now != eSerialVerifyData_DefValueAlways) {
168         if (verify == eSerialVerifyData_Default) {
169             TSerialVerifyData::ResetDefault();
170         } else {
171             TSerialVerifyData::SetDefault(verify);
172         }
173     }
174 }
175 
x_GetVerifyData(void)176 ESerialVerifyData CSerialObject::x_GetVerifyData(void)
177 {
178     ESerialVerifyData now = TSerialVerifyData::GetThreadDefault();
179     if (now == eSerialVerifyData_Default) {
180         now = TSerialVerifyData::GetDefault();
181         if (now == eSerialVerifyData_Default) {
182 // this is to provide compatibility with old implementation
183             const char* str = getenv(SERIAL_VERIFY_DATA_GET);
184             if (str) {
185                 if (NStr::CompareNocase(str,"YES") == 0) {
186                     now = eSerialVerifyData_Yes;
187                 } else if (NStr::CompareNocase(str,"NO") == 0) {
188                     now = eSerialVerifyData_No;
189                 } else if (NStr::CompareNocase(str,"NEVER") == 0) {
190                     now = eSerialVerifyData_Never;
191                 } else  if (NStr::CompareNocase(str,"ALWAYS") == 0) {
192                     now = eSerialVerifyData_Always;
193                 } else  if (NStr::CompareNocase(str,"DEFVALUE") == 0) {
194                     now = eSerialVerifyData_DefValue;
195                 } else  if (NStr::CompareNocase(str,"DEFVALUE_ALWAYS") == 0) {
196                     now = eSerialVerifyData_DefValueAlways;
197                 }
198             }
199         }
200     }
201     switch (now) {
202     default:
203     case eSerialVerifyData_Default:
204         break;
205     case eSerialVerifyData_No:
206     case eSerialVerifyData_Never:
207         return eSerialVerifyData_No;
208     case eSerialVerifyData_Yes:
209     case eSerialVerifyData_Always:
210         return eSerialVerifyData_Yes;
211     case eSerialVerifyData_DefValue:
212     case eSerialVerifyData_DefValueAlways:
213         return eSerialVerifyData_No;
214     }
215     // change the default here, if you like
216     return eSerialVerifyData_Yes;
217 }
218 
219 BEGIN_LOCAL_NAMESPACE;
220 
221 struct SPrintIdentifier
222 {
SPrintIdentifierSPrintIdentifier223     SPrintIdentifier(const CTempString& s) : m_String(s) { }
224     CTempString m_String;
225 };
operator <<(CNcbiOstream & out,SPrintIdentifier s)226 CNcbiOstream& operator<<(CNcbiOstream& out, SPrintIdentifier s)
227 {
228     SIZE_TYPE size = s.m_String.size();
229     SIZE_TYPE e_pos = NPOS;
230     if ( size > 2 && NStr::EndsWith(s.m_String, ".E") ) {
231         e_pos = s.m_String.rfind('.', size-3);
232         if ( e_pos != NPOS ) {
233             size -= 2;
234         }
235     }
236     bool capitalize = true;
237     for ( SIZE_TYPE i = 0; i < size; ++i ) {
238         char c = s.m_String[i];
239         if ( c == '.' ) {
240             out << "::C_";
241             if ( i == e_pos ) {
242                 out << "E_";
243             }
244             capitalize = true;
245         }
246         else {
247             if ( c == '-' ) {
248                 c = '_';
249             }
250             if ( capitalize ) {
251                 c = (char)toupper((unsigned char)c);
252                 capitalize = false;
253             }
254             out << c;
255         }
256     }
257     return out;
258 }
259 
260 END_LOCAL_NAMESPACE;
261 
ThrowUnassigned(TMemberIndex index,const char * file_name,int file_line) const262 void CSerialObject::ThrowUnassigned(TMemberIndex index,
263                                     const char* file_name,
264                                     int file_line) const
265 {
266     if (x_GetVerifyData() == eSerialVerifyData_Yes) {
267         const CTypeInfo* type = GetThisTypeInfo();
268         const CClassTypeInfoBase* classtype =
269             dynamic_cast<const CClassTypeInfoBase*>(type);
270         // offset index as the argument is zero based but items are 1 based
271         string member_name;
272         if ( classtype ) {
273             index += classtype->GetItems().FirstIndex();
274             if ( index >= classtype->GetItems().FirstIndex() &&
275                  index <= classtype->GetItems().LastIndex() ) {
276                 member_name = classtype->GetItems().GetItemInfo(index)->GetId().GetName();
277             }
278         }
279         CNcbiOstrstream s;
280         if ( true ) {
281             // make class name
282             s << "C" << SPrintIdentifier(type->GetAccessName());
283         }
284         if ( !member_name.empty() ) {
285             // make method name
286             s << "::Get" << SPrintIdentifier(member_name) << "()";
287         }
288         s << ": Attempt to get unassigned member "
289           << type->GetAccessModuleName() <<"::"<< type->GetAccessName() << '.';
290         if ( !member_name.empty() ) {
291             s << member_name;
292         } else {
293             s << '[' << index << ']';
294         }
295 // set temporary diag compile info to use argument file name and line
296 #undef DIAG_COMPILE_INFO
297 #define DIAG_COMPILE_INFO                                               \
298         NCBI_NS_NCBI::CDiagCompileInfo(file_name? file_name: __FILE__,  \
299                                        file_line? file_line: __LINE__,  \
300                                        NCBI_CURRENT_FUNCTION,           \
301                                        NCBI_MAKE_MODULE(NCBI_MODULE))
302         NCBI_THROW(CUnassignedMember,eGet,CNcbiOstrstreamToString(s));
303 // restore original diag compile info definition
304 #undef DIAG_COMPILE_INFO
305 #define DIAG_COMPILE_INFO                                               \
306         NCBI_NS_NCBI::CDiagCompileInfo(__FILE__,                        \
307                                        __LINE__,                        \
308                                        NCBI_CURRENT_FUNCTION,           \
309                                        NCBI_MAKE_MODULE(NCBI_MODULE))
310     }
311 }
312 
ThrowUnassigned(TMemberIndex index) const313 void CSerialObject::ThrowUnassigned(TMemberIndex index) const
314 {
315     ThrowUnassigned(index, 0, 0);
316 }
317 
HasNamespaceName(void) const318 bool CSerialObject::HasNamespaceName(void) const
319 {
320     return GetThisTypeInfo()->HasNamespaceName();
321 }
322 
GetNamespaceName(void) const323 const string& CSerialObject::GetNamespaceName(void) const
324 {
325     return GetThisTypeInfo()->GetNamespaceName();
326 }
327 
HasNamespacePrefix(void) const328 bool CSerialObject::HasNamespacePrefix(void) const
329 {
330     return GetThisTypeInfo()->HasNamespacePrefix();
331 }
332 
GetNamespacePrefix(void) const333 const string& CSerialObject::GetNamespacePrefix(void) const
334 {
335     return GetThisTypeInfo()->GetNamespacePrefix();
336 }
337 
338 
CSerialAttribInfoItem(const string & name,const string & ns_name,const CStringUTF8 & value)339 CSerialAttribInfoItem::CSerialAttribInfoItem(
340     const string& name, const string& ns_name, const CStringUTF8& value)
341     : m_Name(name), m_NsName(ns_name), m_Value(value)
342 {
343 }
CSerialAttribInfoItem(const CSerialAttribInfoItem & other)344 CSerialAttribInfoItem::CSerialAttribInfoItem(const CSerialAttribInfoItem& other)
345     : m_Name(other.m_Name), m_NsName(other.m_NsName), m_Value(other.m_Value)
346 {
347 }
348 
~CSerialAttribInfoItem(void)349 CSerialAttribInfoItem::~CSerialAttribInfoItem(void)
350 {
351 }
GetName(void) const352 const string& CSerialAttribInfoItem::GetName(void) const
353 {
354     return m_Name;
355 }
GetNamespaceName(void) const356 const string& CSerialAttribInfoItem::GetNamespaceName(void) const
357 {
358     return m_NsName;
359 }
GetValue(void) const360 const CStringUTF8& CSerialAttribInfoItem::GetValue(void) const
361 {
362     return m_Value;
363 }
364 
365 
CAnyContentObject(void)366 CAnyContentObject::CAnyContentObject(void)
367 {
368 }
369 
CAnyContentObject(const CAnyContentObject & other)370 CAnyContentObject::CAnyContentObject(const CAnyContentObject& other)
371 {
372     x_Copy(other);
373 }
374 
~CAnyContentObject(void)375 CAnyContentObject::~CAnyContentObject(void)
376 {
377 }
378 
GetTypeInfo(void)379 const CTypeInfo* CAnyContentObject::GetTypeInfo(void)
380 {
381     return CStdTypeInfo<ncbi::CAnyContentObject>::GetTypeInfo();
382 }
383 
Reset(void)384 void CAnyContentObject::Reset(void)
385 {
386     m_Name.erase();
387     m_Value.erase();
388     m_NsName.erase();
389     m_NsPrefix.erase();
390     m_Attlist.clear();
391 }
392 
x_Copy(const CAnyContentObject & other)393 void CAnyContentObject::x_Copy(const CAnyContentObject& other)
394 {
395     m_Name = other.m_Name;
396     m_Value= other.m_Value;
397     m_NsName= other.m_NsName;
398     m_NsPrefix= other.m_NsPrefix;
399     m_Attlist.clear();
400     vector<CSerialAttribInfoItem>::const_iterator it;
401     for (it = other.m_Attlist.begin(); it != other.m_Attlist.end(); ++it) {
402         m_Attlist.push_back( *it);
403     }
404 }
operator =(const CAnyContentObject & other)405 CAnyContentObject& CAnyContentObject::operator= (const CAnyContentObject& other)
406 {
407     x_Copy(other);
408     return *this;
409 }
410 
operator ==(const CAnyContentObject & other) const411 bool CAnyContentObject::operator== (const CAnyContentObject& other) const
412 {
413     return m_Name == other.GetName() &&
414            m_Value == other.GetValue() &&
415            m_NsName == other.m_NsName;
416 }
417 
SetName(const string & name)418 void CAnyContentObject::SetName(const string& name)
419 {
420     m_Name = name;
421 }
GetName(void) const422 const string& CAnyContentObject::GetName(void) const
423 {
424     return m_Name;
425 }
SetValue(const CStringUTF8 & value)426 void CAnyContentObject::SetValue(const CStringUTF8& value)
427 {
428     x_Decode(value);
429 }
GetValue(void) const430 const CStringUTF8& CAnyContentObject::GetValue(void) const
431 {
432     return m_Value;
433 }
SetNamespaceName(const string & ns_name)434 void CAnyContentObject::SetNamespaceName(const string& ns_name)
435 {
436     m_NsName = ns_name;
437 }
GetNamespaceName(void) const438 const string& CAnyContentObject::GetNamespaceName(void) const
439 {
440     return m_NsName;
441 }
SetNamespacePrefix(const string & ns_prefix)442 void CAnyContentObject::SetNamespacePrefix(const string& ns_prefix)
443 {
444     m_NsPrefix = ns_prefix;
445 }
GetNamespacePrefix(void) const446 const string& CAnyContentObject::GetNamespacePrefix(void) const
447 {
448     return m_NsPrefix;
449 }
x_Decode(const CStringUTF8 & value)450 void CAnyContentObject::x_Decode(const CStringUTF8& value)
451 {
452     m_Value = value;
453 }
AddAttribute(const string & name,const string & ns_name,const CStringUTF8 & value)454 void CAnyContentObject::AddAttribute(
455     const string& name, const string& ns_name, const CStringUTF8& value)
456 {
457 // TODO: check if an attrib with this name+ns_name already exists
458     m_Attlist.push_back( CSerialAttribInfoItem( name,ns_name,value));
459 }
460 
461 const vector<CSerialAttribInfoItem>&
GetAttributes(void) const462 CAnyContentObject::GetAttributes(void) const
463 {
464     return m_Attlist;
465 }
466 
467 /////////////////////////////////////////////////////////////////////////////
468 //  I/O stream manipulators and helpers for serializable objects
469 
470 #define  eFmt_AsnText     (1l <<  0)
471 #define  eFmt_AsnBinary   (1l <<  1)
472 #define  eFmt_Xml         (1l <<  2)
473 #define  eFmt_Json        (1l <<  3)
474 #define  eFmt_All         (eFmt_AsnText | eFmt_AsnBinary | eFmt_Xml | eFmt_Json)
475 
476 #define  eVerify_No       (1l <<  8)
477 #define  eVerify_Yes      (1l <<  9)
478 #define  eVerify_DefValue (1l << 10)
479 #define  eVerify_All      (eVerify_No | eVerify_Yes | eVerify_DefValue)
480 
481 #define  eSkipUnkMembers_No    (1l <<  11)
482 #define  eSkipUnkMembers_Yes   (1l <<  12)
483 #define  eSkipUnkMembers_All   (eSkipUnkMembers_No  | eSkipUnkMembers_Yes)
484 
485 #define  eSkipUnkVariants_No   (1l <<  13)
486 #define  eSkipUnkVariants_Yes  (1l <<  14)
487 #define  eSkipUnkVariants_All  (eSkipUnkVariants_No | eSkipUnkVariants_Yes)
488 
489 #define  eEncoding_All    (255l << 16)
490 #define  eFmtFlags_All    (255l << 24)
491 
492 static
s_SerFlags(CNcbiIos & io)493 long& s_SerFlags(CNcbiIos& io)
494 {
495     static int s_SerIndex;
496     static bool s_HaveIndex = false;
497 
498     if ( !s_HaveIndex ) {
499         // Make sure to get a unique IOS index
500         DEFINE_STATIC_FAST_MUTEX(s_IndexMutex);
501         CFastMutexGuard guard(s_IndexMutex);
502         if ( !s_HaveIndex ) {
503             s_SerIndex = CNcbiIos::xalloc();
504             s_HaveIndex = true;
505         }
506     }
507 
508     return io.iword(s_SerIndex);
509 }
510 static
s_FlagsToFormat(CNcbiIos & io)511 ESerialDataFormat s_FlagsToFormat(CNcbiIos& io)
512 {
513     switch (s_SerFlags(io) & eFmt_All) {
514     case eFmt_AsnText:     return eSerial_AsnText;
515     case eFmt_AsnBinary:   return eSerial_AsnBinary;
516     case eFmt_Xml:         return eSerial_Xml;
517     case eFmt_Json:        return eSerial_Json;
518     default:               return eSerial_None;
519     }
520 }
521 static
s_FormatToFlags(ESerialDataFormat fmt)522 long s_FormatToFlags(ESerialDataFormat fmt)
523 {
524     switch (fmt) {
525     case eSerial_AsnText:    return eFmt_AsnText;
526     case eSerial_AsnBinary:  return eFmt_AsnBinary;
527     case eSerial_Xml:        return eFmt_Xml;
528     case eSerial_Json:       return eFmt_Json;
529     default:                 return 0;
530     }
531 }
532 
533 static
s_FlagsToVerify(CNcbiIos & io)534 ESerialVerifyData s_FlagsToVerify(CNcbiIos& io)
535 {
536     switch (s_SerFlags(io) & eVerify_All) {
537     case eVerify_No:       return eSerialVerifyData_No;
538     case eVerify_Yes:      return eSerialVerifyData_Yes;
539     case eVerify_DefValue: return eSerialVerifyData_DefValue;
540     default:               return eSerialVerifyData_Default;
541     }
542 }
543 
544 static
s_VerifyToFlags(ESerialVerifyData fmt)545 long s_VerifyToFlags(ESerialVerifyData fmt)
546 {
547     switch (fmt) {
548     case eSerialVerifyData_Never:
549     case eSerialVerifyData_No:       return eVerify_No;
550     case eSerialVerifyData_Always:
551     case eSerialVerifyData_Yes:      return eVerify_Yes;
552     case eSerialVerifyData_DefValueAlways:
553     case eSerialVerifyData_DefValue: return eVerify_DefValue;
554     default:                         return 0;
555     }
556 }
557 
558 static
s_FlagsToSkipUnkMembers(CNcbiIos & io)559 ESerialSkipUnknown s_FlagsToSkipUnkMembers(CNcbiIos& io)
560 {
561     switch (s_SerFlags(io) & eSkipUnkMembers_All) {
562     case eSkipUnkMembers_No:   return eSerialSkipUnknown_No;
563     case eSkipUnkMembers_Yes:  return eSerialSkipUnknown_Yes;
564     default:                   return eSerialSkipUnknown_Default;
565     }
566 }
567 
568 static
s_SkipUnkMembersToFlags(ESerialSkipUnknown fmt)569 long s_SkipUnkMembersToFlags(ESerialSkipUnknown fmt)
570 {
571     switch (fmt) {
572     case eSerialSkipUnknown_Never:
573     case eSerialSkipUnknown_No:      return eSkipUnkMembers_No;
574     case eSerialSkipUnknown_Always:
575     case eSerialSkipUnknown_Yes:     return eSkipUnkMembers_Yes;
576     default:                         return 0;
577     }
578 }
579 static
s_FlagsToSkipUnkVariants(CNcbiIos & io)580 ESerialSkipUnknown s_FlagsToSkipUnkVariants(CNcbiIos& io)
581 {
582     switch (s_SerFlags(io) & eSkipUnkVariants_All) {
583     case eSkipUnkVariants_No:  return eSerialSkipUnknown_No;
584     case eSkipUnkVariants_Yes: return eSerialSkipUnknown_Yes;
585     default:                   return eSerialSkipUnknown_Default;
586     }
587 }
588 
589 static
s_SkipUnkVariantsToFlags(ESerialSkipUnknown fmt)590 long s_SkipUnkVariantsToFlags(ESerialSkipUnknown fmt)
591 {
592     switch (fmt) {
593     case eSerialSkipUnknown_Never:
594     case eSerialSkipUnknown_No:      return eSkipUnkVariants_No;
595     case eSerialSkipUnknown_Always:
596     case eSerialSkipUnknown_Yes:     return eSkipUnkVariants_Yes;
597     default:                         return 0;
598     }
599 }
600 
601 static
s_FlagsToEncoding(CNcbiIos & io)602 EEncoding s_FlagsToEncoding(CNcbiIos& io)
603 {
604     long enc = (s_SerFlags(io) & eEncoding_All) >> 16;
605     switch (enc) {
606     default: return eEncoding_Unknown;
607     case 1:  return eEncoding_UTF8;
608     case 2:  return eEncoding_Ascii;
609     case 3:  return eEncoding_ISO8859_1;
610     case 4:  return eEncoding_Windows_1252;
611     }
612 }
613 
614 static
s_EncodingToFlags(EEncoding fmt)615 long s_EncodingToFlags(EEncoding fmt)
616 {
617     long enc = 0;
618     switch (fmt) {
619     default:                     enc = 0; break;
620     case eEncoding_UTF8:         enc = 1; break;
621     case eEncoding_Ascii:        enc = 2; break;
622     case eEncoding_ISO8859_1:    enc = 3; break;
623     case eEncoding_Windows_1252: enc = 4; break;
624     }
625     return (enc << 16);
626 }
627 
628 static
s_FlagsToFormatFlags(CNcbiIos & io)629 TSerial_Format_Flags s_FlagsToFormatFlags(CNcbiIos& io)
630 {
631     TSerial_Format_Flags t = (TSerial_Format_Flags)(s_SerFlags(io) & eFmtFlags_All);
632     return t >> 24;
633 }
634 
635 static
s_FormatFlagsToFlags(unsigned long flags)636 long s_FormatFlagsToFlags(unsigned long flags)
637 {
638     return flags << 24;
639 }
640 
HasSerialFormatting(CNcbiIos & io)641 bool MSerial_Flags::HasSerialFormatting(CNcbiIos& io)
642 {
643     return s_FlagsToFormat(io) != eSerial_None;
644 }
645 
MSerial_Flags(unsigned long all,unsigned long flags)646 MSerial_Flags::MSerial_Flags(unsigned long all, unsigned long flags)
647     : m_All(all), m_Flags(flags)
648 {
649 }
SetFlags(CNcbiIos & io) const650 void MSerial_Flags::SetFlags(CNcbiIos& io) const
651 {
652     s_SerFlags(io) = (s_SerFlags(io) & ~m_All) | m_Flags;
653 }
654 
SetFormatFlags(unsigned long flags)655 void MSerial_Flags::SetFormatFlags(unsigned long flags)
656 {
657     m_Flags = (m_Flags & ~eFmtFlags_All) | s_FormatFlagsToFlags(flags);
658 }
659 
MSerial_Format(ESerialDataFormat fmt,TSerial_Format_Flags flags)660 MSerial_Format::MSerial_Format(ESerialDataFormat fmt, TSerial_Format_Flags flags)
661     : MSerial_Flags(eFmt_All | eFmtFlags_All,
662         s_FormatToFlags(fmt) | s_FormatFlagsToFlags(flags))
663 {
664 }
665 
operator ()(TSerial_AsnText_Flags flags)666 MSerial_Format& MSerial_Format_AsnText::operator()(TSerial_AsnText_Flags flags)
667 {
668     SetFormatFlags(flags);
669     return *this;
670 }
operator ()(TSerial_Xml_Flags flags)671 MSerial_Format& MSerial_Format_Xml::operator()(TSerial_Xml_Flags flags)
672 {
673     SetFormatFlags(flags);
674     return *this;
675 }
operator ()(TSerial_Json_Flags flags)676 MSerial_Format& MSerial_Format_Json::operator()(TSerial_Json_Flags flags)
677 {
678     SetFormatFlags(flags);
679     return *this;
680 }
681 
MSerial_VerifyData(ESerialVerifyData fmt)682 MSerial_VerifyData::MSerial_VerifyData(ESerialVerifyData fmt)
683     : MSerial_Flags(eVerify_All, s_VerifyToFlags(fmt))
684 {
685 }
686 
MSerial_SkipUnknownMembers(ESerialSkipUnknown fmt)687 MSerial_SkipUnknownMembers::MSerial_SkipUnknownMembers(ESerialSkipUnknown fmt)
688     : MSerial_Flags(eSkipUnkMembers_All, s_SkipUnkMembersToFlags(fmt))
689 {
690 }
691 
MSerial_SkipUnknownVariants(ESerialSkipUnknown fmt)692 MSerial_SkipUnknownVariants::MSerial_SkipUnknownVariants(ESerialSkipUnknown fmt)
693     : MSerial_Flags(eSkipUnkVariants_All, s_SkipUnkVariantsToFlags(fmt))
694 {
695 }
696 
MSerialXml_DefaultStringEncoding(EEncoding fmt)697 MSerialXml_DefaultStringEncoding::MSerialXml_DefaultStringEncoding(EEncoding fmt)
698     : MSerial_Flags(eEncoding_All, s_EncodingToFlags(fmt))
699 {
700 }
701 
MSerial_None(CNcbiIos & io)702 CNcbiIos& MSerial_None(CNcbiIos& io)
703 {
704 //    s_SerFlags(io) = (s_SerFlags(io) & ~eFmt_All);
705     s_SerFlags(io) = 0;
706     return io;
707 }
708 
709 
710 // Class member assignment verification
MSerial_VerifyDefault(CNcbiIos & io)711 CNcbiIos& MSerial_VerifyDefault(CNcbiIos& io)
712 {
713     s_SerFlags(io) = (s_SerFlags(io) & ~eVerify_All);
714     return io;
715 }
MSerial_VerifyNo(CNcbiIos & io)716 CNcbiIos& MSerial_VerifyNo(CNcbiIos& io)
717 {
718     s_SerFlags(io) = (s_SerFlags(io) & ~eVerify_All) | eVerify_No;
719     return io;
720 }
MSerial_VerifyYes(CNcbiIos & io)721 CNcbiIos& MSerial_VerifyYes(CNcbiIos& io)
722 {
723     s_SerFlags(io) = (s_SerFlags(io) & ~eVerify_All) | eVerify_Yes;
724     return io;
725 }
MSerial_VerifyDefValue(CNcbiIos & io)726 CNcbiIos& MSerial_VerifyDefValue(CNcbiIos& io)
727 {
728     s_SerFlags(io) = (s_SerFlags(io) & ~eVerify_All) | eVerify_DefValue;
729     return io;
730 }
731 
732 
733 // Input/output
operator <<(CNcbiOstream & os,const CSerialObject & obj)734 CNcbiOstream& operator<< (CNcbiOstream& os, const CSerialObject& obj)
735 {
736     return WriteObject(os,&obj,obj.GetThisTypeInfo());
737 }
738 
operator >>(CNcbiIstream & is,CSerialObject & obj)739 CNcbiIstream& operator>> (CNcbiIstream& is, CSerialObject& obj)
740 {
741     return ReadObject(is,&obj,obj.GetThisTypeInfo());
742 }
743 
operator <<(CNcbiOstream & os,const CConstObjectInfo & obj)744 CNcbiOstream& operator<< (CNcbiOstream& os, const CConstObjectInfo& obj)
745 {
746     return WriteObject(os,obj.GetObjectPtr(),obj.GetTypeInfo());
747 }
748 
operator >>(CNcbiIstream & is,const CObjectInfo & obj)749 CNcbiIstream& operator>> (CNcbiIstream& is, const CObjectInfo& obj)
750 {
751     return ReadObject(is,obj.GetObjectPtr(),obj.GetTypeInfo());
752 }
753 
WriteObject(CNcbiOstream & os,TConstObjectPtr ptr,TTypeInfo info)754 CNcbiOstream& WriteObject(CNcbiOstream& os, TConstObjectPtr ptr, TTypeInfo info)
755 {
756     unique_ptr<CObjectOStream> ostr( CObjectOStream::Open( s_FlagsToFormat(os), os) );
757     ostr->SetVerifyData( s_FlagsToVerify(os) );
758     ostr->SetFormattingFlags( s_FlagsToFormatFlags(os) );
759     if (ostr->GetDataFormat() == eSerial_Xml) {
760         dynamic_cast<CObjectOStreamXml*>(ostr.get())->
761             SetDefaultStringEncoding( s_FlagsToEncoding(os) );
762     }
763     ostr->Write(ptr,info);
764     return os;
765 }
ReadObject(CNcbiIstream & is,TObjectPtr ptr,TTypeInfo info)766 CNcbiIstream& ReadObject(CNcbiIstream& is, TObjectPtr ptr, TTypeInfo info)
767 {
768     unique_ptr<CObjectIStream> istr( CObjectIStream::Open(s_FlagsToFormat(is), is) );
769     istr->SetVerifyData(s_FlagsToVerify(is));
770     istr->SetSkipUnknownMembers( s_FlagsToSkipUnkMembers(is));
771     istr->SetSkipUnknownVariants( s_FlagsToSkipUnkVariants(is));
772     TSerial_Format_Flags f = s_FlagsToFormatFlags(is);
773     if (f != 0) {
774         ERR_POST_XX_ONCE(Serial_IStream, 9, Warning <<
775             "ReadObject: ignoring unknown formatting flags");
776     }
777     if (istr->GetDataFormat() == eSerial_Xml) {
778         dynamic_cast<CObjectIStreamXml*>(istr.get())->
779             SetDefaultStringEncoding( s_FlagsToEncoding(is) );
780     }
781     istr->Read(ptr,info);
782     return is;
783 }
784 
785 
786 END_NCBI_SCOPE
787