232 lines
8.1 KiB
C++
232 lines
8.1 KiB
C++
/****************************************************************************
|
|
* Copyright (c) 2020 Zheng, Lei (realthunder) <realthunder.dev@gmail.com>*
|
|
* *
|
|
* This file is part of the FreeCAD CAx development system. *
|
|
* *
|
|
* This library is free software; you can redistribute it and/or *
|
|
* modify it under the terms of the GNU Library General Public *
|
|
* License as published by the Free Software Foundation; either *
|
|
* version 2 of the License, or (at your option) any later version. *
|
|
* *
|
|
* This library is distributed in the hope that it will be useful, *
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
* GNU Library General Public License for more details. *
|
|
* *
|
|
* You should have received a copy of the GNU Library General Public *
|
|
* License along with this library; see the file COPYING.LIB. If not, *
|
|
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
|
* Suite 330, Boston, MA 02111-1307, USA *
|
|
* *
|
|
****************************************************************************/
|
|
|
|
#include "PreCompiled.h"
|
|
|
|
#ifndef _PreComp_
|
|
#include <unordered_set>
|
|
#endif
|
|
|
|
#include "MappedName.h"
|
|
|
|
#include "Base/Console.h"
|
|
|
|
#include <boost/iostreams/device/array.hpp>
|
|
#include <boost/iostreams/stream.hpp>
|
|
|
|
|
|
FC_LOG_LEVEL_INIT("MappedName", true, 2); // NOLINT
|
|
|
|
namespace Data
|
|
{
|
|
|
|
void MappedName::compact() const
|
|
{
|
|
auto self = const_cast<MappedName*>(
|
|
this); // FIXME this is a workaround for a single call in ElementMap::addName()
|
|
|
|
if (this->raw) {
|
|
self->data = QByteArray(self->data.constData(), self->data.size());
|
|
self->raw = false;
|
|
}
|
|
}
|
|
|
|
|
|
int MappedName::findTagInElementName(long* tagOut,
|
|
int* lenOut,
|
|
std::string* postfixOut,
|
|
char* typeOut,
|
|
bool negative,
|
|
bool recursive) const
|
|
{
|
|
bool hex = true;
|
|
int pos = this->rfind(POSTFIX_TAG);
|
|
|
|
// Example name, POSTFIX_TAG == ;:H
|
|
// #94;:G0;XTR;:H19:8,F;:H1a,F;BND:-1:0;:H1b:10,F
|
|
// ^
|
|
// |
|
|
// pos
|
|
|
|
if (pos < 0) {
|
|
pos = this->rfind(POSTFIX_DECIMAL_TAG);
|
|
if (pos < 0) {
|
|
return -1;
|
|
}
|
|
hex = false;
|
|
}
|
|
int offset = pos + (int)POSTFIX_TAG_SIZE;
|
|
long _tag = 0;
|
|
int _len = 0;
|
|
char sep = 0;
|
|
char sep2 = 0;
|
|
char tp = 0;
|
|
char eof = 0;
|
|
|
|
int size {0};
|
|
const char* nameAsChars = this->toConstString(offset, size);
|
|
|
|
// check if the number followed by the tagPosfix is negative
|
|
bool isNegative = (nameAsChars[0] == '-');
|
|
if (isNegative) {
|
|
++nameAsChars;
|
|
--size;
|
|
}
|
|
boost::iostreams::stream<boost::iostreams::array_source> iss(nameAsChars, size);
|
|
if (!hex) {
|
|
// no hex is an older version of the encoding scheme
|
|
iss >> _tag >> sep;
|
|
}
|
|
else {
|
|
// The purpose of tagOut postfixOut is to encode one model operation. The
|
|
// 'tagOut' field is used to record the own object ID of that model shape,
|
|
// and the 'lenOut' field indicates the length of the operation codes
|
|
// before the tagOut postfixOut. These fields are in hex. The trailing 'F' is
|
|
// the shape typeOut of this element, 'F' for face, 'E' edge, and 'V' vertex.
|
|
//
|
|
// #94;:G0;XTR;:H19:8,F;:H1a,F;BND:-1:0;:H1b:10,F
|
|
// | | ^^ ^^
|
|
// | | | |
|
|
// ---lenOut = 0x10--- tagOut lenOut
|
|
|
|
iss >> std::hex;
|
|
// _tag field can be skipped, if it is 0
|
|
if (nameAsChars[0] == ',' || nameAsChars[0] == ':') {
|
|
iss >> sep;
|
|
}
|
|
else {
|
|
iss >> _tag >> sep;
|
|
}
|
|
}
|
|
|
|
if (isNegative) {
|
|
_tag = -_tag;
|
|
}
|
|
|
|
if (sep == ':') {
|
|
// ':' is followed by _len field.
|
|
//
|
|
// For decTagPostfix() (i.e. older encoding scheme), this is the length
|
|
// of the string before the entire postfixOut (A postfixOut may contain
|
|
// multiple segments usually separated by ELEMENT_MAP_PREFIX.
|
|
//
|
|
// For newer POSTFIX_TAG, this counts the number of characters that
|
|
// proceeds this tagOut postfixOut segment that forms the op code (see
|
|
// example above).
|
|
//
|
|
// The reason of this change is so that the postfixOut can stay the same
|
|
// regardless of the prefix, which can increase memory efficiency.
|
|
//
|
|
iss >> _len >> sep2 >> tp >> eof;
|
|
|
|
// The next separator to look for is either ':' for older tagOut postfixOut, or ','
|
|
if (!hex && sep2 == ':') {
|
|
sep2 = ',';
|
|
}
|
|
}
|
|
else if (hex && sep == ',') {
|
|
// ',' is followed by a single character that indicates the element typeOut.
|
|
iss >> tp >> eof;
|
|
sep = ':';
|
|
sep2 = ',';
|
|
}
|
|
|
|
if (_len < 0 || sep != ':' || sep2 != ',' || tp == 0 || eof != 0) {
|
|
return -1;
|
|
}
|
|
|
|
if (hex) {
|
|
if (pos - _len < 0) {
|
|
return -1;
|
|
}
|
|
if ((_len != 0) && recursive && (tagOut || lenOut)) {
|
|
// in case of recursive tagOut postfixOut (used by hierarchy element
|
|
// map), look for any embedded tagOut postfixOut
|
|
int next = MappedName::fromRawData(*this, pos - _len, _len).rfind(POSTFIX_TAG);
|
|
if (next >= 0) {
|
|
next += pos - _len;
|
|
// #94;:G0;XTR;:H19:8,F;:H1a,F;BND:-1:0;:H1b:10,F
|
|
// ^ ^
|
|
// | |
|
|
// next pos
|
|
//
|
|
// There maybe other operation codes after this embedded tagOut
|
|
// postfixOut, search for the separator.
|
|
//
|
|
int end {0};
|
|
if (pos == next) {
|
|
end = -1;
|
|
}
|
|
else {
|
|
end = MappedName::fromRawData(*this, next + 1, pos - next - 1)
|
|
.find(ELEMENT_MAP_PREFIX);
|
|
}
|
|
if (end >= 0) {
|
|
end += next + 1;
|
|
// #94;:G0;XTR;:H19:8,F;:H1a,F;BND:-1:0;:H1b:10,F
|
|
// ^
|
|
// |
|
|
// end
|
|
_len = pos - end;
|
|
// #94;:G0;XTR;:H19:8,F;:H1a,F;BND:-1:0;:H1b:10,F
|
|
// | |
|
|
// -- lenOut --
|
|
}
|
|
else {
|
|
_len = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Now convert the 'lenOut' field back to the length of the remaining name
|
|
//
|
|
// #94;:G0;XTR;:H19:8,F;:H1a,F;BND:-1:0;:H1b:10,F
|
|
// | |
|
|
// ----------- lenOut -----------
|
|
_len = pos - _len;
|
|
}
|
|
if (typeOut) {
|
|
*typeOut = tp;
|
|
}
|
|
if (tagOut) {
|
|
if (_tag == 0 && recursive) {
|
|
return MappedName(*this, 0, _len)
|
|
.findTagInElementName(tagOut, lenOut, postfixOut, typeOut, negative);
|
|
}
|
|
if (_tag > 0 || negative) {
|
|
*tagOut = _tag;
|
|
}
|
|
else {
|
|
*tagOut = -_tag;
|
|
}
|
|
}
|
|
if (lenOut) {
|
|
*lenOut = _len;
|
|
}
|
|
if (postfixOut) {
|
|
*postfixOut = this->toString(pos);
|
|
}
|
|
return pos;
|
|
}
|
|
|
|
} // namespace Data
|