diff options
Diffstat (limited to 'src/3rdparty/assimp/code/STEPFileReader.cpp')
-rw-r--r-- | src/3rdparty/assimp/code/STEPFileReader.cpp | 879 |
1 files changed, 429 insertions, 450 deletions
diff --git a/src/3rdparty/assimp/code/STEPFileReader.cpp b/src/3rdparty/assimp/code/STEPFileReader.cpp index c9561daa9..afaa53a45 100644 --- a/src/3rdparty/assimp/code/STEPFileReader.cpp +++ b/src/3rdparty/assimp/code/STEPFileReader.cpp @@ -2,11 +2,11 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2012, assimp team +Copyright (c) 2006-2016, assimp team All rights reserved. -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above @@ -23,30 +23,31 @@ following conditions are met: derived from this software without specific prior written permission of the assimp team. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- */ /** @file STEPFileReader.cpp - * @brief Implementation of the STEP file parser, which fills a + * @brief Implementation of the STEP file parser, which fills a * STEP::DB with data read from a file. */ -#include "AssimpPCH.h" + #include "STEPFileReader.h" #include "STEPFileEncoding.h" #include "TinyFormatter.h" #include "fast_atof.h" +#include <memory> using namespace Assimp; @@ -55,38 +56,16 @@ namespace EXPRESS = STEP::EXPRESS; #include <functional> // ------------------------------------------------------------------------------------------------ -// From http://stackoverflow.com/questions/216823/whats-the-best-way-to-trim-stdstring - -// trim from start -static inline std::string <rim(std::string &s) { - s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1( std::ptr_fun(Assimp::IsSpace<char>)))); - return s; -} - -// trim from end -static inline std::string &rtrim(std::string &s) { - s.erase(std::find_if(s.rbegin(), s.rend(), std::not1( std::ptr_fun(Assimp::IsSpace<char>))).base(),s.end()); - return s; -} -// trim from both ends -static inline std::string &trim(std::string &s) { - return ltrim(rtrim(s)); -} - - - - -// ------------------------------------------------------------------------------------------------ -std::string AddLineNumber(const std::string& s,uint64_t line /*= LINE_NOT_SPECIFIED*/, const std::string& prefix = "") +std::string AddLineNumber(const std::string& s,uint64_t line /*= LINE_NOT_SPECIFIED*/, const std::string& prefix = "") { - return line == STEP::SyntaxError::LINE_NOT_SPECIFIED ? prefix+s : static_cast<std::string>( (Formatter::format(),prefix,"(line ",line,") ",s) ); + return line == STEP::SyntaxError::LINE_NOT_SPECIFIED ? prefix+s : static_cast<std::string>( (Formatter::format(),prefix,"(line ",line,") ",s) ); } // ------------------------------------------------------------------------------------------------ -std::string AddEntityID(const std::string& s,uint64_t entity /*= ENTITY_NOT_SPECIFIED*/, const std::string& prefix = "") +std::string AddEntityID(const std::string& s,uint64_t entity /*= ENTITY_NOT_SPECIFIED*/, const std::string& prefix = "") { - return entity == STEP::TypeError::ENTITY_NOT_SPECIFIED ? prefix+s : static_cast<std::string>( (Formatter::format(),prefix,"(entity #",entity,") ",s)); + return entity == STEP::TypeError::ENTITY_NOT_SPECIFIED ? prefix+s : static_cast<std::string>( (Formatter::format(),prefix,"(entity #",entity,") ",s)); } @@ -106,59 +85,59 @@ STEP::TypeError::TypeError (const std::string& s,uint64_t entity /* = ENTITY_NOT // ------------------------------------------------------------------------------------------------ -STEP::DB* STEP::ReadFileHeader(boost::shared_ptr<IOStream> stream) +STEP::DB* STEP::ReadFileHeader(std::shared_ptr<IOStream> stream) { - boost::shared_ptr<StreamReaderLE> reader = boost::shared_ptr<StreamReaderLE>(new StreamReaderLE(stream)); - std::auto_ptr<STEP::DB> db = std::auto_ptr<STEP::DB>(new STEP::DB(reader)); - - LineSplitter& splitter = db->GetSplitter(); - if (!splitter || *splitter != "ISO-10303-21;") { - throw STEP::SyntaxError("expected magic token: ISO-10303-21",1); - } - - HeaderInfo& head = db->GetHeader(); - for(++splitter; splitter; ++splitter) { - const std::string& s = *splitter; - if (s == "DATA;") { - // here we go, header done, start of data section - ++splitter; - break; - } - - // want one-based line numbers for human readers, so +1 - const uint64_t line = splitter.get_index()+1; - - if (s.substr(0,11) == "FILE_SCHEMA") { - const char* sz = s.c_str()+11; - SkipSpaces(sz,&sz); - boost::shared_ptr< const EXPRESS::DataType > schema = EXPRESS::DataType::Parse(sz); - - // the file schema should be a regular list entity, although it usually contains exactly one entry - // since the list itself is contained in a regular parameter list, we actually have - // two nested lists. - const EXPRESS::LIST* list = dynamic_cast<const EXPRESS::LIST*>(schema.get()); - if (list && list->GetSize()) { - list = dynamic_cast<const EXPRESS::LIST*>( (*list)[0].get() ); - if (!list) { - throw STEP::SyntaxError("expected FILE_SCHEMA to be a list",line); - } - - // XXX need support for multiple schemas? - if (list->GetSize() > 1) { - DefaultLogger::get()->warn(AddLineNumber("multiple schemas currently not supported",line)); - } - const EXPRESS::STRING* string; - if (!list->GetSize() || !(string=dynamic_cast<const EXPRESS::STRING*>( (*list)[0].get() ))) { - throw STEP::SyntaxError("expected FILE_SCHEMA to contain a single string literal",line); - } - head.fileSchema = *string; - } - } - - // XXX handle more header fields - } - - return db.release(); + std::shared_ptr<StreamReaderLE> reader = std::shared_ptr<StreamReaderLE>(new StreamReaderLE(stream)); + std::unique_ptr<STEP::DB> db = std::unique_ptr<STEP::DB>(new STEP::DB(reader)); + + LineSplitter& splitter = db->GetSplitter(); + if (!splitter || *splitter != "ISO-10303-21;") { + throw STEP::SyntaxError("expected magic token: ISO-10303-21",1); + } + + HeaderInfo& head = db->GetHeader(); + for(++splitter; splitter; ++splitter) { + const std::string& s = *splitter; + if (s == "DATA;") { + // here we go, header done, start of data section + ++splitter; + break; + } + + // want one-based line numbers for human readers, so +1 + const uint64_t line = splitter.get_index()+1; + + if (s.substr(0,11) == "FILE_SCHEMA") { + const char* sz = s.c_str()+11; + SkipSpaces(sz,&sz); + std::shared_ptr< const EXPRESS::DataType > schema = EXPRESS::DataType::Parse(sz); + + // the file schema should be a regular list entity, although it usually contains exactly one entry + // since the list itself is contained in a regular parameter list, we actually have + // two nested lists. + const EXPRESS::LIST* list = dynamic_cast<const EXPRESS::LIST*>(schema.get()); + if (list && list->GetSize()) { + list = dynamic_cast<const EXPRESS::LIST*>( (*list)[0].get() ); + if (!list) { + throw STEP::SyntaxError("expected FILE_SCHEMA to be a list",line); + } + + // XXX need support for multiple schemas? + if (list->GetSize() > 1) { + DefaultLogger::get()->warn(AddLineNumber("multiple schemas currently not supported",line)); + } + const EXPRESS::STRING* string( nullptr ); + if (!list->GetSize() || !(string=dynamic_cast<const EXPRESS::STRING*>( (*list)[0].get() ))) { + throw STEP::SyntaxError("expected FILE_SCHEMA to contain a single string literal",line); + } + head.fileSchema = *string; + } + } + + // XXX handle more header fields + } + + return db.release(); } @@ -168,19 +147,19 @@ namespace { // check whether the given line contains an entity definition (i.e. starts with "#<number>=") bool IsEntityDef(const std::string& snext) { - if (snext[0] == '#') { - // it is only a new entity if it has a '=' after the - // entity ID. - for(std::string::const_iterator it = snext.begin()+1; it != snext.end(); ++it) { - if (*it == '=') { - return true; - } - if ((*it < '0' || *it > '9') && *it != ' ') { - break; - } - } - } - return false; + if (snext[0] == '#') { + // it is only a new entity if it has a '=' after the + // entity ID. + for(std::string::const_iterator it = snext.begin()+1; it != snext.end(); ++it) { + if (*it == '=') { + return true; + } + if ((*it < '0' || *it > '9') && *it != ' ') { + break; + } + } + } + return false; } } @@ -188,377 +167,377 @@ bool IsEntityDef(const std::string& snext) // ------------------------------------------------------------------------------------------------ void STEP::ReadFile(DB& db,const EXPRESS::ConversionSchema& scheme, - const char* const* types_to_track, size_t len, - const char* const* inverse_indices_to_track, size_t len2) + const char* const* types_to_track, size_t len, + const char* const* inverse_indices_to_track, size_t len2) { - db.SetSchema(scheme); - db.SetTypesToTrack(types_to_track,len); - db.SetInverseIndicesToTrack(inverse_indices_to_track,len2); - - const DB::ObjectMap& map = db.GetObjects(); - LineSplitter& splitter = db.GetSplitter(); - - while (splitter) { - bool has_next = false; - std::string s = *splitter; - if (s == "ENDSEC;") { - break; - } - s.erase(std::remove(s.begin(), s.end(), ' '), s.end()); - - // want one-based line numbers for human readers, so +1 - const uint64_t line = splitter.get_index()+1; - // LineSplitter already ignores empty lines - ai_assert(s.length()); - if (s[0] != '#') { - DefaultLogger::get()->warn(AddLineNumber("expected token \'#\'",line)); - ++splitter; - continue; - } - // --- - // extract id, entity class name and argument string, - // but don't create the actual object yet. - // --- - const std::string::size_type n0 = s.find_first_of('='); - if (n0 == std::string::npos) { - DefaultLogger::get()->warn(AddLineNumber("expected token \'=\'",line)); - ++splitter; - continue; - } - - const uint64_t id = strtoul10_64(s.substr(1,n0-1).c_str()); - if (!id) { - DefaultLogger::get()->warn(AddLineNumber("expected positive, numeric entity id",line)); - ++splitter; - continue; - } - std::string::size_type n1 = s.find_first_of('(',n0); - if (n1 == std::string::npos) { - has_next = true; - bool ok = false; - for( ++splitter; splitter; ++splitter) { - const std::string& snext = *splitter; - if (snext.empty()) { - continue; - } - - // the next line doesn't start an entity, so maybe it is - // just a continuation for this line, keep going - if (!IsEntityDef(snext)) { - s.append(snext); - n1 = s.find_first_of('(',n0); - ok = (n1 != std::string::npos); - } - else { - break; - } - } - - if(!ok) { - DefaultLogger::get()->warn(AddLineNumber("expected token \'(\'",line)); - continue; - } - } - - std::string::size_type n2 = s.find_last_of(')'); - if (n2 == std::string::npos || n2 < n1 || n2 == s.length() - 1 || s[n2 + 1] != ';') { - - has_next = true; - bool ok = false; - for( ++splitter; splitter; ++splitter) { - const std::string& snext = *splitter; - if (snext.empty()) { - continue; - } - // the next line doesn't start an entity, so maybe it is - // just a continuation for this line, keep going - if (!IsEntityDef(snext)) { - s.append(snext); - n2 = s.find_last_of(')'); - ok = !(n2 == std::string::npos || n2 < n1 || n2 == s.length() - 1 || s[n2 + 1] != ';'); - } - else { - break; - } - } - if(!ok) { - DefaultLogger::get()->warn(AddLineNumber("expected token \')\'",line)); - continue; - } - } - - if (map.find(id) != map.end()) { - DefaultLogger::get()->warn(AddLineNumber((Formatter::format(),"an object with the id #",id," already exists"),line)); - } - - std::string::size_type ns = n0; - do ++ns; while( IsSpace(s.at(ns))); - std::string::size_type ne = n1; - do --ne; while( IsSpace(s.at(ne))); - std::string type = s.substr(ns,ne-ns+1); - std::transform( type.begin(), type.end(), type.begin(), &Assimp::ToLower<char> ); - const char* sz = scheme.GetStaticStringForToken(type); - if(sz) { - const std::string::size_type len = n2-n1+1; - char* const copysz = new char[len+1]; - std::copy(s.c_str()+n1,s.c_str()+n2+1,copysz); - copysz[len] = '\0'; - db.InternInsert(new LazyObject(db,id,line,sz,copysz)); - } - if(!has_next) { - ++splitter; - } - } - - if (!splitter) { - DefaultLogger::get()->warn("STEP: ignoring unexpected EOF"); - } - - if ( !DefaultLogger::isNullLogger()){ - DefaultLogger::get()->debug((Formatter::format(),"STEP: got ",map.size()," object records with ", - db.GetRefs().size()," inverse index entries")); - } + db.SetSchema(scheme); + db.SetTypesToTrack(types_to_track,len); + db.SetInverseIndicesToTrack(inverse_indices_to_track,len2); + + const DB::ObjectMap& map = db.GetObjects(); + LineSplitter& splitter = db.GetSplitter(); + + while (splitter) { + bool has_next = false; + std::string s = *splitter; + if (s == "ENDSEC;") { + break; + } + s.erase(std::remove(s.begin(), s.end(), ' '), s.end()); + + // want one-based line numbers for human readers, so +1 + const uint64_t line = splitter.get_index()+1; + // LineSplitter already ignores empty lines + ai_assert(s.length()); + if (s[0] != '#') { + DefaultLogger::get()->warn(AddLineNumber("expected token \'#\'",line)); + ++splitter; + continue; + } + // --- + // extract id, entity class name and argument string, + // but don't create the actual object yet. + // --- + const std::string::size_type n0 = s.find_first_of('='); + if (n0 == std::string::npos) { + DefaultLogger::get()->warn(AddLineNumber("expected token \'=\'",line)); + ++splitter; + continue; + } + + const uint64_t id = strtoul10_64(s.substr(1,n0-1).c_str()); + if (!id) { + DefaultLogger::get()->warn(AddLineNumber("expected positive, numeric entity id",line)); + ++splitter; + continue; + } + std::string::size_type n1 = s.find_first_of('(',n0); + if (n1 == std::string::npos) { + has_next = true; + bool ok = false; + for( ++splitter; splitter; ++splitter) { + const std::string& snext = *splitter; + if (snext.empty()) { + continue; + } + + // the next line doesn't start an entity, so maybe it is + // just a continuation for this line, keep going + if (!IsEntityDef(snext)) { + s.append(snext); + n1 = s.find_first_of('(',n0); + ok = (n1 != std::string::npos); + } + else { + break; + } + } + + if(!ok) { + DefaultLogger::get()->warn(AddLineNumber("expected token \'(\'",line)); + continue; + } + } + + std::string::size_type n2 = s.find_last_of(')'); + if (n2 == std::string::npos || n2 < n1 || n2 == s.length() - 1 || s[n2 + 1] != ';') { + + has_next = true; + bool ok = false; + for( ++splitter; splitter; ++splitter) { + const std::string& snext = *splitter; + if (snext.empty()) { + continue; + } + // the next line doesn't start an entity, so maybe it is + // just a continuation for this line, keep going + if (!IsEntityDef(snext)) { + s.append(snext); + n2 = s.find_last_of(')'); + ok = !(n2 == std::string::npos || n2 < n1 || n2 == s.length() - 1 || s[n2 + 1] != ';'); + } + else { + break; + } + } + if(!ok) { + DefaultLogger::get()->warn(AddLineNumber("expected token \')\'",line)); + continue; + } + } + + if (map.find(id) != map.end()) { + DefaultLogger::get()->warn(AddLineNumber((Formatter::format(),"an object with the id #",id," already exists"),line)); + } + + std::string::size_type ns = n0; + do ++ns; while( IsSpace(s.at(ns))); + std::string::size_type ne = n1; + do --ne; while( IsSpace(s.at(ne))); + std::string type = s.substr(ns,ne-ns+1); + std::transform( type.begin(), type.end(), type.begin(), &Assimp::ToLower<char> ); + const char* sz = scheme.GetStaticStringForToken(type); + if(sz) { + const std::string::size_type len = n2-n1+1; + char* const copysz = new char[len+1]; + std::copy(s.c_str()+n1,s.c_str()+n2+1,copysz); + copysz[len] = '\0'; + db.InternInsert(new LazyObject(db,id,line,sz,copysz)); + } + if(!has_next) { + ++splitter; + } + } + + if (!splitter) { + DefaultLogger::get()->warn("STEP: ignoring unexpected EOF"); + } + + if ( !DefaultLogger::isNullLogger()){ + DefaultLogger::get()->debug((Formatter::format(),"STEP: got ",map.size()," object records with ", + db.GetRefs().size()," inverse index entries")); + } } // ------------------------------------------------------------------------------------------------ -boost::shared_ptr<const EXPRESS::DataType> EXPRESS::DataType::Parse(const char*& inout,uint64_t line, const EXPRESS::ConversionSchema* schema /*= NULL*/) +std::shared_ptr<const EXPRESS::DataType> EXPRESS::DataType::Parse(const char*& inout,uint64_t line, const EXPRESS::ConversionSchema* schema /*= NULL*/) { - const char* cur = inout; - SkipSpaces(&cur); - if (*cur == ',' || IsSpaceOrNewLine(*cur)) { - throw STEP::SyntaxError("unexpected token, expected parameter",line); - } - - // just skip over constructions such as IFCPLANEANGLEMEASURE(0.01) and read only the value - if (schema) { - bool ok = false; - for(const char* t = cur; *t && *t != ')' && *t != ','; ++t) { - if (*t=='(') { - if (!ok) { - break; - } - for(--t;IsSpace(*t);--t); - std::string s(cur,static_cast<size_t>(t-cur+1)); - std::transform(s.begin(),s.end(),s.begin(),&ToLower<char> ); - if (schema->IsKnownToken(s)) { - for(cur = t+1;*cur++ != '(';); - const boost::shared_ptr<const EXPRESS::DataType> dt = Parse(cur); - inout = *cur ? cur+1 : cur; - return dt; - } - break; - } - else if (!IsSpace(*t)) { - ok = true; - } - } - } - - if (*cur == '*' ) { - inout = cur+1; - return boost::make_shared<EXPRESS::ISDERIVED>(); - } - else if (*cur == '$' ) { - inout = cur+1; - return boost::make_shared<EXPRESS::UNSET>(); - } - else if (*cur == '(' ) { - // start of an aggregate, further parsing is done by the LIST factory constructor - inout = cur; - return EXPRESS::LIST::Parse(inout,line,schema); - } - else if (*cur == '.' ) { - // enum (includes boolean) - const char* start = ++cur; - for(;*cur != '.';++cur) { - if (*cur == '\0') { - throw STEP::SyntaxError("enum not closed",line); - } - } - inout = cur+1; - return boost::make_shared<EXPRESS::ENUMERATION>(std::string(start, static_cast<size_t>(cur-start) )); - } - else if (*cur == '#' ) { - // object reference - return boost::make_shared<EXPRESS::ENTITY>(strtoul10_64(++cur,&inout)); - } - else if (*cur == '\'' ) { - // string literal - const char* start = ++cur; - - for(;*cur != '\'';++cur) { - if (*cur == '\0') { - throw STEP::SyntaxError("string literal not closed",line); - } - } - - if (cur[1] == '\'') { - // Vesanen: more than 2 escaped ' in one literal! - do { - for(cur += 2;*cur != '\'';++cur) { - if (*cur == '\0') { - throw STEP::SyntaxError("string literal not closed",line); - } - } - } - while(cur[1] == '\''); - } - - inout = cur + 1; - - // assimp is supposed to output UTF8 strings, so we have to deal - // with foreign encodings. - std::string stemp = std::string(start, static_cast<size_t>(cur - start)); - if(!StringToUTF8(stemp)) { - // TODO: route this to a correct logger with line numbers etc., better error messages - DefaultLogger::get()->error("an error occurred reading escape sequences in ASCII text"); - } - - return boost::make_shared<EXPRESS::STRING>(stemp); - } - else if (*cur == '\"' ) { - throw STEP::SyntaxError("binary data not supported yet",line); - } - - // else -- must be a number. if there is a decimal dot in it, - // parse it as real value, otherwise as integer. - const char* start = cur; - for(;*cur && *cur != ',' && *cur != ')' && !IsSpace(*cur);++cur) { - if (*cur == '.') { - double f; - inout = fast_atoreal_move<double>(start,f); - return boost::make_shared<EXPRESS::REAL>(f); - } - } - - bool neg = false; - if (*start == '-') { - neg = true; - ++start; - } - else if (*start == '+') { - ++start; - } - int64_t num = static_cast<int64_t>( strtoul10_64(start,&inout) ); - return boost::make_shared<EXPRESS::INTEGER>(neg?-num:num); + const char* cur = inout; + SkipSpaces(&cur); + if (*cur == ',' || IsSpaceOrNewLine(*cur)) { + throw STEP::SyntaxError("unexpected token, expected parameter",line); + } + + // just skip over constructions such as IFCPLANEANGLEMEASURE(0.01) and read only the value + if (schema) { + bool ok = false; + for(const char* t = cur; *t && *t != ')' && *t != ','; ++t) { + if (*t=='(') { + if (!ok) { + break; + } + for(--t;IsSpace(*t);--t); + std::string s(cur,static_cast<size_t>(t-cur+1)); + std::transform(s.begin(),s.end(),s.begin(),&ToLower<char> ); + if (schema->IsKnownToken(s)) { + for(cur = t+1;*cur++ != '(';); + const std::shared_ptr<const EXPRESS::DataType> dt = Parse(cur); + inout = *cur ? cur+1 : cur; + return dt; + } + break; + } + else if (!IsSpace(*t)) { + ok = true; + } + } + } + + if (*cur == '*' ) { + inout = cur+1; + return std::make_shared<EXPRESS::ISDERIVED>(); + } + else if (*cur == '$' ) { + inout = cur+1; + return std::make_shared<EXPRESS::UNSET>(); + } + else if (*cur == '(' ) { + // start of an aggregate, further parsing is done by the LIST factory constructor + inout = cur; + return EXPRESS::LIST::Parse(inout,line,schema); + } + else if (*cur == '.' ) { + // enum (includes boolean) + const char* start = ++cur; + for(;*cur != '.';++cur) { + if (*cur == '\0') { + throw STEP::SyntaxError("enum not closed",line); + } + } + inout = cur+1; + return std::make_shared<EXPRESS::ENUMERATION>(std::string(start, static_cast<size_t>(cur-start) )); + } + else if (*cur == '#' ) { + // object reference + return std::make_shared<EXPRESS::ENTITY>(strtoul10_64(++cur,&inout)); + } + else if (*cur == '\'' ) { + // string literal + const char* start = ++cur; + + for(;*cur != '\'';++cur) { + if (*cur == '\0') { + throw STEP::SyntaxError("string literal not closed",line); + } + } + + if (cur[1] == '\'') { + // Vesanen: more than 2 escaped ' in one literal! + do { + for(cur += 2;*cur != '\'';++cur) { + if (*cur == '\0') { + throw STEP::SyntaxError("string literal not closed",line); + } + } + } + while(cur[1] == '\''); + } + + inout = cur + 1; + + // assimp is supposed to output UTF8 strings, so we have to deal + // with foreign encodings. + std::string stemp = std::string(start, static_cast<size_t>(cur - start)); + if(!StringToUTF8(stemp)) { + // TODO: route this to a correct logger with line numbers etc., better error messages + DefaultLogger::get()->error("an error occurred reading escape sequences in ASCII text"); + } + + return std::make_shared<EXPRESS::STRING>(stemp); + } + else if (*cur == '\"' ) { + throw STEP::SyntaxError("binary data not supported yet",line); + } + + // else -- must be a number. if there is a decimal dot in it, + // parse it as real value, otherwise as integer. + const char* start = cur; + for(;*cur && *cur != ',' && *cur != ')' && !IsSpace(*cur);++cur) { + if (*cur == '.') { + double f; + inout = fast_atoreal_move<double>(start,f); + return std::make_shared<EXPRESS::REAL>(f); + } + } + + bool neg = false; + if (*start == '-') { + neg = true; + ++start; + } + else if (*start == '+') { + ++start; + } + int64_t num = static_cast<int64_t>( strtoul10_64(start,&inout) ); + return std::make_shared<EXPRESS::INTEGER>(neg?-num:num); } // ------------------------------------------------------------------------------------------------ -boost::shared_ptr<const EXPRESS::LIST> EXPRESS::LIST::Parse(const char*& inout,uint64_t line, const EXPRESS::ConversionSchema* schema /*= NULL*/) +std::shared_ptr<const EXPRESS::LIST> EXPRESS::LIST::Parse(const char*& inout,uint64_t line, const EXPRESS::ConversionSchema* schema /*= NULL*/) { - const boost::shared_ptr<EXPRESS::LIST> list = boost::make_shared<EXPRESS::LIST>(); - EXPRESS::LIST::MemberList& members = list->members; - - const char* cur = inout; - if (*cur++ != '(') { - throw STEP::SyntaxError("unexpected token, expected \'(\' token at beginning of list",line); - } - - // estimate the number of items upfront - lists can grow large - size_t count = 1; - for(const char* c=cur; *c && *c != ')'; ++c) { - count += (*c == ',' ? 1 : 0); - } - - members.reserve(count); - - for(;;++cur) { - if (!*cur) { - throw STEP::SyntaxError("unexpected end of line while reading list"); - } - SkipSpaces(cur,&cur); - if (*cur == ')') { - break; - } - - members.push_back( EXPRESS::DataType::Parse(cur,line,schema)); - SkipSpaces(cur,&cur); - - if (*cur != ',') { - if (*cur == ')') { - break; - } - throw STEP::SyntaxError("unexpected token, expected \',\' or \')\' token after list element",line); - } - } - - inout = cur+1; - return list; + const std::shared_ptr<EXPRESS::LIST> list = std::make_shared<EXPRESS::LIST>(); + EXPRESS::LIST::MemberList& members = list->members; + + const char* cur = inout; + if (*cur++ != '(') { + throw STEP::SyntaxError("unexpected token, expected \'(\' token at beginning of list",line); + } + + // estimate the number of items upfront - lists can grow large + size_t count = 1; + for(const char* c=cur; *c && *c != ')'; ++c) { + count += (*c == ',' ? 1 : 0); + } + + members.reserve(count); + + for(;;++cur) { + if (!*cur) { + throw STEP::SyntaxError("unexpected end of line while reading list"); + } + SkipSpaces(cur,&cur); + if (*cur == ')') { + break; + } + + members.push_back( EXPRESS::DataType::Parse(cur,line,schema)); + SkipSpaces(cur,&cur); + + if (*cur != ',') { + if (*cur == ')') { + break; + } + throw STEP::SyntaxError("unexpected token, expected \',\' or \')\' token after list element",line); + } + } + + inout = cur+1; + return list; } // ------------------------------------------------------------------------------------------------ STEP::LazyObject::LazyObject(DB& db, uint64_t id,uint64_t /*line*/, const char* const type,const char* args) - : id(id) - , type(type) - , db(db) - , args(args) - , obj() + : id(id) + , type(type) + , db(db) + , args(args) + , obj() { - // find any external references and store them in the database. - // this helps us emulate STEPs INVERSE fields. - if (db.KeepInverseIndicesForType(type)) { - const char* a = args; - - // do a quick scan through the argument tuple and watch out for entity references - int64_t skip_depth = 0; - while(*a) { - if (*a == '(') { - ++skip_depth; - } - else if (*a == ')') { - --skip_depth; - } - - if (skip_depth >= 1 && *a=='#') { - const char* tmp; - const int64_t num = static_cast<int64_t>( strtoul10_64(a+1,&tmp) ); - db.MarkRef(num,id); - } - ++a; - } - - } + // find any external references and store them in the database. + // this helps us emulate STEPs INVERSE fields. + if (db.KeepInverseIndicesForType(type)) { + const char* a = args; + + // do a quick scan through the argument tuple and watch out for entity references + int64_t skip_depth = 0; + while(*a) { + if (*a == '(') { + ++skip_depth; + } + else if (*a == ')') { + --skip_depth; + } + + if (skip_depth >= 1 && *a=='#') { + const char* tmp; + const int64_t num = static_cast<int64_t>( strtoul10_64(a+1,&tmp) ); + db.MarkRef(num,id); + } + ++a; + } + + } } // ------------------------------------------------------------------------------------------------ -STEP::LazyObject::~LazyObject() +STEP::LazyObject::~LazyObject() { - // make sure the right dtor/operator delete get called - if (obj) { - delete obj; - } - else delete[] args; + // make sure the right dtor/operator delete get called + if (obj) { + delete obj; + } + else delete[] args; } // ------------------------------------------------------------------------------------------------ void STEP::LazyObject::LazyInit() const { - const EXPRESS::ConversionSchema& schema = db.GetSchema(); - STEP::ConvertObjectProc proc = schema.GetConverterProc(type); - - if (!proc) { - throw STEP::TypeError("unknown object type: " + std::string(type),id); - } - - const char* acopy = args; - boost::shared_ptr<const EXPRESS::LIST> conv_args = EXPRESS::LIST::Parse(acopy,STEP::SyntaxError::LINE_NOT_SPECIFIED,&db.GetSchema()); - delete[] args; - args = NULL; - - // if the converter fails, it should throw an exception, but it should never return NULL - try { - obj = proc(db,*conv_args); - } - catch(const TypeError& t) { - // augment line and entity information - throw TypeError(t.what(),id); - } - ++db.evaluated_count; - ai_assert(obj); - - // store the original id in the object instance - obj->SetID(id); + const EXPRESS::ConversionSchema& schema = db.GetSchema(); + STEP::ConvertObjectProc proc = schema.GetConverterProc(type); + + if (!proc) { + throw STEP::TypeError("unknown object type: " + std::string(type),id); + } + + const char* acopy = args; + std::shared_ptr<const EXPRESS::LIST> conv_args = EXPRESS::LIST::Parse(acopy,STEP::SyntaxError::LINE_NOT_SPECIFIED,&db.GetSchema()); + delete[] args; + args = NULL; + + // if the converter fails, it should throw an exception, but it should never return NULL + try { + obj = proc(db,*conv_args); + } + catch(const TypeError& t) { + // augment line and entity information + throw TypeError(t.what(),id); + } + ++db.evaluated_count; + ai_assert(obj); + + // store the original id in the object instance + obj->SetID(id); } |