1/*
2Open Asset Import Library (assimp)
3----------------------------------------------------------------------
4
5Copyright (c) 2006-2017, assimp team
6
7All rights reserved.
8
9Redistribution and use of this software in source and binary forms,
10with or without modification, are permitted provided that the
11following conditions are met:
12
13* Redistributions of source code must retain the above
14 copyright notice, this list of conditions and the
15 following disclaimer.
16
17* Redistributions in binary form must reproduce the above
18 copyright notice, this list of conditions and the
19 following disclaimer in the documentation and/or other
20 materials provided with the distribution.
21
22* Neither the name of the assimp team, nor the names of its
23 contributors may be used to endorse or promote products
24 derived from this software without specific prior
25 written permission of the assimp team.
26
27THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
30A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
31OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
32SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
33LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
35THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
37OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38
39----------------------------------------------------------------------
40*/
41
42#ifndef INCLUDED_AI_STEPFILE_H
43#define INCLUDED_AI_STEPFILE_H
44
45#include <bitset>
46#include <memory>
47#include <typeinfo>
48#include <vector>
49#include <map>
50#include <set>
51
52#include "FBXDocument.h" //ObjectMap::value_type
53#include <assimp/DefaultLogger.hpp>
54
55//
56#if _MSC_VER > 1500 || (defined __GNUC___)
57# define ASSIMP_STEP_USE_UNORDERED_MULTIMAP
58#else
59# define step_unordered_map map
60# define step_unordered_multimap multimap
61#endif
62
63#ifdef ASSIMP_STEP_USE_UNORDERED_MULTIMAP
64# include <unordered_map>
65# if _MSC_VER > 1600
66# define step_unordered_map unordered_map
67# define step_unordered_multimap unordered_multimap
68# else
69# define step_unordered_map tr1::unordered_map
70# define step_unordered_multimap tr1::unordered_multimap
71# endif
72#endif
73
74#include "LineSplitter.h"
75
76// uncomment this to have the loader evaluate all entities upon loading.
77// this is intended as stress test - by default, entities are evaluated
78// lazily and therefore not unless needed.
79
80//#define ASSIMP_IFC_TEST
81
82namespace Assimp {
83
84// ********************************************************************************
85// before things get complicated, this is the basic outline:
86
87
88namespace STEP {
89
90 namespace EXPRESS {
91
92 // base data types known by EXPRESS schemata - any custom data types will derive one of those
93 class DataType;
94 class UNSET; /*: public DataType */
95 class ISDERIVED; /*: public DataType */
96 // class REAL; /*: public DataType */
97 class ENUM; /*: public DataType */
98 // class STRING; /*: public DataType */
99 // class INTEGER; /*: public DataType */
100 class ENTITY; /*: public DataType */
101 class LIST; /*: public DataType */
102 // class SELECT; /*: public DataType */
103
104 // a conversion schema is not exactly an EXPRESS schema, rather it
105 // is a list of pointers to conversion functions to build up the
106 // object tree from an input file.
107 class ConversionSchema;
108 }
109
110 struct HeaderInfo;
111 class Object;
112 class LazyObject;
113 class DB;
114
115
116 typedef Object* (*ConvertObjectProc)(const DB& db, const EXPRESS::LIST& params);
117}
118
119// ********************************************************************************
120
121namespace STEP {
122
123 // -------------------------------------------------------------------------------
124 /** Exception class used by the STEP loading & parsing code. It is typically
125 * coupled with a line number. */
126 // -------------------------------------------------------------------------------
127 struct SyntaxError : DeadlyImportError {
128 enum {
129 LINE_NOT_SPECIFIED = 0xffffffffffffffffLL
130 };
131
132 SyntaxError (const std::string& s,uint64_t line = LINE_NOT_SPECIFIED);
133 };
134
135
136 // -------------------------------------------------------------------------------
137 /** Exception class used by the STEP loading & parsing code when a type
138 * error (i.e. an entity expects a string but receives a bool) occurs.
139 * It is typically coupled with both an entity id and a line number.*/
140 // -------------------------------------------------------------------------------
141 struct TypeError : DeadlyImportError
142 {
143 enum {
144 ENTITY_NOT_SPECIFIED = 0xffffffffffffffffLL
145 };
146
147 TypeError (const std::string& s,uint64_t entity = ENTITY_NOT_SPECIFIED, uint64_t line = SyntaxError::LINE_NOT_SPECIFIED);
148 };
149
150
151 // hack to make a given member template-dependent
152 template <typename T, typename T2>
153 T2& Couple(T2& in) {
154 return in;
155 }
156
157
158 namespace EXPRESS {
159
160 // -------------------------------------------------------------------------------
161 //** Base class for all STEP data types */
162 // -------------------------------------------------------------------------------
163 class DataType
164 {
165 public:
166
167 typedef std::shared_ptr<const DataType> Out;
168
169 public:
170
171 virtual ~DataType() {
172 }
173
174 public:
175
176 template <typename T>
177 const T& To() const {
178 return dynamic_cast<const T&>(*this);
179 }
180
181 template <typename T>
182 T& To() {
183 return dynamic_cast<T&>(*this);
184 }
185
186
187 template <typename T>
188 const T* ToPtr() const {
189 return dynamic_cast<const T*>(this);
190 }
191
192 template <typename T>
193 T* ToPtr() {
194 return dynamic_cast<T*>(this);
195 }
196
197 // utilities to deal with SELECT entities, which currently lack automatic
198 // conversion support.
199 template <typename T>
200 const T& ResolveSelect(const DB& db) const {
201 return Couple<T>(db).MustGetObject(To<EXPRESS::ENTITY>())->template To<T>();
202 }
203
204 template <typename T>
205 const T* ResolveSelectPtr(const DB& db) const {
206 const EXPRESS::ENTITY* e = ToPtr<EXPRESS::ENTITY>();
207 return e?Couple<T>(db).MustGetObject(*e)->template ToPtr<T>():(const T*)0;
208 }
209
210 public:
211
212 /** parse a variable from a string and set 'inout' to the character
213 * behind the last consumed character. An optional schema enables,
214 * if specified, automatic conversion of custom data types.
215 *
216 * @throw SyntaxError
217 */
218 static std::shared_ptr<const EXPRESS::DataType> Parse(const char*& inout,
219 uint64_t line = SyntaxError::LINE_NOT_SPECIFIED,
220 const EXPRESS::ConversionSchema* schema = NULL);
221
222 public:
223 };
224
225 typedef DataType SELECT;
226 typedef DataType LOGICAL;
227
228 // -------------------------------------------------------------------------------
229 /** Sentinel class to represent explicitly unset (optional) fields ($) */
230 // -------------------------------------------------------------------------------
231 class UNSET : public DataType
232 {
233 public:
234 private:
235 };
236
237 // -------------------------------------------------------------------------------
238 /** Sentinel class to represent explicitly derived fields (*) */
239 // -------------------------------------------------------------------------------
240 class ISDERIVED : public DataType
241 {
242 public:
243 private:
244 };
245
246 // -------------------------------------------------------------------------------
247 /** Shared implementation for some of the primitive data type, i.e. int, float */
248 // -------------------------------------------------------------------------------
249 template <typename T>
250 class PrimitiveDataType : public DataType
251 {
252 public:
253
254 // This is the type that will cd ultimatively be used to
255 // expose this data type to the user.
256 typedef T Out;
257
258 public:
259
260 PrimitiveDataType() {}
261 PrimitiveDataType(const T& val)
262 : val(val)
263 {}
264
265 PrimitiveDataType(const PrimitiveDataType& o) {
266 (*this) = o;
267 }
268
269
270 public:
271
272 operator const T& () const {
273 return val;
274 }
275
276 PrimitiveDataType& operator=(const PrimitiveDataType& o) {
277 val = o.val;
278 return *this;
279 }
280
281 protected:
282 T val;
283
284 };
285
286 typedef PrimitiveDataType<int64_t> INTEGER;
287 typedef PrimitiveDataType<double> REAL;
288 typedef PrimitiveDataType<double> NUMBER;
289 typedef PrimitiveDataType<std::string> STRING;
290
291
292
293 // -------------------------------------------------------------------------------
294 /** Generic base class for all enumerated types */
295 // -------------------------------------------------------------------------------
296 class ENUMERATION : public STRING
297 {
298 public:
299
300 ENUMERATION (const std::string& val)
301 : STRING(val)
302 {}
303
304 private:
305 };
306
307 typedef ENUMERATION BOOLEAN;
308
309 // -------------------------------------------------------------------------------
310 /** This is just a reference to an entity/object somewhere else */
311 // -------------------------------------------------------------------------------
312 class ENTITY : public PrimitiveDataType<uint64_t>
313 {
314 public:
315
316 ENTITY(uint64_t val)
317 : PrimitiveDataType<uint64_t>(val)
318 {
319 ai_assert(val!=0);
320 }
321
322 ENTITY()
323 : PrimitiveDataType<uint64_t>(TypeError::ENTITY_NOT_SPECIFIED)
324 {
325 }
326
327 private:
328 };
329
330 // -------------------------------------------------------------------------------
331 /** Wrap any STEP aggregate: LIST, SET, ... */
332 // -------------------------------------------------------------------------------
333 class LIST : public DataType
334 {
335 public:
336
337 // access a particular list index, throw std::range_error for wrong indices
338 std::shared_ptr<const DataType> operator[] (size_t index) const {
339 return members[index];
340 }
341
342 size_t GetSize() const {
343 return members.size();
344 }
345
346 public:
347
348 /** @see DaraType::Parse */
349 static std::shared_ptr<const EXPRESS::LIST> Parse(const char*& inout,
350 uint64_t line = SyntaxError::LINE_NOT_SPECIFIED,
351 const EXPRESS::ConversionSchema* schema = NULL);
352
353
354 private:
355 typedef std::vector< std::shared_ptr<const DataType> > MemberList;
356 MemberList members;
357 };
358
359
360 // -------------------------------------------------------------------------------
361 /* Not exactly a full EXPRESS schema but rather a list of conversion functions
362 * to extract valid C++ objects out of a STEP file. Those conversion functions
363 * may, however, perform further schema validations. */
364 // -------------------------------------------------------------------------------
365 class ConversionSchema
366 {
367
368 public:
369
370 struct SchemaEntry {
371 SchemaEntry(const char* name,ConvertObjectProc func)
372 : name(name)
373 , func(func)
374 {}
375
376 const char* name;
377 ConvertObjectProc func;
378 };
379
380 typedef std::map<std::string,ConvertObjectProc> ConverterMap;
381
382 public:
383
384 template <size_t N>
385 explicit ConversionSchema( const SchemaEntry (& schemas)[N]) {
386 *this = schemas;
387 }
388
389 ConversionSchema() {}
390
391 public:
392
393 ConvertObjectProc GetConverterProc(const std::string& name) const {
394 ConverterMap::const_iterator it = converters.find(name);
395 return it == converters.end() ? NULL : (*it).second;
396 }
397
398
399 bool IsKnownToken(const std::string& name) const {
400 return converters.find(name) != converters.end();
401 }
402
403 const char* GetStaticStringForToken(const std::string& token) const {
404 ConverterMap::const_iterator it = converters.find(token);
405 return it == converters.end() ? NULL : (*it).first.c_str();
406 }
407
408
409 template <size_t N>
410 const ConversionSchema& operator=( const SchemaEntry (& schemas)[N]) {
411 for(size_t i = 0; i < N; ++i ) {
412 const SchemaEntry& schema = schemas[i];
413 converters[schema.name] = schema.func;
414 }
415 return *this;
416 }
417
418 private:
419
420 ConverterMap converters;
421 };
422 }
423
424
425
426 // ------------------------------------------------------------------------------
427 /** Bundle all the relevant info from a STEP header, parts of which may later
428 * be plainly dumped to the logfile, whereas others may help the caller pick an
429 * appropriate loading strategy.*/
430 // ------------------------------------------------------------------------------
431 struct HeaderInfo
432 {
433 std::string timestamp;
434 std::string app;
435 std::string fileSchema;
436 };
437
438
439 // ------------------------------------------------------------------------------
440 /** Base class for all concrete object instances */
441 // ------------------------------------------------------------------------------
442 class Object {
443 public:
444 Object(const char* classname = "unknown")
445 : id( 0 )
446 , classname(classname) {
447 // empty
448 }
449
450 virtual ~Object() {
451 // empty
452 }
453
454 public:
455
456 // utilities to simplify casting to concrete types
457 template <typename T>
458 const T& To() const {
459 return dynamic_cast<const T&>(*this);
460 }
461
462 template <typename T>
463 T& To() {
464 return dynamic_cast<T&>(*this);
465 }
466
467 template <typename T>
468 const T* ToPtr() const {
469 return dynamic_cast<const T*>(this);
470 }
471
472 template <typename T>
473 T* ToPtr() {
474 return dynamic_cast<T*>(this);
475 }
476
477 public:
478 uint64_t GetID() const {
479 return id;
480 }
481
482 std::string GetClassName() const {
483 return classname;
484 }
485
486 void SetID(uint64_t newval) {
487 id = newval;
488 }
489
490 private:
491 uint64_t id;
492 const char* const classname;
493 };
494
495 template <typename T>
496 size_t GenericFill(const STEP::DB& db, const EXPRESS::LIST& params, T* in);
497 // (intentionally undefined)
498
499
500 // ------------------------------------------------------------------------------
501 /** CRTP shared base class for use by concrete entity implementation classes */
502 // ------------------------------------------------------------------------------
503 template <typename TDerived, size_t arg_count>
504 struct ObjectHelper : virtual Object
505 {
506 ObjectHelper() : aux_is_derived(0) {}
507
508 static Object* Construct(const STEP::DB& db, const EXPRESS::LIST& params) {
509 // make sure we don't leak if Fill() throws an exception
510 std::unique_ptr<TDerived> impl(new TDerived());
511
512 // GenericFill<T> is undefined so we need to have a specialization
513 const size_t num_args = GenericFill<TDerived>(db,params,&*impl);
514 (void)num_args;
515
516 // the following check is commented because it will always trigger if
517 // parts of the entities are generated with dummy wrapper code.
518 // This is currently done to reduce the size of the loader
519 // code.
520 //if (num_args != params.GetSize() && impl->GetClassName() != "NotImplemented") {
521 // DefaultLogger::get()->debug("STEP: not all parameters consumed");
522 //}
523 return impl.release();
524 }
525
526 // note that this member always exists multiple times within the hierarchy
527 // of an individual object, so any access to it must be disambiguated.
528 std::bitset<arg_count> aux_is_derived;
529 };
530
531 // ------------------------------------------------------------------------------
532 /** Class template used to represent OPTIONAL data members in the converted schema */
533 // ------------------------------------------------------------------------------
534 template <typename T>
535 struct Maybe
536 {
537 Maybe() : have() {}
538 explicit Maybe(const T& ptr) : ptr(ptr), have(true) {
539 }
540
541
542 void flag_invalid() {
543 have = false;
544 }
545
546 void flag_valid() {
547 have = true;
548 }
549
550
551 bool operator! () const {
552 return !have;
553 }
554
555 operator bool() const {
556 return have;
557 }
558
559 operator const T&() const {
560 return Get();
561 }
562
563 const T& Get() const {
564 ai_assert(have);
565 return ptr;
566 }
567
568 Maybe& operator=(const T& _ptr) {
569 ptr = _ptr;
570 have = true;
571 return *this;
572 }
573
574 private:
575
576 template <typename T2> friend struct InternGenericConvert;
577
578 operator T&() {
579 return ptr;
580 }
581
582 T ptr;
583 bool have;
584 };
585
586 // ------------------------------------------------------------------------------
587 /** A LazyObject is created when needed. Before this happens, we just keep
588 the text line that contains the object definition. */
589 // -------------------------------------------------------------------------------
590 class LazyObject
591 {
592 friend class DB;
593 public:
594
595 LazyObject(DB& db, uint64_t id, uint64_t line, const char* type,const char* args);
596 ~LazyObject();
597
598 public:
599
600 Object& operator * () {
601 if (!obj) {
602 LazyInit();
603 ai_assert(obj);
604 }
605 return *obj;
606 }
607
608 const Object& operator * () const {
609 if (!obj) {
610 LazyInit();
611 ai_assert(obj);
612 }
613 return *obj;
614 }
615
616 template <typename T>
617 const T& To() const {
618 return dynamic_cast<const T&>( **this );
619 }
620
621 template <typename T>
622 T& To() {
623 return dynamic_cast<T&>( **this );
624 }
625
626 template <typename T>
627 const T* ToPtr() const {
628 return dynamic_cast<const T*>( &**this );
629 }
630
631 template <typename T>
632 T* ToPtr() {
633 return dynamic_cast<T*>( &**this );
634 }
635
636 Object* operator -> () {
637 return &**this;
638 }
639
640 const Object* operator -> () const {
641 return &**this;
642 }
643
644 bool operator== (const std::string& atype) const {
645 return type == atype;
646 }
647
648 bool operator!= (const std::string& atype) const {
649 return type != atype;
650 }
651
652 uint64_t GetID() const {
653 return id;
654 }
655
656 private:
657
658 void LazyInit() const;
659
660 private:
661
662 mutable uint64_t id;
663 const char* const type;
664 DB& db;
665
666 mutable const char* args;
667 mutable Object* obj;
668 };
669
670 template <typename T>
671 inline bool operator==( std::shared_ptr<LazyObject> lo, T whatever ) {
672 return *lo == whatever; // XXX use std::forward if we have 0x
673 }
674
675 template <typename T>
676 inline bool operator==( const std::pair<uint64_t, std::shared_ptr<LazyObject> >& lo, T whatever ) {
677 return *(lo.second) == whatever; // XXX use std::forward if we have 0x
678 }
679
680
681 // ------------------------------------------------------------------------------
682 /** Class template used to represent lazily evaluated object references in the converted schema */
683 // ------------------------------------------------------------------------------
684 template <typename T>
685 struct Lazy
686 {
687 typedef Lazy Out;
688 Lazy(const LazyObject* obj = NULL) : obj(obj) {
689 }
690
691 operator const T*() const {
692 return obj->ToPtr<T>();
693 }
694
695 operator const T&() const {
696 return obj->To<T>();
697 }
698
699 const T& operator * () const {
700 return obj->To<T>();
701 }
702
703 const T* operator -> () const {
704 return &obj->To<T>();
705 }
706
707 const LazyObject* obj;
708 };
709
710 // ------------------------------------------------------------------------------
711 /** Class template used to represent LIST and SET data members in the converted schema */
712 // ------------------------------------------------------------------------------
713 template <typename T, uint64_t min_cnt, uint64_t max_cnt=0uL>
714 struct ListOf : public std::vector<typename T::Out>
715 {
716 typedef typename T::Out OutScalar;
717 typedef ListOf Out;
718
719
720 ListOf() {
721 static_assert(min_cnt <= max_cnt || !max_cnt, "min_cnt <= max_cnt || !max_cnt");
722 }
723
724 };
725
726
727 // ------------------------------------------------------------------------------
728 template <typename TOut>
729 struct PickBaseType {
730 typedef EXPRESS::PrimitiveDataType<TOut> Type;
731 };
732
733 template <typename TOut>
734 struct PickBaseType< Lazy<TOut> > {
735 typedef EXPRESS::ENTITY Type;
736 };
737
738 template <> struct PickBaseType< std::shared_ptr< const EXPRESS::DataType > >;
739
740 // ------------------------------------------------------------------------------
741 template <typename T>
742 struct InternGenericConvert {
743 void operator()(T& out, const std::shared_ptr< const EXPRESS::DataType >& in, const STEP::DB& /*db*/) {
744 try{
745 out = dynamic_cast< const typename PickBaseType<T>::Type& > ( *in );
746 }
747 catch(std::bad_cast&) {
748 throw TypeError("type error reading literal field");
749 }
750 }
751 };
752
753 template <>
754 struct InternGenericConvert< std::shared_ptr< const EXPRESS::DataType > > {
755 void operator()(std::shared_ptr< const EXPRESS::DataType >& out, const std::shared_ptr< const EXPRESS::DataType >& in, const STEP::DB& /*db*/) {
756 out = in;
757 }
758 };
759
760 template <typename T>
761 struct InternGenericConvert< Maybe<T> > {
762 void operator()(Maybe<T>& out, const std::shared_ptr< const EXPRESS::DataType >& in, const STEP::DB& db) {
763 GenericConvert((T&)out,in,db);
764 out.flag_valid();
765 }
766 };
767
768 template <typename T,uint64_t min_cnt, uint64_t max_cnt>
769 struct InternGenericConvertList {
770 void operator()(ListOf<T, min_cnt, max_cnt>& out, const std::shared_ptr< const EXPRESS::DataType >& inp_base, const STEP::DB& db) {
771
772 const EXPRESS::LIST* inp = dynamic_cast<const EXPRESS::LIST*>(inp_base.get());
773 if (!inp) {
774 throw TypeError("type error reading aggregate");
775 }
776
777 // XXX is this really how the EXPRESS notation ([?:3],[1:3]) is intended?
778 if (max_cnt && inp->GetSize() > max_cnt) {
779 DefaultLogger::get()->warn("too many aggregate elements");
780 }
781 else if (inp->GetSize() < min_cnt) {
782 DefaultLogger::get()->warn("too few aggregate elements");
783 }
784
785 out.reserve(inp->GetSize());
786 for(size_t i = 0; i < inp->GetSize(); ++i) {
787
788 out.push_back( typename ListOf<T, min_cnt, max_cnt>::OutScalar() );
789 try{
790 GenericConvert(out.back(),(*inp)[i], db);
791 }
792 catch(const TypeError& t) {
793 throw TypeError(t.what() +std::string(" of aggregate"));
794 }
795 }
796 }
797 };
798
799 template <typename T>
800 struct InternGenericConvert< Lazy<T> > {
801 void operator()(Lazy<T>& out, const std::shared_ptr< const EXPRESS::DataType >& in_base, const STEP::DB& db) {
802 const EXPRESS::ENTITY* in = dynamic_cast<const EXPRESS::ENTITY*>(in_base.get());
803 if (!in) {
804 throw TypeError("type error reading entity");
805 }
806 out = Couple<T>(db).GetObject(*in);
807 }
808 };
809
810 template <typename T1>
811 inline void GenericConvert(T1& a, const std::shared_ptr< const EXPRESS::DataType >& b, const STEP::DB& db) {
812 return InternGenericConvert<T1>()(a,b,db);
813 }
814
815 template <typename T1,uint64_t N1, uint64_t N2>
816 inline void GenericConvert(ListOf<T1,N1,N2>& a, const std::shared_ptr< const EXPRESS::DataType >& b, const STEP::DB& db) {
817 return InternGenericConvertList<T1,N1,N2>()(a,b,db);
818 }
819
820
821 // ------------------------------------------------------------------------------
822 /** Lightweight manager class that holds the map of all objects in a
823 * STEP file. DB's are exclusively maintained by the functions in
824 * STEPFileReader.h*/
825 // -------------------------------------------------------------------------------
826 class DB
827 {
828 friend DB* ReadFileHeader(std::shared_ptr<IOStream> stream);
829 friend void ReadFile(DB& db,const EXPRESS::ConversionSchema& scheme,
830 const char* const* types_to_track, size_t len,
831 const char* const* inverse_indices_to_track, size_t len2
832 );
833
834 friend class LazyObject;
835
836 public:
837
838 // objects indexed by ID - this can grow pretty large (i.e some hundred million
839 // entries), so use raw pointers to avoid *any* overhead.
840 typedef std::map<uint64_t,const LazyObject* > ObjectMap;
841
842 // objects indexed by their declarative type, but only for those that we truly want
843 typedef std::set< const LazyObject*> ObjectSet;
844 typedef std::map<std::string, ObjectSet > ObjectMapByType;
845
846 // list of types for which to keep inverse indices for all references
847 // that the respective objects keep.
848 // the list keeps pointers to strings in static storage
849 typedef std::set<const char*> InverseWhitelist;
850
851 // references - for each object id the ids of all objects which reference it
852 // this is used to simulate STEP inverse indices for selected types.
853 typedef std::step_unordered_multimap<uint64_t, uint64_t > RefMap;
854 typedef std::pair<RefMap::const_iterator,RefMap::const_iterator> RefMapRange;
855
856 private:
857
858 DB(std::shared_ptr<StreamReaderLE> reader)
859 : reader(reader)
860 , splitter(*reader,true,true)
861 , evaluated_count()
862 , schema( NULL )
863 {}
864
865 public:
866
867 ~DB() {
868 for(ObjectMap::value_type& o : objects) {
869 delete o.second;
870 }
871 }
872
873 public:
874
875 uint64_t GetObjectCount() const {
876 return objects.size();
877 }
878
879 uint64_t GetEvaluatedObjectCount() const {
880 return evaluated_count;
881 }
882
883 const HeaderInfo& GetHeader() const {
884 return header;
885 }
886
887 const EXPRESS::ConversionSchema& GetSchema() const {
888 return *schema;
889 }
890
891 const ObjectMap& GetObjects() const {
892 return objects;
893 }
894
895 const ObjectMapByType& GetObjectsByType() const {
896 return objects_bytype;
897 }
898
899 const RefMap& GetRefs() const {
900 return refs;
901 }
902
903
904 bool KeepInverseIndicesForType(const char* const type) const {
905 return inv_whitelist.find(type) != inv_whitelist.end();
906 }
907
908
909 // get the yet unevaluated object record with a given id
910 const LazyObject* GetObject(uint64_t id) const {
911 const ObjectMap::const_iterator it = objects.find(id);
912 if (it != objects.end()) {
913 return (*it).second;
914 }
915 return NULL;
916 }
917
918
919 // get an arbitrary object out of the soup with the only restriction being its type.
920 const LazyObject* GetObject(const std::string& type) const {
921 const ObjectMapByType::const_iterator it = objects_bytype.find(type);
922 if (it != objects_bytype.end() && (*it).second.size()) {
923 return *(*it).second.begin();
924 }
925 return NULL;
926 }
927
928 // same, but raise an exception if the object doesn't exist and return a reference
929 const LazyObject& MustGetObject(uint64_t id) const {
930 const LazyObject* o = GetObject(id);
931 if (!o) {
932 throw TypeError("requested entity is not present",id);
933 }
934 return *o;
935 }
936
937 const LazyObject& MustGetObject(const std::string& type) const {
938 const LazyObject* o = GetObject(type);
939 if (!o) {
940 throw TypeError("requested entity of type "+type+"is not present");
941 }
942 return *o;
943 }
944
945
946#ifdef ASSIMP_IFC_TEST
947
948 // evaluate *all* entities in the file. this is a power test for the loader
949 void EvaluateAll() {
950 for(ObjectMap::value_type& e :objects) {
951 **e.second;
952 }
953 ai_assert(evaluated_count == objects.size());
954 }
955
956#endif
957
958 private:
959
960 // full access only offered to close friends - they should
961 // use the provided getters rather than messing around with
962 // the members directly.
963 LineSplitter& GetSplitter() {
964 return splitter;
965 }
966
967 void InternInsert(const LazyObject* lz) {
968 objects[lz->GetID()] = lz;
969
970 const ObjectMapByType::iterator it = objects_bytype.find( lz->type );
971 if (it != objects_bytype.end()) {
972 (*it).second.insert(lz);
973 }
974 }
975
976 void SetSchema(const EXPRESS::ConversionSchema& _schema) {
977 schema = &_schema;
978 }
979
980
981 void SetTypesToTrack(const char* const* types, size_t N) {
982 for(size_t i = 0; i < N;++i) {
983 objects_bytype[types[i]] = ObjectSet();
984 }
985 }
986
987 void SetInverseIndicesToTrack( const char* const* types, size_t N ) {
988 for(size_t i = 0; i < N;++i) {
989 const char* const sz = schema->GetStaticStringForToken(types[i]);
990 ai_assert(sz);
991 inv_whitelist.insert(sz);
992 }
993 }
994
995 HeaderInfo& GetHeader() {
996 return header;
997 }
998
999 void MarkRef(uint64_t who, uint64_t by_whom) {
1000 refs.insert(std::make_pair(who,by_whom));
1001 }
1002
1003 private:
1004 HeaderInfo header;
1005 ObjectMap objects;
1006 ObjectMapByType objects_bytype;
1007 RefMap refs;
1008 InverseWhitelist inv_whitelist;
1009 std::shared_ptr<StreamReaderLE> reader;
1010 LineSplitter splitter;
1011 uint64_t evaluated_count;
1012 const EXPRESS::ConversionSchema* schema;
1013 };
1014
1015}
1016
1017} // end Assimp
1018
1019#endif // INCLUDED_AI_STEPFILE_H
1020