diff options
Diffstat (limited to 'libs/assimp/code/AssetLib/STEPParser')
4 files changed, 1131 insertions, 0 deletions
diff --git a/libs/assimp/code/AssetLib/STEPParser/STEPFileEncoding.cpp b/libs/assimp/code/AssetLib/STEPParser/STEPFileEncoding.cpp new file mode 100644 index 0000000..d4456e6 --- /dev/null +++ b/libs/assimp/code/AssetLib/STEPParser/STEPFileEncoding.cpp @@ -0,0 +1,432 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2022, 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 +following conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its + contributors may be used to endorse or promote products + 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 +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +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 +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 +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +---------------------------------------------------------------------- +*/ + +/** @file STEPFileEncoding.cpp + * @brief STEP character handling, string un-escaping + */ +#include "STEPFileEncoding.h" +#include <assimp/fast_atof.h> +#ifdef ASSIMP_USE_HUNTER +# include <utf8.h> +#else +# include <contrib/utf8cpp/source/utf8.h> +#endif + +#include <memory> + +using namespace Assimp; + +// roman1 to utf16 table +static const uint16_t mac_codetable[] = { + // 0x20 unassig./nonprint. slots + 0x0020 , + 0x0021 , + 0x0022 , + 0x0023 , + 0x0024 , + 0x0025 , + 0x0026 , + 0x0027 , + 0x0028 , + 0x0029 , + 0x002A , + 0x002B , + 0x002C , + 0x002D , + 0x002E , + 0x002F , + 0x0030 , + 0x0031 , + 0x0032 , + 0x0033 , + 0x0034 , + 0x0035 , + 0x0036 , + 0x0037 , + 0x0038 , + 0x0039 , + 0x003A , + 0x003B , + 0x003C , + 0x003D , + 0x003E , + 0x003F , + 0x0040 , + 0x0041 , + 0x0042 , + 0x0043 , + 0x0044 , + 0x0045 , + 0x0046 , + 0x0047 , + 0x0048 , + 0x0049 , + 0x004A , + 0x004B , + 0x004C , + 0x004D , + 0x004E , + 0x004F , + 0x0050 , + 0x0051 , + 0x0052 , + 0x0053 , + 0x0054 , + 0x0055 , + 0x0056 , + 0x0057 , + 0x0058 , + 0x0059 , + 0x005A , + 0x005B , + 0x005C , + 0x005D , + 0x005E , + 0x005F , + 0x0060 , + 0x0061 , + 0x0062 , + 0x0063 , + 0x0064 , + 0x0065 , + 0x0066 , + 0x0067 , + 0x0068 , + 0x0069 , + 0x006A , + 0x006B , + 0x006C , + 0x006D , + 0x006E , + 0x006F , + 0x0070 , + 0x0071 , + 0x0072 , + 0x0073 , + 0x0074 , + 0x0075 , + 0x0076 , + 0x0077 , + 0x0078 , + 0x0079 , + 0x007A , + 0x007B , + 0x007C , + 0x007D , + 0x007E , + 0x0000 , // unassig. + 0x00C4 , + 0x00C5 , + 0x00C7 , + 0x00C9 , + 0x00D1 , + 0x00D6 , + 0x00DC , + 0x00E1 , + 0x00E0 , + 0x00E2 , + 0x00E4 , + 0x00E3 , + 0x00E5 , + 0x00E7 , + 0x00E9 , + 0x00E8 , + 0x00EA , + 0x00EB , + 0x00ED , + 0x00EC , + 0x00EE , + 0x00EF , + 0x00F1 , + 0x00F3 , + 0x00F2 , + 0x00F4 , + 0x00F6 , + 0x00F5 , + 0x00FA , + 0x00F9 , + 0x00FB , + 0x00FC , + 0x2020 , + 0x00B0 , + 0x00A2 , + 0x00A3 , + 0x00A7 , + 0x2022 , + 0x00B6 , + 0x00DF , + 0x00AE , + 0x00A9 , + 0x2122 , + 0x00B4 , + 0x00A8 , + 0x2260 , + 0x00C6 , + 0x00D8 , + 0x221E , + 0x00B1 , + 0x2264 , + 0x2265 , + 0x00A5 , + 0x00B5 , + 0x2202 , + 0x2211 , + 0x220F , + 0x03C0 , + 0x222B , + 0x00AA , + 0x00BA , + 0x03A9 , + 0x00E6 , + 0x00F8 , + 0x00BF , + 0x00A1 , + 0x00AC , + 0x221A , + 0x0192 , + 0x2248 , + 0x2206 , + 0x00AB , + 0x00BB , + 0x2026 , + 0x00A0 , + 0x00C0 , + 0x00C3 , + 0x00D5 , + 0x0152 , + 0x0153 , + 0x2013 , + 0x2014 , + 0x201C , + 0x201D , + 0x2018 , + 0x2019 , + 0x00F7 , + 0x25CA , + 0x00FF , + 0x0178 , + 0x2044 , + 0x20AC , + 0x2039 , + 0x203A , + 0xFB01 , + 0xFB02 , + 0x2021 , + 0x00B7 , + 0x201A , + 0x201E , + 0x2030 , + 0x00C2 , + 0x00CA , + 0x00C1 , + 0x00CB , + 0x00C8 , + 0x00CD , + 0x00CE , + 0x00CF , + 0x00CC , + 0x00D3 , + 0x00D4 , + 0xF8FF , + 0x00D2 , + 0x00DA , + 0x00DB , + 0x00D9 , + 0x0131 , + 0x02C6 , + 0x02DC , + 0x00AF , + 0x02D8 , + 0x02D9 , + 0x02DA , + 0x00B8 , + 0x02DD , + 0x02DB , + 0x02C7 +}; + +// ------------------------------------------------------------------------------------------------ +bool STEP::StringToUTF8(std::string& s) +{ + // very basic handling for escaped string sequences + // http://doc.spatial.com/index.php?title=InterOp:Connect/STEP&redirect=no + + for (size_t i = 0; i < s.size(); ) { + if (s[i] == '\\') { + // \S\X - cp1252 (X is the character remapped to [0,127]) + if (i+3 < s.size() && s[i+1] == 'S' && s[i+2] == '\\') { + // http://stackoverflow.com/questions/5586214/how-to-convert-char-from-iso-8859-1-to-utf-8-in-c-multiplatformly + ai_assert((uint8_t)s[i+3] < 0x80); + const uint8_t ch = s[i+3] + 0x80; + + s[i] = 0xc0 | (ch & 0xc0) >> 6; + s[i+1] = 0x80 | (ch & 0x3f); + + s.erase(i + 2,2); + ++i; + } + // \X\xx - mac/roman (xx is a hex sequence) + else if (i+4 < s.size() && s[i+1] == 'X' && s[i+2] == '\\') { + + const uint8_t macval = HexOctetToDecimal(s.c_str() + i + 3); + if(macval < 0x20) { + return false; + } + + ai_assert(sizeof(mac_codetable) / sizeof(mac_codetable[0]) == 0x100-0x20); + + const uint32_t unival = mac_codetable[macval - 0x20], *univalp = &unival; + + unsigned char temp[5], *tempp = temp; + ai_assert(sizeof( unsigned char ) == 1); + + utf8::utf32to8( univalp, univalp + 1, tempp ); + + const size_t outcount = static_cast<size_t>(tempp-temp); + + s.erase(i,5); + s.insert(i, reinterpret_cast<char*>(temp), outcount); + i += outcount; + } + // \Xn\ .. \X0\ - various unicode encodings (n=2: utf16; n=4: utf32) + else if (i+3 < s.size() && s[i+1] == 'X' && s[i+2] >= '0' && s[i+2] <= '9') { + switch(s[i+2]) { + // utf16 + case '2': + // utf32 + case '4': + if (s[i+3] == '\\') { + const size_t basei = i+4; + size_t j = basei, jend = s.size()-3; + + for (; j < jend; ++j) { + if (s[j] == '\\' && s[j+1] == 'X' && s[j+2] == '0' && s[j+3] == '\\') { + break; + } + } + if (j == jend) { + return false; + } + + if (j == basei) { + s.erase(i,8); + continue; + } + + if (s[i+2] == '2') { + if (((j - basei) % 4) != 0) { + return false; + } + + const size_t count = (j-basei)/4; + std::unique_ptr<uint16_t[]> src(new uint16_t[count]); + + const char* cur = s.c_str() + basei; + for (size_t k = 0; k < count; ++k, cur += 4) { + src[k] = (static_cast<uint16_t>(HexOctetToDecimal(cur)) << 8u) | + static_cast<uint16_t>(HexOctetToDecimal(cur+2)); + } + + const size_t dcount = count * 3; // this is enough to hold all possible outputs + std::unique_ptr<unsigned char[]> dest(new unsigned char[dcount]); + + const uint16_t* srct = src.get(); + unsigned char* destt = dest.get(); + utf8::utf16to8( srct, srct + count, destt ); + + const size_t outcount = static_cast<size_t>(destt-dest.get()); + + s.erase(i,(j+4-i)); + + ai_assert(sizeof(unsigned char) == 1); + s.insert(i, reinterpret_cast<char*>(dest.get()), outcount); + + i += outcount; + continue; + } + else if (s[i+2] == '4') { + if (((j - basei) % 8) != 0) { + return false; + } + + const size_t count = (j-basei)/8; + std::unique_ptr<uint32_t[]> src(new uint32_t[count]); + + const char* cur = s.c_str() + basei; + for (size_t k = 0; k < count; ++k, cur += 8) { + src[k] = (static_cast<uint32_t>(HexOctetToDecimal(cur )) << 24u) | + (static_cast<uint32_t>(HexOctetToDecimal(cur+2)) << 16u) | + (static_cast<uint32_t>(HexOctetToDecimal(cur+4)) << 8u) | + (static_cast<uint32_t>(HexOctetToDecimal(cur+6))); + } + + const size_t dcount = count * 5; // this is enough to hold all possible outputs + std::unique_ptr<unsigned char[]> dest(new unsigned char[dcount]); + + const uint32_t* srct = src.get(); + unsigned char* destt = dest.get(); + utf8::utf32to8( srct, srct + count, destt ); + + const size_t outcount = static_cast<size_t>(destt-dest.get()); + + s.erase(i,(j+4-i)); + + ai_assert(sizeof(unsigned char) == 1); + s.insert(i, reinterpret_cast<char*>(dest.get()), outcount); + + i += outcount; + continue; + } + } + break; + + // TODO: other encoding patterns? + + default: + return false; + } + } + } + ++i; + } + return true; +} diff --git a/libs/assimp/code/AssetLib/STEPParser/STEPFileEncoding.h b/libs/assimp/code/AssetLib/STEPParser/STEPFileEncoding.h new file mode 100644 index 0000000..950c9b3 --- /dev/null +++ b/libs/assimp/code/AssetLib/STEPParser/STEPFileEncoding.h @@ -0,0 +1,65 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2022, 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 +following conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its + contributors may be used to endorse or promote products + 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 +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +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 +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 +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +---------------------------------------------------------------------- +*/ + +#ifndef INCLUDED_AI_STEPFILEENCODING_H +#define INCLUDED_AI_STEPFILEENCODING_H + +#include <string> + +namespace Assimp { +namespace STEP { + + + // -------------------------------------------------------------------------- + // Convert an ASCII STEP identifier with possibly escaped character + // sequences using foreign encodings to plain UTF8. + // + // Return false if an error occurs, s may or may not be modified in + // this case and could still contain escape sequences (even partly + // escaped ones). + bool StringToUTF8(std::string& s); + + +} // ! STEP +} // ! Assimp + +#endif diff --git a/libs/assimp/code/AssetLib/STEPParser/STEPFileReader.cpp b/libs/assimp/code/AssetLib/STEPParser/STEPFileReader.cpp new file mode 100644 index 0000000..2bcfa17 --- /dev/null +++ b/libs/assimp/code/AssetLib/STEPParser/STEPFileReader.cpp @@ -0,0 +1,563 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2022, 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 +following conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its + contributors may be used to endorse or promote products + 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 +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +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 +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 +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 + * STEP::DB with data read from a file. + */ + +#include "STEPFileReader.h" +#include "STEPFileEncoding.h" +#include <assimp/TinyFormatter.h> +#include <assimp/fast_atof.h> +#include <functional> +#include <memory> +#include <utility> + +using namespace Assimp; + +namespace EXPRESS = STEP::EXPRESS; + +// ------------------------------------------------------------------------------------------------ +std::string AddLineNumber(const std::string& s,uint64_t line /*= LINE_NOT_SPECIFIED*/, const std::string& prefix = std::string()) +{ + 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()) +{ + return entity == STEP::TypeError::ENTITY_NOT_SPECIFIED ? prefix+s : static_cast<std::string>( (Formatter::format(),prefix,"(entity #",entity,") ",s)); +} + + +// ------------------------------------------------------------------------------------------------ +STEP::SyntaxError::SyntaxError (const std::string& s,uint64_t line /* = LINE_NOT_SPECIFIED */) +: DeadlyImportError(AddLineNumber(s,line)) +{ + +} + +// ------------------------------------------------------------------------------------------------ +STEP::TypeError::TypeError (const std::string& s,uint64_t entity /* = ENTITY_NOT_SPECIFIED */,uint64_t line /*= LINE_NOT_SPECIFIED*/) +: DeadlyImportError(AddLineNumber(AddEntityID(s,entity),line)) +{ + +} + +static const char *ISO_Token = "ISO-10303-21;"; +static const char *FILE_SCHEMA_Token = "FILE_SCHEMA"; +// ------------------------------------------------------------------------------------------------ +STEP::DB* STEP::ReadFileHeader(std::shared_ptr<IOStream> stream) { + std::shared_ptr<StreamReaderLE> reader = std::shared_ptr<StreamReaderLE>(new StreamReaderLE(std::move(stream))); + std::unique_ptr<STEP::DB> db = std::unique_ptr<STEP::DB>(new STEP::DB(reader)); + + LineSplitter &splitter = db->GetSplitter(); + if (!splitter || *splitter != ISO_Token ) { + throw STEP::SyntaxError("expected magic token: " + std::string( ISO_Token ), 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_Token) { + 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) { + ASSIMP_LOG_WARN(AddLineNumber("multiple schemas currently not supported",line)); + } + const EXPRESS::STRING *string = dynamic_cast<const EXPRESS::STRING *>((*list)[0].get()); + if (!list->GetSize() || nullptr == string ) { + throw STEP::SyntaxError("expected FILE_SCHEMA to contain a single string literal",line); + } + head.fileSchema = *string; + } + } + + // XXX handle more header fields + } + + return db.release(); +} + + +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; +} + +} + + +// ------------------------------------------------------------------------------------------------ +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) +{ + 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] != '#') { + ASSIMP_LOG_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) { + ASSIMP_LOG_WARN(AddLineNumber("expected token \'=\'",line)); + ++splitter; + continue; + } + + const uint64_t id = strtoul10_64(s.substr(1,n0-1).c_str()); + if (!id) { + ASSIMP_LOG_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) { + ASSIMP_LOG_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) { + ASSIMP_LOG_WARN(AddLineNumber("expected token \')\'",line)); + continue; + } + } + + if (map.find(id) != map.end()) { + ASSIMP_LOG_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); + type = ai_tolower(type); + const char* sz = scheme.GetStaticStringForToken(type); + if(sz) { + const std::string::size_type szLen = n2-n1+1; + char* const copysz = new char[szLen+1]; + std::copy(s.c_str()+n1,s.c_str()+n2+1,copysz); + copysz[szLen] = '\0'; + db.InternInsert(new LazyObject(db,id,line,sz,copysz)); + } + if(!has_next) { + ++splitter; + } + } + + if (!splitter) { + ASSIMP_LOG_WARN("STEP: ignoring unexpected EOF"); + } + + if ( !DefaultLogger::isNullLogger()){ + ASSIMP_LOG_DEBUG("STEP: got ",map.size()," object records with ", + db.GetRefs().size()," inverse index entries"); + } +} + +// ------------------------------------------------------------------------------------------------ +std::shared_ptr<const EXPRESS::DataType> EXPRESS::DataType::Parse(const char*& inout,uint64_t line, const EXPRESS::ConversionSchema* schema /*= nullptr*/) +{ + 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(),&ai_tolower<char> ); + if (schema->IsKnownToken(s)) { + for(cur = t+1;*cur++ != '(';); + 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 + ASSIMP_LOG_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); +} + +// ------------------------------------------------------------------------------------------------ +std::shared_ptr<const EXPRESS::LIST> EXPRESS::LIST::Parse(const char*& inout,uint64_t line, const EXPRESS::ConversionSchema* schema /*= nullptr*/) { + 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; +} + +// ------------------------------------------------------------------------------------------------ +static void handleSkippedDepthFromToken(const char *a, int64_t &skip_depth ) { + if (*a == '(') { + ++skip_depth; + } else if (*a == ')') { + --skip_depth; + } +} + +// ------------------------------------------------------------------------------------------------ +static int64_t getIdFromToken(const char *a) { + const char *tmp; + const int64_t num = static_cast<int64_t>(strtoul10_64(a + 1, &tmp)); + + return num; +} + +// ------------------------------------------------------------------------------------------------ +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() { + // find any external references and store them in the database. + // this helps us emulate STEPs INVERSE fields. + if (!db.KeepInverseIndicesForType(type)) { + return; + } + + // do a quick scan through the argument tuple and watch out for entity references + const char *a( args ); + int64_t skip_depth( 0 ); + while ( *a ) { + handleSkippedDepthFromToken(a, skip_depth); + /*if (*a == '(') { + ++skip_depth; + } else if (*a == ')') { + --skip_depth; + }*/ + + if (skip_depth >= 1 && *a=='#') { + if (*(a + 1) != '#') { + /*const char *tmp; + const int64_t num = static_cast<int64_t>(strtoul10_64(a + 1, &tmp)); + db.MarkRef(num, id);*/ + db.MarkRef(getIdFromToken(a), id); + } else { + ++a; + } + } + ++a; + } +} + +// ------------------------------------------------------------------------------------------------ +STEP::LazyObject::~LazyObject() { + // 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; + std::shared_ptr<const EXPRESS::LIST> conv_args = EXPRESS::LIST::Parse(acopy,(uint64_t)STEP::SyntaxError::LINE_NOT_SPECIFIED,&db.GetSchema()); + delete[] args; + args = nullptr; + + // if the converter fails, it should throw an exception, but it should never return nullptr + 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); +} diff --git a/libs/assimp/code/AssetLib/STEPParser/STEPFileReader.h b/libs/assimp/code/AssetLib/STEPParser/STEPFileReader.h new file mode 100644 index 0000000..8a57937 --- /dev/null +++ b/libs/assimp/code/AssetLib/STEPParser/STEPFileReader.h @@ -0,0 +1,71 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2022, 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 +following conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its + contributors may be used to endorse or promote products + 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 +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +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 +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 +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +---------------------------------------------------------------------- +*/ + +#ifndef INCLUDED_AI_STEPFILEREADER_H +#define INCLUDED_AI_STEPFILEREADER_H + +#include "AssetLib/Step/STEPFile.h" + +namespace Assimp { +namespace STEP { + +// -------------------------------------------------------------------------- +/// @brief Parsing a STEP file is a twofold procedure. +/// 1) read file header and return to caller, who checks if the +/// file is of a supported schema .. +DB* ReadFileHeader(std::shared_ptr<IOStream> stream); + +/// 2) read the actual file contents using a user-supplied set of +/// conversion functions to interpret the data. +void 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); + +/// @brief Helper to read a file. +template <size_t N, size_t N2> +inline +void ReadFile(DB& db,const EXPRESS::ConversionSchema& scheme, const char* const (&arr)[N], const char* const (&arr2)[N2]) { + return ReadFile(db,scheme,arr,N,arr2,N2); +} + +} // ! STEP +} // ! Assimp + +#endif // INCLUDED_AI_STEPFILEREADER_H |