summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/assimp/code/STEPFileReader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdparty/assimp/code/STEPFileReader.cpp')
-rw-r--r--src/3rdparty/assimp/code/STEPFileReader.cpp879
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 &ltrim(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);
}