| File: | libraries/libdxfrw/src/drw_entities.cpp |
| Warning: | line 14702, column 5 Called C++ object pointer is null |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /****************************************************************************** | |||
| 2 | ** libDXFrw - Library to read/write DXF files (ascii & binary) ** | |||
| 3 | ** ** | |||
| 4 | ** Copyright (C) 2016-2022 A. Stebich (librecad@mail.lordofbikes.de) ** | |||
| 5 | ** Copyright (C) 2011-2015 José F. Soriano, rallazz@gmail.com ** | |||
| 6 | ** Copyright (C) 2026 LibreCAD (librecad.org) ** | |||
| 7 | ** ** | |||
| 8 | ** This library is free software, licensed under the terms of the GNU ** | |||
| 9 | ** General Public License as published by the Free Software Foundation, ** | |||
| 10 | ** either version 2 of the License, or (at your option) any later version. ** | |||
| 11 | ** You should have received a copy of the GNU General Public License ** | |||
| 12 | ** along with this program. If not, see <http://www.gnu.org/licenses/>. ** | |||
| 13 | ******************************************************************************/ | |||
| 14 | ||||
| 15 | #include <algorithm> | |||
| 16 | #include <cctype> | |||
| 17 | #include <cstdint> | |||
| 18 | #include <cmath> | |||
| 19 | #include <cstdio> | |||
| 20 | #include <cstdlib> | |||
| 21 | #include <cstring> | |||
| 22 | #include <limits> | |||
| 23 | #include <vector> | |||
| 24 | #include "drw_entities.h" | |||
| 25 | #include "intern/dxfreader.h" | |||
| 26 | #include "intern/dxfparserlimits.h" | |||
| 27 | #include "intern/dwgbuffer.h" | |||
| 28 | #include "intern/dwgbufferw.h" | |||
| 29 | #include "intern/drw_textcodec.h" | |||
| 30 | #include "intern/drw_dbg.h" | |||
| 31 | #include "intern/drw_reserve.h" | |||
| 32 | #include "intern/dwgreader.h" | |||
| 33 | #include "intern/dwgsafety.h" | |||
| 34 | ||||
| 35 | namespace { | |||
| 36 | ||||
| 37 | struct EmbeddedMTextHandleInfo { | |||
| 38 | bool m_ownerHandle = false; | |||
| 39 | int m_numReactors = 0; | |||
| 40 | // AC1015 has no xdict bit; AC1018+ supplies it and uses 1 to suppress | |||
| 41 | // the embedded xdictionary handle. | |||
| 42 | std::uint8_t m_xDictFlag = 0; | |||
| 43 | bool m_hasAcDbColorHandle = false; | |||
| 44 | int m_ltFlags = 0; | |||
| 45 | int m_plotFlags = 0; | |||
| 46 | int m_materialFlag = 0; | |||
| 47 | int m_shadowFlag = 0; | |||
| 48 | bool m_hasFullVisualStyle = false; | |||
| 49 | bool m_hasFaceVisualStyle = false; | |||
| 50 | bool m_hasEdgeVisualStyle = false; | |||
| 51 | bool m_hasStyleHandle = true; | |||
| 52 | bool m_hasR2018AppIdHandle = false; | |||
| 53 | bool m_hasAnnotativeAppHandle = false; | |||
| 54 | }; | |||
| 55 | static bool parseEmbeddedMTextDwg(DRW::Version version, dwgBuffer *buf, | |||
| 56 | dwgBuffer *sBuf, DRW_MText& mtext, | |||
| 57 | EmbeddedMTextHandleInfo& info, | |||
| 58 | std::uint64_t bodyEndBit = | |||
| 59 | std::numeric_limits<std::uint64_t>::max(), | |||
| 60 | std::uint64_t stringEndBit = | |||
| 61 | std::numeric_limits<std::uint64_t>::max()); | |||
| 62 | static bool consumeEmbeddedMTextHandles( | |||
| 63 | DRW::Version version, dwgBuffer *buf, | |||
| 64 | const EmbeddedMTextHandleInfo& info, DRW_MText *mtext, | |||
| 65 | std::uint64_t handleEndBit = | |||
| 66 | std::numeric_limits<std::uint64_t>::max()); | |||
| 67 | ||||
| 68 | constexpr std::uint32_t kMaxTableRows = 10000; | |||
| 69 | constexpr std::uint32_t kMaxTableColumns = 1000; | |||
| 70 | constexpr std::uint32_t kMaxTableCells = 200000; | |||
| 71 | constexpr std::uint32_t kMaxTableItems = 100000; | |||
| 72 | constexpr std::uint32_t kMaxTableStringBytes = 16 * 1024 * 1024; | |||
| 73 | constexpr std::uint32_t kMaxTableCellAttributes = 10000; | |||
| 74 | constexpr std::int32_t kMaxLWPolylineVertices = 1000000; | |||
| 75 | constexpr std::int32_t kMaxSplineItems = 1000000; | |||
| 76 | constexpr std::int32_t kMaxSplineDegree = 1024; | |||
| 77 | constexpr std::int32_t kMaxHatchItems = DRW_Hatch::kMaxDxfItems; | |||
| 78 | constexpr std::int32_t kMaxMInsertCount = | |||
| 79 | std::numeric_limits<std::int16_t>::max(); | |||
| 80 | constexpr std::int32_t kMaxViewportFrozenLayers = 512; | |||
| 81 | constexpr std::int32_t kMaxMTextColumnHeights = 4096; | |||
| 82 | constexpr std::int32_t kMaxMLeaderItems = 5000; | |||
| 83 | constexpr std::int32_t kMaxLeaderVertices = 5000; | |||
| 84 | constexpr std::uint16_t kMaxLoftedSurfaceModelerFormatVersion = 3; | |||
| 85 | ||||
| 86 | constexpr std::int32_t kSplineFlagMethodFitPoints = 1; | |||
| 87 | constexpr std::int32_t kSplineFlagClosed = 4; | |||
| 88 | constexpr std::int32_t kSplineFlagUseKnotParameter = 8; | |||
| 89 | constexpr std::int32_t kSplineKnotParamCustom = 15; | |||
| 90 | ||||
| 91 | bool isValidCount(std::int32_t count, std::int32_t maxCount) { | |||
| 92 | return count >= 0 && count <= maxCount; | |||
| 93 | } | |||
| 94 | ||||
| 95 | bool readDxfIntInRange(const std::unique_ptr<dxfReader>& reader, | |||
| 96 | int minimum, int maximum, int& value) { | |||
| 97 | value = reader->getInt32(); | |||
| 98 | return value >= minimum && value <= maximum; | |||
| 99 | } | |||
| 100 | ||||
| 101 | int hexNibble(char c) { | |||
| 102 | if (c >= '0' && c <= '9') | |||
| 103 | return c - '0'; | |||
| 104 | if (c >= 'A' && c <= 'F') | |||
| 105 | return c - 'A' + 10; | |||
| 106 | if (c >= 'a' && c <= 'f') | |||
| 107 | return c - 'a' + 10; | |||
| 108 | return -1; | |||
| 109 | } | |||
| 110 | ||||
| 111 | bool decodeHexBytes(const std::string& hex, std::vector<std::uint8_t>& out) { | |||
| 112 | if ((hex.size() % 2) != 0) | |||
| 113 | return false; | |||
| 114 | ||||
| 115 | std::vector<std::uint8_t> decoded; | |||
| 116 | const std::size_t byteCount = hex.size() / 2; | |||
| 117 | if (byteCount > static_cast<std::size_t>(std::numeric_limits<int>::max()) | |||
| 118 | || !DRW::reserve(decoded, static_cast<int>(byteCount))) | |||
| 119 | return false; | |||
| 120 | for (std::size_t i = 0; i < hex.size(); i += 2) { | |||
| 121 | const int hi = hexNibble(hex[i]); | |||
| 122 | const int lo = hexNibble(hex[i + 1]); | |||
| 123 | if (hi < 0 || lo < 0) | |||
| 124 | return false; | |||
| 125 | decoded.push_back(static_cast<std::uint8_t>((hi << 4) | lo)); | |||
| 126 | } | |||
| 127 | ||||
| 128 | out = std::move(decoded); | |||
| 129 | return true; | |||
| 130 | } | |||
| 131 | ||||
| 132 | bool appendBytesChecked(std::vector<std::uint8_t>& destination, | |||
| 133 | const std::vector<std::uint8_t>& bytes, | |||
| 134 | std::size_t maxSize) { | |||
| 135 | if (destination.size() > maxSize | |||
| 136 | || bytes.size() > maxSize - destination.size()) | |||
| 137 | return false; | |||
| 138 | const std::size_t newSize = destination.size() + bytes.size(); | |||
| 139 | if (newSize > static_cast<std::size_t>(std::numeric_limits<int>::max()) | |||
| 140 | || !DRW::reserve(destination, static_cast<int>(newSize))) | |||
| 141 | return false; | |||
| 142 | try { | |||
| 143 | destination.insert(destination.end(), bytes.begin(), bytes.end()); | |||
| 144 | } catch (...) { | |||
| 145 | return false; | |||
| 146 | } | |||
| 147 | return true; | |||
| 148 | } | |||
| 149 | ||||
| 150 | bool appendTextBytesChecked(std::vector<std::uint8_t>& destination, | |||
| 151 | const std::string& text, | |||
| 152 | std::size_t maxSize) { | |||
| 153 | if (destination.size() > maxSize | |||
| 154 | || text.size() > maxSize - destination.size()) | |||
| 155 | return false; | |||
| 156 | const std::size_t newSize = destination.size() + text.size(); | |||
| 157 | if (newSize > static_cast<std::size_t>(std::numeric_limits<int>::max()) | |||
| 158 | || !DRW::reserve(destination, static_cast<int>(newSize))) | |||
| 159 | return false; | |||
| 160 | try { | |||
| 161 | destination.insert(destination.end(), text.begin(), text.end()); | |||
| 162 | } catch (...) { | |||
| 163 | return false; | |||
| 164 | } | |||
| 165 | return true; | |||
| 166 | } | |||
| 167 | ||||
| 168 | bool appendHexBytesChecked(std::string& destination, const std::string& hex, | |||
| 169 | std::size_t maxSize) { | |||
| 170 | if ((hex.size() & 1u) != 0u || destination.size() > maxSize) | |||
| 171 | return false; | |||
| 172 | const std::size_t byteCount = hex.size() / 2u; | |||
| 173 | if (byteCount > maxSize - destination.size() | |||
| 174 | || byteCount > static_cast<std::size_t>(std::numeric_limits<int>::max())) | |||
| 175 | return false; | |||
| 176 | ||||
| 177 | std::string decoded; | |||
| 178 | if (!DRW::reserve(decoded, static_cast<int>(byteCount))) | |||
| 179 | return false; | |||
| 180 | for (std::size_t i = 0; i < hex.size(); i += 2) { | |||
| 181 | const int hi = hexNibble(hex[i]); | |||
| 182 | const int lo = hexNibble(hex[i + 1]); | |||
| 183 | if (hi < 0 || lo < 0) | |||
| 184 | return false; | |||
| 185 | decoded.push_back(static_cast<char>((hi << 4) | lo)); | |||
| 186 | } | |||
| 187 | try { | |||
| 188 | destination.append(decoded); | |||
| 189 | } catch (...) { | |||
| 190 | return false; | |||
| 191 | } | |||
| 192 | return true; | |||
| 193 | } | |||
| 194 | ||||
| 195 | std::uint64_t currentDwgBit(const dwgBuffer *buf) { | |||
| 196 | return buf->getPosition() * 8 + buf->getBitPos(); | |||
| 197 | } | |||
| 198 | ||||
| 199 | bool leaderHasEndpointProjection(DRW::Version version) { | |||
| 200 | return version >= DRW::AC1014; | |||
| 201 | } | |||
| 202 | ||||
| 203 | bool leaderHasTextBox(DRW::Version version) { | |||
| 204 | // R2010+ files use the compact LEADER layout without these legacy fields. | |||
| 205 | return version <= DRW::AC1021; | |||
| 206 | } | |||
| 207 | ||||
| 208 | std::uint64_t tableBodyEndBit(DRW::Version version, | |||
| 209 | const dwgBuffer *stringBuf, | |||
| 210 | std::uint32_t objectSize) { | |||
| 211 | // AC1021 objects may legally omit the string footer when they have no | |||
| 212 | // detached text. Keep their complete object body available; AC1024+ | |||
| 213 | // frames have the unambiguous extended object-data boundary. | |||
| 214 | if (version > DRW::AC1021 && stringBuf != nullptr) | |||
| 215 | return currentDwgBit(stringBuf); | |||
| 216 | return objectSize; | |||
| 217 | } | |||
| 218 | ||||
| 219 | bool readTableBodyCount(DRW::Version version, dwgBuffer *buf, | |||
| 220 | std::uint64_t objectSize, std::uint32_t maximum, | |||
| 221 | std::uint32_t minimumBitsPerItem, | |||
| 222 | std::uint32_t& value) { | |||
| 223 | if (buf == nullptr || !buf->isGood()) | |||
| 224 | return false; | |||
| 225 | ||||
| 226 | dwgBuffer probe = buf->forkIndependent(); | |||
| 227 | const std::int32_t parsed = probe.getBitLong(); | |||
| 228 | if (!probe.isGood() || parsed < 0 | |||
| 229 | || static_cast<std::uint32_t>(parsed) > maximum) | |||
| 230 | return false; | |||
| 231 | ||||
| 232 | if (version >= DRW::AC1015 && objectSize != 0) { | |||
| 233 | const std::uint64_t current = currentDwgBit(&probe); | |||
| 234 | if (current > objectSize || (minimumBitsPerItem != 0 | |||
| 235 | && static_cast<std::uint64_t>(parsed) | |||
| 236 | > (objectSize - current) | |||
| 237 | / minimumBitsPerItem)) | |||
| 238 | return false; | |||
| 239 | } | |||
| 240 | ||||
| 241 | *buf = probe; | |||
| 242 | value = static_cast<std::uint32_t>(parsed); | |||
| 243 | return true; | |||
| 244 | } | |||
| 245 | ||||
| 246 | std::uint64_t proxyEntityEndBit(const dwgBuffer& buffer, | |||
| 247 | std::uint32_t objectSize) { | |||
| 248 | if (objectSize != 0) | |||
| 249 | return objectSize; | |||
| 250 | return buffer.size() > std::numeric_limits<std::uint64_t>::max() / 8u | |||
| 251 | ? std::numeric_limits<std::uint64_t>::max() | |||
| 252 | : static_cast<std::uint64_t>(buffer.size()) * 8u; | |||
| 253 | } | |||
| 254 | ||||
| 255 | bool entityBodyDataEndBit(const dwgBuffer& stringBuffer, | |||
| 256 | DRW::Version version, std::uint32_t objectSize, | |||
| 257 | std::uint64_t& endBit, | |||
| 258 | std::uint64_t* stringEndBit = nullptr) { | |||
| 259 | if (version <= DRW::AC1021 || objectSize == 0) { | |||
| 260 | endBit = proxyEntityEndBit(stringBuffer, objectSize); | |||
| 261 | if (stringEndBit != nullptr) | |||
| 262 | *stringEndBit = endBit; | |||
| 263 | return true; | |||
| 264 | } | |||
| 265 | ||||
| 266 | std::uint64_t stringStartBit = 0; | |||
| 267 | std::uint64_t parsedStringEndBit = 0; | |||
| 268 | if (!stringBuffer.getR2007StringStreamBounds( | |||
| 269 | objectSize, stringStartBit, parsedStringEndBit) | |||
| 270 | || stringStartBit > parsedStringEndBit | |||
| 271 | || parsedStringEndBit > objectSize | |||
| 272 | || currentDwgBit(&stringBuffer) != stringStartBit) { | |||
| 273 | return false; | |||
| 274 | } | |||
| 275 | endBit = stringStartBit; | |||
| 276 | if (stringEndBit != nullptr) | |||
| 277 | *stringEndBit = parsedStringEndBit; | |||
| 278 | return true; | |||
| 279 | } | |||
| 280 | ||||
| 281 | bool dwgHandleStreamEndBit(const dwgBuffer& buffer, DRW::Version version, | |||
| 282 | std::uint32_t objectSize, std::uint32_t handleBits, | |||
| 283 | std::uint64_t& endBit) { | |||
| 284 | if (version > DRW::AC1021) { | |||
| 285 | std::uint64_t totalBits = 0; | |||
| 286 | return dwgSafety::add(objectSize, handleBits, endBit) | |||
| 287 | && dwgSafety::multiply(buffer.size(), 8, totalBits) | |||
| 288 | && endBit <= totalBits; | |||
| 289 | } | |||
| 290 | return dwgSafety::multiply(buffer.size(), 8, endBit); | |||
| 291 | } | |||
| 292 | ||||
| 293 | bool proxyEntityHasBits(const dwgBuffer& buffer, std::uint64_t endBit, | |||
| 294 | std::uint64_t count) { | |||
| 295 | const std::uint64_t current = currentDwgBit(&buffer); | |||
| 296 | return current <= endBit && count <= endBit - current; | |||
| 297 | } | |||
| 298 | ||||
| 299 | bool readProxyEntityOptionalBitLong(dwgBuffer& buffer, std::uint64_t endBit, | |||
| 300 | bool& present, std::int32_t& value) { | |||
| 301 | present = false; | |||
| 302 | if (!proxyEntityHasBits(buffer, endBit, 2)) | |||
| 303 | return true; | |||
| 304 | ||||
| 305 | const std::uint8_t prefix = buffer.get2Bits(); | |||
| 306 | if (!buffer.isGood()) | |||
| 307 | return false; | |||
| 308 | if (prefix == 0) { | |||
| 309 | if (!proxyEntityHasBits(buffer, endBit, 32)) | |||
| 310 | return false; | |||
| 311 | value = static_cast<std::int32_t>(buffer.getRawLong32()); | |||
| 312 | } else if (prefix == 1) { | |||
| 313 | if (!proxyEntityHasBits(buffer, endBit, 8)) | |||
| 314 | return false; | |||
| 315 | value = static_cast<std::int32_t>(buffer.getRawChar8()); | |||
| 316 | } else { | |||
| 317 | value = 0; | |||
| 318 | } | |||
| 319 | present = buffer.isGood(); | |||
| 320 | return present; | |||
| 321 | } | |||
| 322 | ||||
| 323 | bool copyDwgBitRange(const dwgBuffer& source, std::uint64_t startBit, | |||
| 324 | std::uint64_t endBit, | |||
| 325 | std::vector<std::uint8_t>& data) { | |||
| 326 | data.clear(); | |||
| 327 | if (endBit <= startBit) | |||
| 328 | return true; | |||
| 329 | ||||
| 330 | const std::uint64_t sourceEnd = proxyEntityEndBit(source, 0); | |||
| 331 | if (endBit > sourceEnd) | |||
| 332 | return false; | |||
| 333 | const std::uint64_t startByte = startBit >> 3; | |||
| 334 | const std::uint64_t endByte = (endBit >> 3) + ((endBit & 7u) != 0); | |||
| 335 | const std::uint64_t byteCount = endByte - startByte; | |||
| 336 | if (endByte < startByte | |||
| 337 | || byteCount > std::numeric_limits<std::size_t>::max() | |||
| 338 | || byteCount > static_cast<std::uint64_t>(std::numeric_limits<int>::max()) | |||
| 339 | || !DRW::resize(data, static_cast<int>(byteCount))) | |||
| 340 | return false; | |||
| 341 | dwgBuffer copy = source; | |||
| 342 | if (!copy.setPosition(startByte)) | |||
| 343 | return false; | |||
| 344 | if ((startBit & 7u) != 0) { | |||
| 345 | copy.setBitPos(static_cast<std::uint8_t>(startBit & 7u)); | |||
| 346 | if (!copy.isGood()) | |||
| 347 | return false; | |||
| 348 | } | |||
| 349 | return data.empty() | |||
| 350 | || (copy.getBytes(data.data(), data.size()) && copy.isGood()); | |||
| 351 | } | |||
| 352 | ||||
| 353 | bool readBoundedBitShort(dwgBuffer& buffer, std::uint64_t endBit, | |||
| 354 | std::uint16_t& value) { | |||
| 355 | if (!proxyEntityHasBits(buffer, endBit, 2)) | |||
| 356 | return false; | |||
| 357 | ||||
| 358 | // BS has a two-bit selector followed by either no payload, one byte, or | |||
| 359 | // two bytes. Probe the selector on an independent cursor before touching | |||
| 360 | // the publishing cursor, so a frame boundary is checked exactly. | |||
| 361 | dwgBuffer probe = buffer.forkIndependent(); | |||
| 362 | const std::uint8_t selector = probe.get2Bits(); | |||
| 363 | if (!probe.isGood()) | |||
| 364 | return false; | |||
| 365 | const std::uint64_t bits = selector == 0 ? 18 | |||
| 366 | : selector == 1 ? 10 : 2; | |||
| 367 | if (!proxyEntityHasBits(buffer, endBit, bits)) | |||
| 368 | return false; | |||
| 369 | value = buffer.getBitShort(); | |||
| 370 | return buffer.isGood(); | |||
| 371 | } | |||
| 372 | ||||
| 373 | bool readBoundedRawChar8(dwgBuffer& buffer, std::uint64_t endBit, | |||
| 374 | std::uint8_t& value) { | |||
| 375 | if (!proxyEntityHasBits(buffer, endBit, 8)) | |||
| 376 | return false; | |||
| 377 | value = buffer.getRawChar8(); | |||
| 378 | return buffer.isGood(); | |||
| 379 | } | |||
| 380 | ||||
| 381 | bool readBounded2Bits(dwgBuffer& buffer, std::uint64_t endBit, | |||
| 382 | std::uint8_t& value) { | |||
| 383 | if (!proxyEntityHasBits(buffer, endBit, 2)) | |||
| 384 | return false; | |||
| 385 | value = buffer.get2Bits(); | |||
| 386 | return buffer.isGood(); | |||
| 387 | } | |||
| 388 | ||||
| 389 | bool readBoundedRawLong32(dwgBuffer& buffer, std::uint64_t endBit, | |||
| 390 | std::uint32_t& value) { | |||
| 391 | if (!proxyEntityHasBits(buffer, endBit, 32)) | |||
| 392 | return false; | |||
| 393 | value = buffer.getRawLong32(); | |||
| 394 | return buffer.isGood(); | |||
| 395 | } | |||
| 396 | ||||
| 397 | bool readBoundedBit(dwgBuffer& buffer, std::uint64_t endBit, bool& value) { | |||
| 398 | if (!proxyEntityHasBits(buffer, endBit, 1)) | |||
| 399 | return false; | |||
| 400 | value = buffer.getBit() != 0; | |||
| 401 | return buffer.isGood(); | |||
| 402 | } | |||
| 403 | ||||
| 404 | bool readBoundedBitLong(dwgBuffer& buffer, std::uint64_t endBit, | |||
| 405 | std::int32_t& value) { | |||
| 406 | if (!proxyEntityHasBits(buffer, endBit, 2)) | |||
| 407 | return false; | |||
| 408 | dwgBuffer probe = buffer.forkIndependent(); | |||
| 409 | const std::uint8_t selector = probe.get2Bits(); | |||
| 410 | if (!probe.isGood()) | |||
| 411 | return false; | |||
| 412 | const std::uint64_t bits = selector == 0 ? 34 | |||
| 413 | : selector == 1 ? 10 : 2; | |||
| 414 | if (!proxyEntityHasBits(buffer, endBit, bits)) | |||
| 415 | return false; | |||
| 416 | value = buffer.getBitLong(); | |||
| 417 | return buffer.isGood(); | |||
| 418 | } | |||
| 419 | ||||
| 420 | bool readBoundedBitLongLong(dwgBuffer& buffer, std::uint64_t endBit, | |||
| 421 | std::uint64_t& value) { | |||
| 422 | if (!proxyEntityHasBits(buffer, endBit, 3)) | |||
| 423 | return false; | |||
| 424 | dwgBuffer probe = buffer.forkIndependent(); | |||
| 425 | const std::uint8_t byteCount = probe.get3Bits(); | |||
| 426 | const std::uint64_t bits = 3u + static_cast<std::uint64_t>(byteCount) * 8u; | |||
| 427 | if (!probe.isGood() || !proxyEntityHasBits(buffer, endBit, bits)) | |||
| 428 | return false; | |||
| 429 | value = buffer.getBitLongLong(); | |||
| 430 | return buffer.isGood(); | |||
| 431 | } | |||
| 432 | ||||
| 433 | bool readBoundedBitDouble(dwgBuffer& buffer, std::uint64_t endBit, | |||
| 434 | double& value) { | |||
| 435 | if (!proxyEntityHasBits(buffer, endBit, 2)) | |||
| 436 | return false; | |||
| 437 | dwgBuffer probe = buffer.forkIndependent(); | |||
| 438 | const std::uint8_t selector = probe.get2Bits(); | |||
| 439 | if (!probe.isGood()) | |||
| 440 | return false; | |||
| 441 | const std::uint64_t bits = selector == 0 ? 66 : 2; | |||
| 442 | if (!proxyEntityHasBits(buffer, endBit, bits)) | |||
| 443 | return false; | |||
| 444 | dwgBuffer candidate = buffer.forkIndependent(); | |||
| 445 | const double parsed = candidate.getBitDouble(); | |||
| 446 | if (!candidate.isGood() || currentDwgBit(&candidate) > endBit | |||
| 447 | || !std::isfinite(parsed)) | |||
| 448 | return false; | |||
| 449 | buffer = candidate; | |||
| 450 | value = parsed; | |||
| 451 | return true; | |||
| 452 | } | |||
| 453 | ||||
| 454 | bool readBoundedBitCoord(dwgBuffer& buffer, std::uint64_t endBit, | |||
| 455 | DRW_Coord& value) { | |||
| 456 | return readBoundedBitDouble(buffer, endBit, value.x) | |||
| 457 | && readBoundedBitDouble(buffer, endBit, value.y) | |||
| 458 | && readBoundedBitDouble(buffer, endBit, value.z); | |||
| 459 | } | |||
| 460 | ||||
| 461 | bool readBoundedEnColor(dwgBuffer& buffer, std::uint64_t endBit, | |||
| 462 | DRW::Version version, std::uint32_t& value) { | |||
| 463 | if (!buffer.isGood() || currentDwgBit(&buffer) > endBit) | |||
| 464 | return false; | |||
| 465 | dwgBuffer probe = buffer.forkIndependent(); | |||
| 466 | const std::uint32_t parsed = probe.getEnColor(version); | |||
| 467 | if (!probe.isGood() || currentDwgBit(&probe) > endBit) | |||
| 468 | return false; | |||
| 469 | buffer = probe; | |||
| 470 | buffer.lastEnColorHadDbColorRef = probe.lastEnColorHadDbColorRef; | |||
| 471 | buffer.lastEnColorName = probe.lastEnColorName; | |||
| 472 | buffer.lastEnColorBookName = probe.lastEnColorBookName; | |||
| 473 | buffer.lastEnColorRgb = probe.lastEnColorRgb; | |||
| 474 | buffer.lastEnColorAlphaRaw = probe.lastEnColorAlphaRaw; | |||
| 475 | value = parsed; | |||
| 476 | return true; | |||
| 477 | } | |||
| 478 | ||||
| 479 | struct TableDwgBounds { | |||
| 480 | std::uint64_t bodyEndBit = std::numeric_limits<std::uint64_t>::max(); | |||
| 481 | std::uint64_t stringEndBit = std::numeric_limits<std::uint64_t>::max(); | |||
| 482 | std::uint64_t handleEndBit = std::numeric_limits<std::uint64_t>::max(); | |||
| 483 | }; | |||
| 484 | ||||
| 485 | std::uint64_t tableTextEndBit(const dwgBuffer *bodyBuf, | |||
| 486 | const dwgBuffer *textBuf, | |||
| 487 | const TableDwgBounds& bounds) { | |||
| 488 | return textBuf == bodyBuf ? bounds.bodyEndBit : bounds.stringEndBit; | |||
| 489 | } | |||
| 490 | ||||
| 491 | bool readBoundedRawShort16(dwgBuffer& buffer, std::uint64_t endBit, | |||
| 492 | std::uint16_t& value) { | |||
| 493 | if (!proxyEntityHasBits(buffer, endBit, 16)) | |||
| 494 | return false; | |||
| 495 | value = buffer.getRawShort16(); | |||
| 496 | return buffer.isGood(); | |||
| 497 | } | |||
| 498 | ||||
| 499 | bool skipTableBit(dwgBuffer& buffer, std::uint64_t endBit) { | |||
| 500 | bool value = false; | |||
| 501 | return readBoundedBit(buffer, endBit, value); | |||
| 502 | } | |||
| 503 | ||||
| 504 | bool skipTableBitShort(dwgBuffer& buffer, std::uint64_t endBit) { | |||
| 505 | std::uint16_t value = 0; | |||
| 506 | return readBoundedBitShort(buffer, endBit, value); | |||
| 507 | } | |||
| 508 | ||||
| 509 | bool skipTableBitLong(dwgBuffer& buffer, std::uint64_t endBit) { | |||
| 510 | std::int32_t value = 0; | |||
| 511 | return readBoundedBitLong(buffer, endBit, value); | |||
| 512 | } | |||
| 513 | ||||
| 514 | bool skipTableBitDouble(dwgBuffer& buffer, std::uint64_t endBit) { | |||
| 515 | double value = 0.0; | |||
| 516 | return readBoundedBitDouble(buffer, endBit, value); | |||
| 517 | } | |||
| 518 | ||||
| 519 | bool skipTableRawChar8(dwgBuffer& buffer, std::uint64_t endBit) { | |||
| 520 | std::uint8_t value = 0; | |||
| 521 | return readBoundedRawChar8(buffer, endBit, value); | |||
| 522 | } | |||
| 523 | ||||
| 524 | bool skipTableRawShort16(dwgBuffer& buffer, std::uint64_t endBit) { | |||
| 525 | std::uint16_t value = 0; | |||
| 526 | return readBoundedRawShort16(buffer, endBit, value); | |||
| 527 | } | |||
| 528 | ||||
| 529 | bool readBounded3BitDouble(dwgBuffer& buffer, std::uint64_t endBit, | |||
| 530 | DRW_Coord& value) { | |||
| 531 | dwgBuffer probe = buffer.forkIndependent(); | |||
| 532 | DRW_Coord parsed; | |||
| 533 | if (!readBoundedBitDouble(probe, endBit, parsed.x) | |||
| 534 | || !readBoundedBitDouble(probe, endBit, parsed.y) | |||
| 535 | || !readBoundedBitDouble(probe, endBit, parsed.z)) | |||
| 536 | return false; | |||
| 537 | buffer = probe; | |||
| 538 | value = parsed; | |||
| 539 | return true; | |||
| 540 | } | |||
| 541 | ||||
| 542 | bool readBoundedBytes(dwgBuffer& buffer, std::uint64_t endBit, | |||
| 543 | std::uint8_t *data, std::size_t size) { | |||
| 544 | std::uint64_t bits = 0; | |||
| 545 | if (!dwgSafety::multiply(static_cast<std::uint64_t>(size), 8, bits) | |||
| 546 | || !proxyEntityHasBits(buffer, endBit, bits)) | |||
| 547 | return false; | |||
| 548 | return size == 0 || (buffer.getBytes(data, size) && buffer.isGood()); | |||
| 549 | } | |||
| 550 | ||||
| 551 | bool readBoundedRawLong64(dwgBuffer& buffer, std::uint64_t endBit, | |||
| 552 | std::uint64_t& value) { | |||
| 553 | if (!proxyEntityHasBits(buffer, endBit, 64)) | |||
| 554 | return false; | |||
| 555 | dwgBuffer probe = buffer.forkIndependent(); | |||
| 556 | const std::uint64_t parsed = probe.getRawLong64(); | |||
| 557 | if (!probe.isGood()) | |||
| 558 | return false; | |||
| 559 | buffer = probe; | |||
| 560 | value = parsed; | |||
| 561 | return true; | |||
| 562 | } | |||
| 563 | ||||
| 564 | bool readBounded2RawDouble(dwgBuffer& buffer, std::uint64_t endBit, | |||
| 565 | DRW_Coord& value) { | |||
| 566 | if (!proxyEntityHasBits(buffer, endBit, 128)) | |||
| 567 | return false; | |||
| 568 | dwgBuffer probe = buffer.forkIndependent(); | |||
| 569 | DRW_Coord parsed = probe.get2RawDouble(); | |||
| 570 | if (!probe.isGood() | |||
| 571 | || !std::isfinite(parsed.x) | |||
| 572 | || !std::isfinite(parsed.y) | |||
| 573 | || !std::isfinite(parsed.z)) | |||
| 574 | return false; | |||
| 575 | parsed.z = 0.0; // 2RD carries only X and Y; keep the unused component defined. | |||
| 576 | buffer = probe; | |||
| 577 | value = parsed; | |||
| 578 | return true; | |||
| 579 | } | |||
| 580 | ||||
| 581 | bool readBoundedRawDouble(dwgBuffer& buffer, std::uint64_t endBit, | |||
| 582 | double& value) { | |||
| 583 | if (!proxyEntityHasBits(buffer, endBit, 64)) | |||
| 584 | return false; | |||
| 585 | dwgBuffer probe = buffer.forkIndependent(); | |||
| 586 | const double parsed = probe.getRawDouble(); | |||
| 587 | if (!probe.isGood() || currentDwgBit(&probe) > endBit | |||
| 588 | || !std::isfinite(parsed)) | |||
| 589 | return false; | |||
| 590 | buffer = probe; | |||
| 591 | value = parsed; | |||
| 592 | return true; | |||
| 593 | } | |||
| 594 | ||||
| 595 | bool readBoundedDwgHandle(dwgBuffer& buffer, std::uint64_t endBit, | |||
| 596 | std::uint32_t baseHandle, bool offset, | |||
| 597 | dwgHandle& value) { | |||
| 598 | if (!buffer.isGood() || currentDwgBit(&buffer) > endBit) | |||
| 599 | return false; | |||
| 600 | dwgBuffer probe = buffer.forkIndependent(); | |||
| 601 | dwgHandle parsed; | |||
| 602 | if (!readDwgHandleChecked(probe, baseHandle, offset, parsed) | |||
| 603 | || currentDwgBit(&probe) > endBit) | |||
| 604 | return false; | |||
| 605 | buffer = probe; | |||
| 606 | value = parsed; | |||
| 607 | return true; | |||
| 608 | } | |||
| 609 | ||||
| 610 | bool readBoundedDwgObjectId(dwgBuffer& buffer, std::uint64_t endBit, | |||
| 611 | std::uint32_t baseHandle, dwgHandle& raw, | |||
| 612 | dwgHandle& resolved) { | |||
| 613 | if (!buffer.isGood() || currentDwgBit(&buffer) > endBit) | |||
| 614 | return false; | |||
| 615 | ||||
| 616 | dwgBuffer rawProbe = buffer.forkIndependent(); | |||
| 617 | raw = rawProbe.getHandle(); | |||
| 618 | if (!rawProbe.isGood() || currentDwgBit(&rawProbe) > endBit) | |||
| 619 | return false; | |||
| 620 | ||||
| 621 | dwgBuffer resolvedProbe = buffer.forkIndependent(); | |||
| 622 | resolved = resolvedProbe.getOffsetHandle(baseHandle); | |||
| 623 | if (!resolvedProbe.isGood() || currentDwgBit(&resolvedProbe) > endBit) | |||
| 624 | return false; | |||
| 625 | ||||
| 626 | buffer = resolvedProbe; | |||
| 627 | return true; | |||
| 628 | } | |||
| 629 | ||||
| 630 | bool readBoundedVariableText(dwgBuffer& buffer, std::uint64_t endBit, | |||
| 631 | DRW::Version version, UTF8STRINGstd::string& value) { | |||
| 632 | if (!proxyEntityHasBits(buffer, endBit, 2)) | |||
| 633 | return false; | |||
| 634 | ||||
| 635 | dwgBuffer probe = buffer.forkIndependent(); | |||
| 636 | const std::uint16_t units = probe.getBitShort(); | |||
| 637 | if (!probe.isGood()) | |||
| 638 | return false; | |||
| 639 | ||||
| 640 | const std::uint64_t bitsPerUnit = version > DRW::AC1018 ? 16u : 8u; | |||
| 641 | std::uint64_t payloadBits = 0; | |||
| 642 | if (!dwgSafety::multiply(static_cast<std::uint64_t>(units), bitsPerUnit, | |||
| 643 | payloadBits) | |||
| 644 | || !proxyEntityHasBits(probe, endBit, payloadBits)) | |||
| 645 | return false; | |||
| 646 | ||||
| 647 | value = buffer.getVariableText(version, false); | |||
| 648 | return buffer.isGood() && currentDwgBit(&buffer) <= endBit; | |||
| 649 | } | |||
| 650 | ||||
| 651 | bool readBoundedDefaultDouble(dwgBuffer& buffer, std::uint64_t endBit, | |||
| 652 | double defaultValue, double& value) { | |||
| 653 | if (!proxyEntityHasBits(buffer, endBit, 2)) | |||
| 654 | return false; | |||
| 655 | dwgBuffer probe = buffer.forkIndependent(); | |||
| 656 | const std::uint8_t selector = probe.get2Bits(); | |||
| 657 | if (!probe.isGood()) | |||
| 658 | return false; | |||
| 659 | const std::uint64_t bits = selector == 0 ? 2 | |||
| 660 | : selector == 1 ? 34 | |||
| 661 | : selector == 2 ? 50 : 66; | |||
| 662 | if (!proxyEntityHasBits(buffer, endBit, bits)) | |||
| 663 | return false; | |||
| 664 | value = buffer.getDefaultDouble(defaultValue); | |||
| 665 | return buffer.isGood(); | |||
| 666 | } | |||
| 667 | ||||
| 668 | bool readBoundedThickness(dwgBuffer& buffer, std::uint64_t endBit, | |||
| 669 | bool modern, double& value) { | |||
| 670 | if (!modern) | |||
| 671 | return readBoundedBitDouble(buffer, endBit, value); | |||
| 672 | if (!proxyEntityHasBits(buffer, endBit, 1)) | |||
| 673 | return false; | |||
| 674 | dwgBuffer probe = buffer.forkIndependent(); | |||
| 675 | const bool isZero = probe.getBit() != 0; | |||
| 676 | if (!probe.isGood()) | |||
| 677 | return false; | |||
| 678 | buffer.getBit(); | |||
| 679 | if (!buffer.isGood()) | |||
| 680 | return false; | |||
| 681 | if (isZero) { | |||
| 682 | value = 0.0; | |||
| 683 | return true; | |||
| 684 | } | |||
| 685 | return readBoundedBitDouble(buffer, endBit, value); | |||
| 686 | } | |||
| 687 | ||||
| 688 | bool readBoundedExtrusion(dwgBuffer& buffer, std::uint64_t endBit, | |||
| 689 | bool modern, DRW_Coord& value) { | |||
| 690 | if (modern) { | |||
| 691 | if (!proxyEntityHasBits(buffer, endBit, 1)) | |||
| 692 | return false; | |||
| 693 | dwgBuffer probe = buffer.forkIndependent(); | |||
| 694 | const bool isDefault = probe.getBit() != 0; | |||
| 695 | if (!probe.isGood()) | |||
| 696 | return false; | |||
| 697 | buffer.getBit(); | |||
| 698 | if (!buffer.isGood()) | |||
| 699 | return false; | |||
| 700 | if (isDefault) { | |||
| 701 | value = DRW_Coord{0.0, 0.0, 1.0}; | |||
| 702 | return true; | |||
| 703 | } | |||
| 704 | } | |||
| 705 | ||||
| 706 | return readBoundedBitDouble(buffer, endBit, value.x) | |||
| 707 | && readBoundedBitDouble(buffer, endBit, value.y) | |||
| 708 | && readBoundedBitDouble(buffer, endBit, value.z); | |||
| 709 | } | |||
| 710 | ||||
| 711 | bool readBoundedCmColor(dwgBuffer& buffer, dwgBuffer *stringBuffer, | |||
| 712 | std::uint64_t endBit, DRW::Version version, | |||
| 713 | std::uint32_t& value, std::int32_t *rgb24 = nullptr, | |||
| 714 | bool *hasRgbColor = nullptr, | |||
| 715 | UTF8STRINGstd::string *outName = nullptr, | |||
| 716 | UTF8STRINGstd::string *outBookName = nullptr, | |||
| 717 | std::uint64_t stringEndBit = | |||
| 718 | std::numeric_limits<std::uint64_t>::max()) { | |||
| 719 | const bool separateStringBuffer = stringBuffer != nullptr | |||
| 720 | && stringBuffer != &buffer; | |||
| 721 | dwgBuffer bodyProbe = buffer.forkIndependent(); | |||
| 722 | dwgBuffer stringProbe = separateStringBuffer | |||
| 723 | ? stringBuffer->forkIndependent() : bodyProbe.forkIndependent(); | |||
| 724 | dwgBuffer *colorStringBuffer = separateStringBuffer | |||
| 725 | ? &stringProbe : &bodyProbe; | |||
| 726 | UTF8STRINGstd::string parsedName; | |||
| 727 | UTF8STRINGstd::string parsedBookName; | |||
| 728 | std::int32_t parsedRgb = -1; | |||
| 729 | bool parsedHasRgb = false; | |||
| 730 | const std::uint32_t parsed = bodyProbe.getCmColor( | |||
| 731 | version, &parsedRgb, colorStringBuffer, &parsedName, &parsedBookName, | |||
| 732 | &parsedHasRgb); | |||
| 733 | if (!bodyProbe.isGood() || !colorStringBuffer->isGood() | |||
| 734 | || currentDwgBit(&bodyProbe) > endBit | |||
| 735 | || (separateStringBuffer | |||
| 736 | && currentDwgBit(&stringProbe) > stringEndBit)) | |||
| 737 | return false; | |||
| 738 | buffer = bodyProbe; | |||
| 739 | if (separateStringBuffer) | |||
| 740 | *stringBuffer = stringProbe; | |||
| 741 | value = parsed; | |||
| 742 | if (outName != nullptr) | |||
| 743 | *outName = std::move(parsedName); | |||
| 744 | if (outBookName != nullptr) | |||
| 745 | *outBookName = std::move(parsedBookName); | |||
| 746 | if (rgb24 != nullptr) | |||
| 747 | *rgb24 = parsedRgb; | |||
| 748 | if (hasRgbColor != nullptr) | |||
| 749 | *hasRgbColor = parsedHasRgb; | |||
| 750 | return true; | |||
| 751 | } | |||
| 752 | ||||
| 753 | struct DwgTextBodyData { | |||
| 754 | DRW_Coord basePoint{0.0, 0.0, 0.0}; | |||
| 755 | DRW_Coord secPoint{0.0, 0.0, 0.0}; | |||
| 756 | DRW_Coord extPoint{0.0, 0.0, 1.0}; | |||
| 757 | double thickness = 0.0; | |||
| 758 | double oblique = 0.0; | |||
| 759 | double angle = 0.0; | |||
| 760 | double height = 0.0; | |||
| 761 | double widthscale = 1.0; | |||
| 762 | UTF8STRINGstd::string text; | |||
| 763 | int textgen = 0; | |||
| 764 | DRW_Text::HAlign alignH = DRW_Text::HLeft; | |||
| 765 | DRW_Text::VAlign alignV = DRW_Text::VBaseLine; | |||
| 766 | }; | |||
| 767 | ||||
| 768 | bool readBoundedDwgTextBody( | |||
| 769 | DRW::Version version, dwgBuffer& body, dwgBuffer& stringBuffer, | |||
| 770 | std::uint64_t bodyEndBit, std::uint64_t stringStartBit, | |||
| 771 | std::uint64_t stringEndBit, DwgTextBodyData& data) { | |||
| 772 | std::uint8_t dataFlags = 0; | |||
| 773 | if (version > DRW::AC1014) { | |||
| 774 | if (!readBoundedRawChar8(body, bodyEndBit, dataFlags)) | |||
| 775 | return false; | |||
| 776 | if (!(dataFlags & 0x01) | |||
| 777 | && !readBoundedRawDouble(body, bodyEndBit, data.basePoint.z)) | |||
| 778 | return false; | |||
| 779 | } else if (!readBoundedBitDouble(body, bodyEndBit, data.basePoint.z)) { | |||
| 780 | return false; | |||
| 781 | } | |||
| 782 | ||||
| 783 | if (!readBoundedRawDouble(body, bodyEndBit, data.basePoint.x) | |||
| 784 | || !readBoundedRawDouble(body, bodyEndBit, data.basePoint.y)) | |||
| 785 | return false; | |||
| 786 | ||||
| 787 | if (version > DRW::AC1014) { | |||
| 788 | if (!(dataFlags & 0x02)) { | |||
| 789 | if (!readBoundedDefaultDouble(body, bodyEndBit, | |||
| 790 | data.basePoint.x, data.secPoint.x) | |||
| 791 | || !readBoundedDefaultDouble(body, bodyEndBit, | |||
| 792 | data.basePoint.y, | |||
| 793 | data.secPoint.y)) | |||
| 794 | return false; | |||
| 795 | } else { | |||
| 796 | data.secPoint = data.basePoint; | |||
| 797 | } | |||
| 798 | } else if (!readBoundedRawDouble(body, bodyEndBit, data.secPoint.x) | |||
| 799 | || !readBoundedRawDouble(body, bodyEndBit, data.secPoint.y)) { | |||
| 800 | return false; | |||
| 801 | } | |||
| 802 | data.secPoint.z = data.basePoint.z; | |||
| 803 | ||||
| 804 | if (!readBoundedExtrusion(body, bodyEndBit, version > DRW::AC1014, | |||
| 805 | data.extPoint) | |||
| 806 | || !readBoundedThickness(body, bodyEndBit, version > DRW::AC1014, | |||
| 807 | data.thickness)) | |||
| 808 | return false; | |||
| 809 | ||||
| 810 | if (version > DRW::AC1014) { | |||
| 811 | if (!(dataFlags & 0x04) | |||
| 812 | && !readBoundedRawDouble(body, bodyEndBit, data.oblique)) | |||
| 813 | return false; | |||
| 814 | if (!(dataFlags & 0x08) | |||
| 815 | && !readBoundedRawDouble(body, bodyEndBit, data.angle)) | |||
| 816 | return false; | |||
| 817 | if (!readBoundedRawDouble(body, bodyEndBit, data.height)) | |||
| 818 | return false; | |||
| 819 | if (!(dataFlags & 0x10) | |||
| 820 | && !readBoundedRawDouble(body, bodyEndBit, data.widthscale)) | |||
| 821 | return false; | |||
| 822 | } else if (!readBoundedBitDouble(body, bodyEndBit, data.oblique) | |||
| 823 | || !readBoundedBitDouble(body, bodyEndBit, data.angle) | |||
| 824 | || !readBoundedBitDouble(body, bodyEndBit, data.height) | |||
| 825 | || !readBoundedBitDouble(body, bodyEndBit, data.widthscale)) { | |||
| 826 | return false; | |||
| 827 | } | |||
| 828 | data.angle *= ARAD57.29577951308232; | |||
| 829 | ||||
| 830 | if (version > DRW::AC1018 && stringStartBit >= stringEndBit) { | |||
| 831 | data.text.clear(); | |||
| 832 | } else if (!readBoundedVariableText(stringBuffer, stringEndBit, version, | |||
| 833 | data.text)) { | |||
| 834 | return false; | |||
| 835 | } | |||
| 836 | ||||
| 837 | std::uint16_t parsedTextgen = 0; | |||
| 838 | std::uint16_t parsedAlignH = 0; | |||
| 839 | std::uint16_t parsedAlignV = 0; | |||
| 840 | if (!(dataFlags & 0x20) | |||
| 841 | && !readBoundedBitShort(body, bodyEndBit, parsedTextgen)) | |||
| 842 | return false; | |||
| 843 | if (!(dataFlags & 0x40) | |||
| 844 | && !readBoundedBitShort(body, bodyEndBit, parsedAlignH)) | |||
| 845 | return false; | |||
| 846 | if (!(dataFlags & 0x80) | |||
| 847 | && !readBoundedBitShort(body, bodyEndBit, parsedAlignV)) | |||
| 848 | return false; | |||
| 849 | data.textgen = parsedTextgen; | |||
| 850 | data.alignH = static_cast<DRW_Text::HAlign>(parsedAlignH); | |||
| 851 | data.alignV = static_cast<DRW_Text::VAlign>(parsedAlignV); | |||
| 852 | ||||
| 853 | const auto finite = [](const DRW_Coord& point) { | |||
| 854 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 855 | && std::isfinite(point.z); | |||
| 856 | }; | |||
| 857 | return body.isGood() && stringBuffer.isGood() && finite(data.basePoint) | |||
| 858 | && finite(data.secPoint) && finite(data.extPoint) | |||
| 859 | && std::isfinite(data.thickness) && std::isfinite(data.oblique) | |||
| 860 | && std::isfinite(data.angle) && std::isfinite(data.height) | |||
| 861 | && std::isfinite(data.widthscale); | |||
| 862 | } | |||
| 863 | ||||
| 864 | bool readBoundedHatchGradient(dwgBuffer& body, dwgBuffer *stringBuffer, | |||
| 865 | std::uint64_t endBit, DRW::Version version, | |||
| 866 | int& isGradient, int& reserved, | |||
| 867 | double& angle, double& shift, int& singleColor, | |||
| 868 | double& tint, UTF8STRINGstd::string& name, | |||
| 869 | std::vector<DRW_Hatch::GradientStop>& colors, | |||
| 870 | std::uint64_t stringEndBit = | |||
| 871 | std::numeric_limits<std::uint64_t>::max()) { | |||
| 872 | std::int32_t parsedIsGradient = 0; | |||
| 873 | std::int32_t parsedReserved = 0; | |||
| 874 | std::int32_t parsedSingleColor = 0; | |||
| 875 | double parsedAngle = 0.0; | |||
| 876 | double parsedShift = 0.0; | |||
| 877 | double parsedTint = 0.0; | |||
| 878 | if (!readBoundedBitLong(body, endBit, parsedIsGradient) | |||
| 879 | || !readBoundedBitLong(body, endBit, parsedReserved) | |||
| 880 | || !readBoundedBitDouble(body, endBit, parsedAngle) | |||
| 881 | || !readBoundedBitDouble(body, endBit, parsedShift) | |||
| 882 | || !readBoundedBitLong(body, endBit, parsedSingleColor) | |||
| 883 | || !readBoundedBitDouble(body, endBit, parsedTint)) | |||
| 884 | return false; | |||
| 885 | ||||
| 886 | std::uint32_t colorCount = 0; | |||
| 887 | if (!readTableBodyCount(version, &body, endBit, kMaxHatchItems, 14, | |||
| 888 | colorCount)) | |||
| 889 | return false; | |||
| 890 | std::vector<DRW_Hatch::GradientStop> parsedColors; | |||
| 891 | if (!DRW::reserve(parsedColors, colorCount)) | |||
| 892 | return false; | |||
| 893 | for (std::uint32_t i = 0; i < colorCount; ++i) { | |||
| 894 | DRW_Hatch::GradientStop stop; | |||
| 895 | std::uint16_t aciColor = 0; | |||
| 896 | std::int32_t rgb = 0; | |||
| 897 | std::uint8_t ignoredColor = 0; | |||
| 898 | if (!readBoundedBitDouble(body, endBit, stop.value) | |||
| 899 | || !readBoundedBitShort(body, endBit, aciColor) | |||
| 900 | || !readBoundedBitLong(body, endBit, rgb) | |||
| 901 | || !readBoundedRawChar8(body, endBit, ignoredColor) | |||
| 902 | || !std::isfinite(stop.value)) | |||
| 903 | return false; | |||
| 904 | stop.aciColor = aciColor; | |||
| 905 | stop.rgb = rgb; | |||
| 906 | parsedColors.push_back(std::move(stop)); | |||
| 907 | } | |||
| 908 | ||||
| 909 | UTF8STRINGstd::string parsedName; | |||
| 910 | if (stringBuffer == nullptr | |||
| 911 | || !readBoundedVariableText(*stringBuffer, stringEndBit, version, | |||
| 912 | parsedName)) | |||
| 913 | return false; | |||
| 914 | ||||
| 915 | if (!std::isfinite(parsedAngle) || !std::isfinite(parsedShift) | |||
| 916 | || !std::isfinite(parsedTint)) | |||
| 917 | return false; | |||
| 918 | isGradient = parsedIsGradient; | |||
| 919 | reserved = parsedReserved; | |||
| 920 | angle = parsedAngle; | |||
| 921 | shift = parsedShift; | |||
| 922 | singleColor = parsedSingleColor; | |||
| 923 | tint = parsedTint; | |||
| 924 | name = std::move(parsedName); | |||
| 925 | colors = std::move(parsedColors); | |||
| 926 | return true; | |||
| 927 | } | |||
| 928 | ||||
| 929 | struct SurfaceDwgPayloadInfo { | |||
| 930 | bool acisEmpty = false; | |||
| 931 | int acisVersion = 0; | |||
| 932 | int modelerFormatVersion = 0; | |||
| 933 | int uIsolines = 0; | |||
| 934 | int vIsolines = 0; | |||
| 935 | bool revolvedFieldsValid = false; | |||
| 936 | std::uint32_t revolvedClassId = 0; | |||
| 937 | std::uint32_t revolvedId = 0; | |||
| 938 | DRW_Coord revolvedAxisPoint; | |||
| 939 | DRW_Coord revolvedAxisVector; | |||
| 940 | double revolvedAngle = 0.0; | |||
| 941 | double revolvedStartAngle = 0.0; | |||
| 942 | std::array<double, DRW_RevolvedSurface::kTransformSize> revolvedTransform{}; | |||
| 943 | double revolvedDraftAngle = 0.0; | |||
| 944 | double revolvedDraftStartDistance = 0.0; | |||
| 945 | double revolvedDraftEndDistance = 0.0; | |||
| 946 | double revolvedTwistAngle = 0.0; | |||
| 947 | bool revolvedSolid = false; | |||
| 948 | bool revolvedCloseToAxis = false; | |||
| 949 | bool extrudedFieldsValid = false; | |||
| 950 | DRW_Coord extrudedSweepVector; | |||
| 951 | std::array<double, DRW_ExtrudedSurface::kTransformSize> | |||
| 952 | extrudedTransform{}; | |||
| 953 | std::array<double, DRW_ExtrudedSurface::kTransformSize> | |||
| 954 | extrudedSweepEntityTransform{}; | |||
| 955 | std::array<double, DRW_ExtrudedSurface::kTransformSize> | |||
| 956 | extrudedPathEntityTransform{}; | |||
| 957 | double extrudedDraftAngle = 0.0; | |||
| 958 | double extrudedDraftStartDistance = 0.0; | |||
| 959 | double extrudedDraftEndDistance = 0.0; | |||
| 960 | double extrudedTwistAngle = 0.0; | |||
| 961 | double extrudedScaleFactor = 0.0; | |||
| 962 | double extrudedAlignAngle = 0.0; | |||
| 963 | bool extrudedSolid = false; | |||
| 964 | std::int32_t extrudedSweepAlignmentFlags = 0; | |||
| 965 | std::int32_t extrudedPathFlags = 0; | |||
| 966 | bool extrudedAlignStart = false; | |||
| 967 | bool extrudedBank = false; | |||
| 968 | bool extrudedBasePointSet = false; | |||
| 969 | bool extrudedSweepEntityTransformComputed = false; | |||
| 970 | bool extrudedPathEntityTransformComputed = false; | |||
| 971 | DRW_Coord extrudedReferenceVector; | |||
| 972 | bool sweptFieldsValid = false; | |||
| 973 | std::uint32_t sweptClassVersion = 0; | |||
| 974 | std::uint32_t sweptEntityId = 0; | |||
| 975 | std::vector<std::uint8_t> sweptData; | |||
| 976 | std::uint32_t sweptPathEntityId = 0; | |||
| 977 | std::vector<std::uint8_t> sweptPathData; | |||
| 978 | std::array<double, DRW_SweptSurface::kTransformSize> | |||
| 979 | sweptEntityTransform{}; | |||
| 980 | std::array<double, DRW_SweptSurface::kTransformSize> | |||
| 981 | sweptPathEntityTransform{}; | |||
| 982 | double sweptDraftAngle = 0.0; | |||
| 983 | double sweptDraftStartDistance = 0.0; | |||
| 984 | double sweptDraftEndDistance = 0.0; | |||
| 985 | double sweptTwistAngle = 0.0; | |||
| 986 | double sweptScaleFactor = 1.0; | |||
| 987 | double sweptAlignAngle = 0.0; | |||
| 988 | std::array<double, DRW_SweptSurface::kTransformSize> | |||
| 989 | sweptEntityTransformed{}; | |||
| 990 | std::array<double, DRW_SweptSurface::kTransformSize> | |||
| 991 | sweptPathEntityTransformed{}; | |||
| 992 | bool sweptSolid = false; | |||
| 993 | std::int32_t sweptAlignmentFlags = 0; | |||
| 994 | std::int32_t sweptPathFlags = 0; | |||
| 995 | bool sweptAlignStart = false; | |||
| 996 | bool sweptBank = false; | |||
| 997 | bool sweptBasePointSet = false; | |||
| 998 | bool sweptEntityTransformComputed = false; | |||
| 999 | bool sweptPathEntityTransformComputed = false; | |||
| 1000 | DRW_Coord sweptReferenceVector; | |||
| 1001 | bool loftedFieldsValid = false; | |||
| 1002 | std::array<double, DRW_LoftedSurface::kTransformSize> | |||
| 1003 | loftedEntityTransform{}; | |||
| 1004 | std::int32_t loftedPlaneNormalLoftingType = 0; | |||
| 1005 | double loftedStartDraftAngle = 0.0; | |||
| 1006 | double loftedEndDraftAngle = 0.0; | |||
| 1007 | double loftedStartDraftMagnitude = 0.0; | |||
| 1008 | double loftedEndDraftMagnitude = 0.0; | |||
| 1009 | bool loftedArcLengthParameterization = false; | |||
| 1010 | bool loftedNoTwist = true; | |||
| 1011 | bool loftedAlignDirection = true; | |||
| 1012 | bool loftedSimpleSurfaces = true; | |||
| 1013 | bool loftedClosedSurfaces = false; | |||
| 1014 | bool loftedSolid = false; | |||
| 1015 | bool loftedRuledSurface = false; | |||
| 1016 | bool loftedVirtualGuide = false; | |||
| 1017 | std::int32_t loftedNumCrossSections = 0; | |||
| 1018 | std::int32_t loftedNumGuideCurves = 0; | |||
| 1019 | bool nurbsFieldsValid = false; | |||
| 1020 | std::uint16_t nurbsShort170 = 0; | |||
| 1021 | bool nurbsCvHullDisplay = false; | |||
| 1022 | DRW_Coord nurbsUvec1; | |||
| 1023 | DRW_Coord nurbsVvec1; | |||
| 1024 | DRW_Coord nurbsUvec2; | |||
| 1025 | DRW_Coord nurbsVvec2; | |||
| 1026 | }; | |||
| 1027 | ||||
| 1028 | std::uint64_t surfaceDwgBit(const dwgBuffer& buffer) { | |||
| 1029 | return buffer.getPosition() * 8u + buffer.getBitPos(); | |||
| 1030 | } | |||
| 1031 | ||||
| 1032 | bool surfaceDwgHasBits(const dwgBuffer& buffer, std::uint64_t endBit, | |||
| 1033 | std::uint64_t count) { | |||
| 1034 | const std::uint64_t current = surfaceDwgBit(buffer); | |||
| 1035 | return current <= endBit && count <= endBit - current; | |||
| 1036 | } | |||
| 1037 | ||||
| 1038 | bool surfaceDwgReadBit(dwgBuffer& buffer, std::uint64_t endBit, | |||
| 1039 | std::uint8_t& value) { | |||
| 1040 | if (!surfaceDwgHasBits(buffer, endBit, 1)) | |||
| 1041 | return false; | |||
| 1042 | // Probe variable-width fields on a fork so a short object frame cannot | |||
| 1043 | // invalidate the reader before the caller re-anchors at its boundary. | |||
| 1044 | dwgBuffer candidate(buffer); | |||
| 1045 | value = candidate.getBit(); | |||
| 1046 | if (!candidate.isGood() || surfaceDwgBit(candidate) > endBit) | |||
| 1047 | return false; | |||
| 1048 | buffer = candidate; | |||
| 1049 | return true; | |||
| 1050 | } | |||
| 1051 | ||||
| 1052 | bool surfaceDwgReadRawChar(dwgBuffer& buffer, std::uint64_t endBit, | |||
| 1053 | std::uint8_t& value) { | |||
| 1054 | if (!surfaceDwgHasBits(buffer, endBit, 8)) | |||
| 1055 | return false; | |||
| 1056 | dwgBuffer candidate(buffer); | |||
| 1057 | value = candidate.getRawChar8(); | |||
| 1058 | if (!candidate.isGood() || surfaceDwgBit(candidate) > endBit) | |||
| 1059 | return false; | |||
| 1060 | buffer = candidate; | |||
| 1061 | return true; | |||
| 1062 | } | |||
| 1063 | ||||
| 1064 | bool surfaceDwgReadRawChar(dwgBuffer& buffer, std::uint64_t endBit) { | |||
| 1065 | std::uint8_t value = 0; | |||
| 1066 | return surfaceDwgReadRawChar(buffer, endBit, value); | |||
| 1067 | } | |||
| 1068 | ||||
| 1069 | bool surfaceDwgReadBitShort(dwgBuffer& buffer, std::uint64_t endBit, | |||
| 1070 | std::uint16_t& value) { | |||
| 1071 | if (!surfaceDwgHasBits(buffer, endBit, 2)) | |||
| 1072 | return false; | |||
| 1073 | dwgBuffer candidate(buffer); | |||
| 1074 | value = candidate.getBitShort(); | |||
| 1075 | if (!candidate.isGood() || surfaceDwgBit(candidate) > endBit) | |||
| 1076 | return false; | |||
| 1077 | buffer = candidate; | |||
| 1078 | return true; | |||
| 1079 | } | |||
| 1080 | ||||
| 1081 | bool surfaceDwgReadBitLong(dwgBuffer& buffer, std::uint64_t endBit, | |||
| 1082 | std::int32_t& value) { | |||
| 1083 | if (!surfaceDwgHasBits(buffer, endBit, 2)) | |||
| 1084 | return false; | |||
| 1085 | dwgBuffer candidate(buffer); | |||
| 1086 | value = candidate.getBitLong(); | |||
| 1087 | if (!candidate.isGood() || surfaceDwgBit(candidate) > endBit) | |||
| 1088 | return false; | |||
| 1089 | buffer = candidate; | |||
| 1090 | return true; | |||
| 1091 | } | |||
| 1092 | ||||
| 1093 | bool surfaceDwgReadDouble(dwgBuffer& buffer, std::uint64_t endBit, | |||
| 1094 | double& value) { | |||
| 1095 | if (!surfaceDwgHasBits(buffer, endBit, 2)) | |||
| 1096 | return false; | |||
| 1097 | dwgBuffer candidate(buffer); | |||
| 1098 | value = candidate.getBitDouble(); | |||
| 1099 | if (!candidate.isGood() || surfaceDwgBit(candidate) > endBit | |||
| 1100 | || !std::isfinite(value)) | |||
| 1101 | return false; | |||
| 1102 | buffer = candidate; | |||
| 1103 | return true; | |||
| 1104 | } | |||
| 1105 | ||||
| 1106 | bool surfaceDwgReadDouble(dwgBuffer& buffer, std::uint64_t endBit) { | |||
| 1107 | double value = 0.0; | |||
| 1108 | return surfaceDwgReadDouble(buffer, endBit, value); | |||
| 1109 | } | |||
| 1110 | ||||
| 1111 | bool surfaceDwgRead3BitDouble(dwgBuffer& buffer, std::uint64_t endBit) { | |||
| 1112 | return surfaceDwgReadDouble(buffer, endBit) | |||
| 1113 | && surfaceDwgReadDouble(buffer, endBit) | |||
| 1114 | && surfaceDwgReadDouble(buffer, endBit); | |||
| 1115 | } | |||
| 1116 | ||||
| 1117 | bool surfaceDwgRead3BitDouble(dwgBuffer& buffer, std::uint64_t endBit, | |||
| 1118 | DRW_Coord& value) { | |||
| 1119 | return surfaceDwgReadDouble(buffer, endBit, value.x) | |||
| 1120 | && surfaceDwgReadDouble(buffer, endBit, value.y) | |||
| 1121 | && surfaceDwgReadDouble(buffer, endBit, value.z); | |||
| 1122 | } | |||
| 1123 | ||||
| 1124 | bool surfaceDwgSkipBytes(dwgBuffer& buffer, std::uint64_t endBit, | |||
| 1125 | std::uint64_t count) { | |||
| 1126 | const std::uint64_t current = surfaceDwgBit(buffer); | |||
| 1127 | if (current > endBit | |||
| 1128 | || count > static_cast<std::uint64_t>(std::numeric_limits<std::int32_t>::max()) / 8u | |||
| 1129 | || count > (endBit - current) / 8u) | |||
| 1130 | return false; | |||
| 1131 | return buffer.moveBitPos(static_cast<std::int32_t>(count * 8u)) | |||
| 1132 | && buffer.isGood() && surfaceDwgBit(buffer) <= endBit; | |||
| 1133 | } | |||
| 1134 | ||||
| 1135 | bool surfaceDwgReadBytes(dwgBuffer& buffer, std::uint64_t endBit, | |||
| 1136 | std::int32_t count, std::size_t maxCount, | |||
| 1137 | std::vector<std::uint8_t>& data) { | |||
| 1138 | if (count < 0 || static_cast<std::size_t>(count) > maxCount | |||
| 1139 | || !surfaceDwgHasBits(buffer, endBit, | |||
| 1140 | static_cast<std::uint64_t>(count) * 8u)) | |||
| 1141 | return false; | |||
| 1142 | dwgBuffer candidate(buffer); | |||
| 1143 | std::vector<std::uint8_t> decoded; | |||
| 1144 | if (!DRW::resize(decoded, count)) | |||
| 1145 | return false; | |||
| 1146 | for (std::uint8_t& value : decoded) { | |||
| 1147 | if (!surfaceDwgReadRawChar(candidate, endBit, value)) | |||
| 1148 | return false; | |||
| 1149 | } | |||
| 1150 | data = std::move(decoded); | |||
| 1151 | buffer = candidate; | |||
| 1152 | return true; | |||
| 1153 | } | |||
| 1154 | ||||
| 1155 | std::uint8_t surfaceDwgPeekByte(const std::vector<std::uint8_t>& data, | |||
| 1156 | std::size_t index, std::uint8_t bit) { | |||
| 1157 | if (index >= data.size()) | |||
| 1158 | return 0; | |||
| 1159 | if (bit == 0) | |||
| 1160 | return data[index]; | |||
| 1161 | const std::uint8_t next = index + 1 < data.size() ? data[index + 1] : 0; | |||
| 1162 | return static_cast<std::uint8_t>((data[index] << bit) | (next >> (8 - bit))); | |||
| 1163 | } | |||
| 1164 | ||||
| 1165 | std::size_t surfaceDwgFindMarker(const std::vector<std::uint8_t>& data, | |||
| 1166 | std::size_t start, std::uint8_t bit, | |||
| 1167 | const std::uint8_t* marker, | |||
| 1168 | std::size_t markerSize) { | |||
| 1169 | if (marker == nullptr || markerSize == 0 || data.size() < markerSize | |||
| 1170 | || start > data.size() - markerSize) | |||
| 1171 | return std::numeric_limits<std::size_t>::max(); | |||
| 1172 | for (std::size_t index = start; index <= data.size() - markerSize; ++index) { | |||
| 1173 | bool matched = true; | |||
| 1174 | for (std::size_t offset = 0; offset < markerSize; ++offset) { | |||
| 1175 | if (surfaceDwgPeekByte(data, index + offset, bit) != marker[offset]) { | |||
| 1176 | matched = false; | |||
| 1177 | break; | |||
| 1178 | } | |||
| 1179 | } | |||
| 1180 | if (matched) | |||
| 1181 | return index; | |||
| 1182 | } | |||
| 1183 | return std::numeric_limits<std::size_t>::max(); | |||
| 1184 | } | |||
| 1185 | ||||
| 1186 | bool surfaceDwgSkipAcis(dwgBuffer& buffer, const std::vector<std::uint8_t>& data, | |||
| 1187 | std::uint64_t endBit, bool& acisEmpty, int& acisVersion) { | |||
| 1188 | std::uint8_t empty = 0; | |||
| 1189 | if (!surfaceDwgReadBit(buffer, endBit, empty)) | |||
| 1190 | return false; | |||
| 1191 | acisEmpty = empty != 0; | |||
| 1192 | if (acisEmpty) | |||
| 1193 | return true; | |||
| 1194 | ||||
| 1195 | std::uint8_t unused = 0; | |||
| 1196 | std::uint16_t version = 0; | |||
| 1197 | if (!surfaceDwgReadBit(buffer, endBit, unused) | |||
| 1198 | || !surfaceDwgReadBitShort(buffer, endBit, version)) | |||
| 1199 | return false; | |||
| 1200 | acisVersion = static_cast<int>(version); | |||
| 1201 | ||||
| 1202 | if (version == 2) { | |||
| 1203 | static constexpr std::uint8_t endAcis[] = { | |||
| 1204 | 0x0E, 0x03, 0x45, 0x6E, 0x64, 0x0E, 0x02, 0x6F, 0x66, 0x0E, | |||
| 1205 | 0x04, 0x41, 0x43, 0x49, 0x53, 0x0D, 0x04, 0x64, 0x61, 0x74, | |||
| 1206 | 0x61}; | |||
| 1207 | static constexpr std::uint8_t endAsm[] = { | |||
| 1208 | 0x0E, 0x03, 0x45, 0x6E, 0x64, 0x0E, 0x02, 0x6F, 0x66, 0x0E, | |||
| 1209 | 0x03, 0x41, 0x53, 0x4D, 0x0D, 0x04, 0x64, 0x61, 0x74, 0x61}; | |||
| 1210 | const std::size_t start = static_cast<std::size_t>(buffer.getPosition()); | |||
| 1211 | const std::uint8_t bit = buffer.getBitPos(); | |||
| 1212 | std::size_t marker = surfaceDwgFindMarker( | |||
| 1213 | data, start, bit, endAcis, sizeof(endAcis)); | |||
| 1214 | std::size_t markerSize = sizeof(endAcis); | |||
| 1215 | if (marker == std::numeric_limits<std::size_t>::max()) { | |||
| 1216 | marker = surfaceDwgFindMarker( | |||
| 1217 | data, start, bit, endAsm, sizeof(endAsm)); | |||
| 1218 | markerSize = sizeof(endAsm); | |||
| 1219 | } | |||
| 1220 | if (marker == std::numeric_limits<std::size_t>::max() | |||
| 1221 | || marker < start) | |||
| 1222 | return false; | |||
| 1223 | return surfaceDwgSkipBytes(buffer, endBit, | |||
| 1224 | marker - start + markerSize); | |||
| 1225 | } | |||
| 1226 | ||||
| 1227 | for (std::uint32_t block = 0; block < 65536u; ++block) { | |||
| 1228 | std::int32_t blockSize = 0; | |||
| 1229 | if (!surfaceDwgReadBitLong(buffer, endBit, blockSize)) | |||
| 1230 | return false; | |||
| 1231 | if (blockSize == 0) | |||
| 1232 | return true; | |||
| 1233 | if (blockSize < 0 | |||
| 1234 | || !surfaceDwgSkipBytes(buffer, endBit, | |||
| 1235 | static_cast<std::uint32_t>(blockSize))) | |||
| 1236 | return false; | |||
| 1237 | } | |||
| 1238 | return false; | |||
| 1239 | } | |||
| 1240 | ||||
| 1241 | bool surfaceDwgSkipWire(dwgBuffer& buffer, std::uint64_t endBit, | |||
| 1242 | DRW::Version version) { | |||
| 1243 | if (!surfaceDwgReadRawChar(buffer, endBit)) | |||
| 1244 | return false; | |||
| 1245 | std::int32_t ignored = 0; | |||
| 1246 | if (!surfaceDwgReadBitLong(buffer, endBit, ignored)) | |||
| 1247 | return false; | |||
| 1248 | std::uint16_t color = 0; | |||
| 1249 | if (version < DRW::AC1018) { | |||
| 1250 | if (!surfaceDwgReadBitShort(buffer, endBit, color)) | |||
| 1251 | return false; | |||
| 1252 | } else if (!surfaceDwgReadBitLong(buffer, endBit, ignored)) { | |||
| 1253 | return false; | |||
| 1254 | } | |||
| 1255 | if (!surfaceDwgReadBitLong(buffer, endBit, ignored)) | |||
| 1256 | return false; | |||
| 1257 | ||||
| 1258 | std::int32_t pointCount = 0; | |||
| 1259 | if (!surfaceDwgReadBitLong(buffer, endBit, pointCount) | |||
| 1260 | || pointCount < 0 || pointCount > 1000000) | |||
| 1261 | return false; | |||
| 1262 | for (std::int32_t point = 0; point < pointCount; ++point) { | |||
| 1263 | if (!surfaceDwgRead3BitDouble(buffer, endBit)) | |||
| 1264 | return false; | |||
| 1265 | } | |||
| 1266 | ||||
| 1267 | std::uint8_t transformPresent = 0; | |||
| 1268 | if (!surfaceDwgReadBit(buffer, endBit, transformPresent)) | |||
| 1269 | return false; | |||
| 1270 | if (transformPresent != 0) { | |||
| 1271 | for (int field = 0; field < 5; ++field) { | |||
| 1272 | if (!surfaceDwgRead3BitDouble(buffer, endBit)) | |||
| 1273 | return false; | |||
| 1274 | } | |||
| 1275 | for (int field = 0; field < 3; ++field) { | |||
| 1276 | if (!surfaceDwgReadBit(buffer, endBit, transformPresent)) | |||
| 1277 | return false; | |||
| 1278 | } | |||
| 1279 | } | |||
| 1280 | return true; | |||
| 1281 | } | |||
| 1282 | ||||
| 1283 | bool surfaceDwgSkipCommon3dSolid(dwgBuffer& buffer, std::uint64_t endBit, | |||
| 1284 | DRW::Version version, int acisVersion) { | |||
| 1285 | std::uint8_t present = 0; | |||
| 1286 | if (!surfaceDwgReadBit(buffer, endBit, present)) | |||
| 1287 | return false; | |||
| 1288 | if (present != 0) { | |||
| 1289 | if (!surfaceDwgReadBit(buffer, endBit, present)) | |||
| 1290 | return false; | |||
| 1291 | if (present != 0 && !surfaceDwgRead3BitDouble(buffer, endBit)) | |||
| 1292 | return false; | |||
| 1293 | ||||
| 1294 | std::int32_t ignored = 0; | |||
| 1295 | if (!surfaceDwgReadBitLong(buffer, endBit, ignored) | |||
| 1296 | || !surfaceDwgReadBit(buffer, endBit, present)) | |||
| 1297 | return false; | |||
| 1298 | if (present != 0) { | |||
| 1299 | std::int32_t count = 0; | |||
| 1300 | if (!surfaceDwgReadBitLong(buffer, endBit, count) | |||
| 1301 | || count < 0 || count > 1000000) | |||
| 1302 | return false; | |||
| 1303 | for (std::int32_t i = 0; i < count; ++i) { | |||
| 1304 | if (!surfaceDwgSkipWire(buffer, endBit, version)) | |||
| 1305 | return false; | |||
| 1306 | } | |||
| 1307 | if (!surfaceDwgReadBitLong(buffer, endBit, count) | |||
| 1308 | || count < 0 || count > 1000000) | |||
| 1309 | return false; | |||
| 1310 | for (std::int32_t i = 0; i < count; ++i) { | |||
| 1311 | if (!surfaceDwgReadBitLong(buffer, endBit, ignored) | |||
| 1312 | || !surfaceDwgRead3BitDouble(buffer, endBit) | |||
| 1313 | || !surfaceDwgRead3BitDouble(buffer, endBit) | |||
| 1314 | || !surfaceDwgRead3BitDouble(buffer, endBit) | |||
| 1315 | || !surfaceDwgReadBit(buffer, endBit, present) | |||
| 1316 | || !surfaceDwgReadBit(buffer, endBit, present)) | |||
| 1317 | return false; | |||
| 1318 | if (present != 0) { | |||
| 1319 | std::int32_t wireCount = 0; | |||
| 1320 | if (!surfaceDwgReadBitLong(buffer, endBit, wireCount) | |||
| 1321 | || wireCount < 0 || wireCount > 1000000) | |||
| 1322 | return false; | |||
| 1323 | for (std::int32_t wire = 0; wire < wireCount; ++wire) { | |||
| 1324 | if (!surfaceDwgSkipWire(buffer, endBit, version)) | |||
| 1325 | return false; | |||
| 1326 | } | |||
| 1327 | } | |||
| 1328 | } | |||
| 1329 | } | |||
| 1330 | } | |||
| 1331 | ||||
| 1332 | if (!surfaceDwgReadBit(buffer, endBit, present)) | |||
| 1333 | return false; | |||
| 1334 | if (acisVersion > 1 && version >= DRW::AC1021) { | |||
| 1335 | std::int32_t count = 0; | |||
| 1336 | if (!surfaceDwgReadBitLong(buffer, endBit, count) | |||
| 1337 | || count < 0 || count > 1000000) | |||
| 1338 | return false; | |||
| 1339 | for (std::int32_t i = 0; i < count; ++i) { | |||
| 1340 | std::int32_t ignored = 0; | |||
| 1341 | if (!surfaceDwgReadBitLong(buffer, endBit, ignored) | |||
| 1342 | || !surfaceDwgReadBitLong(buffer, endBit, ignored)) | |||
| 1343 | return false; | |||
| 1344 | } | |||
| 1345 | } | |||
| 1346 | if (version >= DRW::AC1027) { | |||
| 1347 | if (!surfaceDwgReadBit(buffer, endBit, present)) | |||
| 1348 | return false; | |||
| 1349 | std::int32_t ignored = 0; | |||
| 1350 | std::uint16_t ignoredShort = 0; | |||
| 1351 | if (!surfaceDwgReadBitLong(buffer, endBit, ignored) | |||
| 1352 | || !surfaceDwgReadBitShort(buffer, endBit, ignoredShort) | |||
| 1353 | || !surfaceDwgReadBitShort(buffer, endBit, ignoredShort) | |||
| 1354 | || !surfaceDwgSkipBytes(buffer, endBit, 8) | |||
| 1355 | || !surfaceDwgReadBitLong(buffer, endBit, ignored)) | |||
| 1356 | return false; | |||
| 1357 | } | |||
| 1358 | return true; | |||
| 1359 | } | |||
| 1360 | ||||
| 1361 | bool surfaceHasModelerFormatVersion(DRW::ETYPE type) { | |||
| 1362 | switch (type) { | |||
| 1363 | case DRW::PLANESURFACE: | |||
| 1364 | case DRW::LOFTEDSURFACE: | |||
| 1365 | case DRW::REVOLVEDSURFACE: | |||
| 1366 | case DRW::SWEPTSURFACE: | |||
| 1367 | return true; | |||
| 1368 | case DRW::EXTRUDEDSURFACE: | |||
| 1369 | case DRW::NURBSURFACE: | |||
| 1370 | default: | |||
| 1371 | return false; | |||
| 1372 | } | |||
| 1373 | } | |||
| 1374 | ||||
| 1375 | std::uint16_t surfaceModelerFormatVersionLimit(DRW::ETYPE type) { | |||
| 1376 | return type == DRW::LOFTEDSURFACE ? kMaxLoftedSurfaceModelerFormatVersion | |||
| 1377 | : std::numeric_limits<std::uint16_t>::max(); | |||
| 1378 | } | |||
| 1379 | ||||
| 1380 | bool readSurfaceDwgPayload(const std::vector<std::uint8_t>& data, | |||
| 1381 | std::uint64_t bitSize, DRW::Version version, | |||
| 1382 | DRW::ETYPE type, | |||
| 1383 | bool hasModelerFormatVersion, | |||
| 1384 | std::uint16_t modelerFormatVersionLimit, | |||
| 1385 | SurfaceDwgPayloadInfo& info) { | |||
| 1386 | if (data.empty() || bitSize == 0 | |||
| 1387 | || bitSize > static_cast<std::uint64_t>(data.size()) * 8u) | |||
| 1388 | return false; | |||
| 1389 | ||||
| 1390 | std::vector<std::uint8_t> payload = data; | |||
| 1391 | dwgBuffer buffer(payload.data(), payload.size()); | |||
| 1392 | const std::uint64_t endBit = bitSize; | |||
| 1393 | bool acisEmpty = false; | |||
| 1394 | int acisVersion = 0; | |||
| 1395 | if (!surfaceDwgSkipAcis(buffer, payload, endBit, acisEmpty, acisVersion)) | |||
| 1396 | return false; | |||
| 1397 | if (!acisEmpty | |||
| 1398 | && !surfaceDwgSkipCommon3dSolid(buffer, endBit, version, acisVersion)) | |||
| 1399 | return false; | |||
| 1400 | ||||
| 1401 | std::uint16_t modelerFormatVersion = 0; | |||
| 1402 | std::uint16_t uIsolines = 0; | |||
| 1403 | std::uint16_t vIsolines = 0; | |||
| 1404 | if ((hasModelerFormatVersion | |||
| 1405 | && !surfaceDwgReadBitShort(buffer, endBit, modelerFormatVersion)) | |||
| 1406 | || !surfaceDwgReadBitShort(buffer, endBit, uIsolines) | |||
| 1407 | || !surfaceDwgReadBitShort(buffer, endBit, vIsolines)) { | |||
| 1408 | return false; | |||
| 1409 | } | |||
| 1410 | if (hasModelerFormatVersion | |||
| 1411 | && modelerFormatVersion > modelerFormatVersionLimit) | |||
| 1412 | return false; | |||
| 1413 | ||||
| 1414 | if (type == DRW::EXTRUDEDSURFACE) { | |||
| 1415 | // DWG stores SweepOptions before the sweep vector and its transform; | |||
| 1416 | // keep the candidate isolated because the same fields have a | |||
| 1417 | // different order in the DXF subclass. | |||
| 1418 | dwgBuffer candidate = buffer; | |||
| 1419 | std::array<double, DRW_ExtrudedSurface::kTransformSize> | |||
| 1420 | sweepEntityTransform{}; | |||
| 1421 | std::array<double, DRW_ExtrudedSurface::kTransformSize> | |||
| 1422 | pathEntityTransform{}; | |||
| 1423 | std::array<double, DRW_ExtrudedSurface::kTransformSize> | |||
| 1424 | extrudedTransform{}; | |||
| 1425 | double draftAngle = 0.0; | |||
| 1426 | double draftStartDistance = 0.0; | |||
| 1427 | double draftEndDistance = 0.0; | |||
| 1428 | double twistAngle = 0.0; | |||
| 1429 | double scaleFactor = 0.0; | |||
| 1430 | double alignAngle = 0.0; | |||
| 1431 | std::uint8_t solid = 0; | |||
| 1432 | std::uint16_t sweepAlignmentFlags = 0; | |||
| 1433 | std::uint16_t pathFlags = 0; | |||
| 1434 | std::uint8_t alignStart = 0; | |||
| 1435 | std::uint8_t bank = 0; | |||
| 1436 | std::uint8_t basePointSet = 0; | |||
| 1437 | std::uint8_t sweepEntityTransformComputed = 0; | |||
| 1438 | std::uint8_t pathEntityTransformComputed = 0; | |||
| 1439 | DRW_Coord referenceVector; | |||
| 1440 | DRW_Coord sweepVector; | |||
| 1441 | auto readMatrix = [&](std::array<double, | |||
| 1442 | DRW_ExtrudedSurface::kTransformSize>& matrix) { | |||
| 1443 | for (double& value : matrix) { | |||
| 1444 | if (!surfaceDwgReadDouble(candidate, endBit, value)) | |||
| 1445 | return false; | |||
| 1446 | } | |||
| 1447 | return true; | |||
| 1448 | }; | |||
| 1449 | bool valid = surfaceDwgReadDouble(candidate, endBit, draftAngle) | |||
| 1450 | && surfaceDwgReadDouble(candidate, endBit, draftStartDistance) | |||
| 1451 | && surfaceDwgReadDouble(candidate, endBit, draftEndDistance) | |||
| 1452 | && surfaceDwgReadDouble(candidate, endBit, twistAngle) | |||
| 1453 | && surfaceDwgReadDouble(candidate, endBit, scaleFactor) | |||
| 1454 | && surfaceDwgReadDouble(candidate, endBit, alignAngle) | |||
| 1455 | && readMatrix(sweepEntityTransform) | |||
| 1456 | && readMatrix(pathEntityTransform) | |||
| 1457 | && surfaceDwgReadBit(candidate, endBit, solid) | |||
| 1458 | && surfaceDwgReadBitShort(candidate, endBit, sweepAlignmentFlags) | |||
| 1459 | && surfaceDwgReadBitShort(candidate, endBit, pathFlags) | |||
| 1460 | && surfaceDwgReadBit(candidate, endBit, alignStart) | |||
| 1461 | && surfaceDwgReadBit(candidate, endBit, bank) | |||
| 1462 | && surfaceDwgReadBit(candidate, endBit, basePointSet) | |||
| 1463 | && surfaceDwgReadBit(candidate, endBit, sweepEntityTransformComputed) | |||
| 1464 | && surfaceDwgReadBit(candidate, endBit, pathEntityTransformComputed) | |||
| 1465 | && surfaceDwgRead3BitDouble(candidate, endBit, referenceVector) | |||
| 1466 | && surfaceDwgRead3BitDouble(candidate, endBit, sweepVector) | |||
| 1467 | && readMatrix(extrudedTransform); | |||
| 1468 | if (valid) { | |||
| 1469 | info.extrudedFieldsValid = true; | |||
| 1470 | info.extrudedSweepVector = sweepVector; | |||
| 1471 | info.extrudedTransform = extrudedTransform; | |||
| 1472 | info.extrudedSweepEntityTransform = sweepEntityTransform; | |||
| 1473 | info.extrudedPathEntityTransform = pathEntityTransform; | |||
| 1474 | info.extrudedDraftAngle = draftAngle; | |||
| 1475 | info.extrudedDraftStartDistance = draftStartDistance; | |||
| 1476 | info.extrudedDraftEndDistance = draftEndDistance; | |||
| 1477 | info.extrudedTwistAngle = twistAngle; | |||
| 1478 | info.extrudedScaleFactor = scaleFactor; | |||
| 1479 | info.extrudedAlignAngle = alignAngle; | |||
| 1480 | info.extrudedSolid = solid != 0; | |||
| 1481 | info.extrudedSweepAlignmentFlags = sweepAlignmentFlags; | |||
| 1482 | info.extrudedPathFlags = pathFlags; | |||
| 1483 | info.extrudedAlignStart = alignStart != 0; | |||
| 1484 | info.extrudedBank = bank != 0; | |||
| 1485 | info.extrudedBasePointSet = basePointSet != 0; | |||
| 1486 | info.extrudedSweepEntityTransformComputed = | |||
| 1487 | sweepEntityTransformComputed != 0; | |||
| 1488 | info.extrudedPathEntityTransformComputed = | |||
| 1489 | pathEntityTransformComputed != 0; | |||
| 1490 | info.extrudedReferenceVector = referenceVector; | |||
| 1491 | } | |||
| 1492 | } else if (type == DRW::LOFTEDSURFACE) { | |||
| 1493 | dwgBuffer candidate = buffer; | |||
| 1494 | std::array<double, DRW_LoftedSurface::kTransformSize> | |||
| 1495 | loftEntityTransform{}; | |||
| 1496 | std::int32_t planeNormalLoftingType = 0; | |||
| 1497 | double startDraftAngle = 0.0; | |||
| 1498 | double endDraftAngle = 0.0; | |||
| 1499 | double startDraftMagnitude = 0.0; | |||
| 1500 | double endDraftMagnitude = 0.0; | |||
| 1501 | std::uint8_t arcLengthParameterization = 0; | |||
| 1502 | std::uint8_t noTwist = 0; | |||
| 1503 | std::uint8_t alignDirection = 0; | |||
| 1504 | std::uint8_t simpleSurfaces = 0; | |||
| 1505 | std::uint8_t closedSurfaces = 0; | |||
| 1506 | std::uint8_t solid = 0; | |||
| 1507 | std::uint8_t ruledSurface = 0; | |||
| 1508 | std::uint8_t virtualGuide = 0; | |||
| 1509 | std::uint16_t numCrossSections = 0; | |||
| 1510 | std::uint16_t numGuideCurves = 0; | |||
| 1511 | auto readMatrix = [&](std::array<double, | |||
| 1512 | DRW_LoftedSurface::kTransformSize>& matrix) { | |||
| 1513 | for (double& value : matrix) { | |||
| 1514 | if (!surfaceDwgReadDouble(candidate, endBit, value)) | |||
| 1515 | return false; | |||
| 1516 | } | |||
| 1517 | return true; | |||
| 1518 | }; | |||
| 1519 | const bool valid = readMatrix(loftEntityTransform) | |||
| 1520 | && surfaceDwgReadBitLong(candidate, endBit, | |||
| 1521 | planeNormalLoftingType) | |||
| 1522 | && surfaceDwgReadDouble(candidate, endBit, startDraftAngle) | |||
| 1523 | && surfaceDwgReadDouble(candidate, endBit, endDraftAngle) | |||
| 1524 | && surfaceDwgReadDouble(candidate, endBit, startDraftMagnitude) | |||
| 1525 | && surfaceDwgReadDouble(candidate, endBit, endDraftMagnitude) | |||
| 1526 | && surfaceDwgReadBit(candidate, endBit, arcLengthParameterization) | |||
| 1527 | && surfaceDwgReadBit(candidate, endBit, noTwist) | |||
| 1528 | && surfaceDwgReadBit(candidate, endBit, alignDirection) | |||
| 1529 | && surfaceDwgReadBit(candidate, endBit, simpleSurfaces) | |||
| 1530 | && surfaceDwgReadBit(candidate, endBit, closedSurfaces) | |||
| 1531 | && surfaceDwgReadBit(candidate, endBit, solid) | |||
| 1532 | && surfaceDwgReadBit(candidate, endBit, ruledSurface) | |||
| 1533 | && surfaceDwgReadBit(candidate, endBit, virtualGuide) | |||
| 1534 | && surfaceDwgReadBitShort(candidate, endBit, numCrossSections) | |||
| 1535 | && surfaceDwgReadBitShort(candidate, endBit, numGuideCurves) | |||
| 1536 | && numCrossSections <= DRW_LoftedSurface::kMaxReferenceTokenCount | |||
| 1537 | && numGuideCurves <= DRW_LoftedSurface::kMaxReferenceTokenCount; | |||
| 1538 | if (valid) { | |||
| 1539 | info.loftedFieldsValid = true; | |||
| 1540 | info.loftedEntityTransform = loftEntityTransform; | |||
| 1541 | info.loftedPlaneNormalLoftingType = planeNormalLoftingType; | |||
| 1542 | info.loftedStartDraftAngle = startDraftAngle; | |||
| 1543 | info.loftedEndDraftAngle = endDraftAngle; | |||
| 1544 | info.loftedStartDraftMagnitude = startDraftMagnitude; | |||
| 1545 | info.loftedEndDraftMagnitude = endDraftMagnitude; | |||
| 1546 | info.loftedArcLengthParameterization = arcLengthParameterization != 0; | |||
| 1547 | info.loftedNoTwist = noTwist != 0; | |||
| 1548 | info.loftedAlignDirection = alignDirection != 0; | |||
| 1549 | info.loftedSimpleSurfaces = simpleSurfaces != 0; | |||
| 1550 | info.loftedClosedSurfaces = closedSurfaces != 0; | |||
| 1551 | info.loftedSolid = solid != 0; | |||
| 1552 | info.loftedRuledSurface = ruledSurface != 0; | |||
| 1553 | info.loftedVirtualGuide = virtualGuide != 0; | |||
| 1554 | info.loftedNumCrossSections = numCrossSections; | |||
| 1555 | info.loftedNumGuideCurves = numGuideCurves; | |||
| 1556 | } | |||
| 1557 | } else if (type == DRW::SWEPTSURFACE) { | |||
| 1558 | dwgBuffer candidate = buffer; | |||
| 1559 | std::int32_t classVersion = 0; | |||
| 1560 | std::int32_t sweepEntityId = 0; | |||
| 1561 | std::int32_t sweepDataSize = 0; | |||
| 1562 | std::int32_t pathEntityId = 0; | |||
| 1563 | std::int32_t pathDataSize = 0; | |||
| 1564 | std::vector<std::uint8_t> sweepData; | |||
| 1565 | std::vector<std::uint8_t> pathData; | |||
| 1566 | std::array<double, DRW_SweptSurface::kTransformSize> | |||
| 1567 | sweepEntityTransform{}; | |||
| 1568 | std::array<double, DRW_SweptSurface::kTransformSize> | |||
| 1569 | pathEntityTransform{}; | |||
| 1570 | double draftAngle = 0.0; | |||
| 1571 | double draftStartDistance = 0.0; | |||
| 1572 | double draftEndDistance = 0.0; | |||
| 1573 | double twistAngle = 0.0; | |||
| 1574 | double scaleFactor = 1.0; | |||
| 1575 | double alignAngle = 0.0; | |||
| 1576 | std::uint8_t solid = 0; | |||
| 1577 | std::uint16_t sweepAlignmentFlags = 0; | |||
| 1578 | std::uint16_t pathFlags = 0; | |||
| 1579 | std::uint8_t alignStart = 0; | |||
| 1580 | std::uint8_t bank = 0; | |||
| 1581 | std::uint8_t basePointSet = 0; | |||
| 1582 | std::uint8_t sweepEntityTransformComputed = 0; | |||
| 1583 | std::uint8_t pathEntityTransformComputed = 0; | |||
| 1584 | DRW_Coord referenceVector; | |||
| 1585 | auto readMatrix = [&](std::array<double, | |||
| 1586 | DRW_SweptSurface::kTransformSize>& matrix) { | |||
| 1587 | for (double& value : matrix) { | |||
| 1588 | if (!surfaceDwgReadDouble(candidate, endBit, value)) | |||
| 1589 | return false; | |||
| 1590 | } | |||
| 1591 | return true; | |||
| 1592 | }; | |||
| 1593 | bool valid = surfaceDwgReadBitLong(candidate, endBit, classVersion) | |||
| 1594 | && classVersion >= 0 && classVersion <= 10 | |||
| 1595 | && surfaceDwgReadBitLong(candidate, endBit, sweepEntityId) | |||
| 1596 | && sweepEntityId >= 0 | |||
| 1597 | && surfaceDwgReadBitLong(candidate, endBit, sweepDataSize) | |||
| 1598 | && surfaceDwgReadBytes(candidate, endBit, sweepDataSize, | |||
| 1599 | DRW_SweptSurface::kMaxSweepDataSize, | |||
| 1600 | sweepData) | |||
| 1601 | && surfaceDwgReadBitLong(candidate, endBit, pathEntityId) | |||
| 1602 | && pathEntityId >= 0 | |||
| 1603 | && surfaceDwgReadBitLong(candidate, endBit, pathDataSize) | |||
| 1604 | && surfaceDwgReadBytes(candidate, endBit, pathDataSize, | |||
| 1605 | DRW_SweptSurface::kMaxSweepDataSize, | |||
| 1606 | pathData) | |||
| 1607 | && surfaceDwgReadDouble(candidate, endBit, draftAngle) | |||
| 1608 | && surfaceDwgReadDouble(candidate, endBit, draftStartDistance) | |||
| 1609 | && surfaceDwgReadDouble(candidate, endBit, draftEndDistance) | |||
| 1610 | && surfaceDwgReadDouble(candidate, endBit, twistAngle) | |||
| 1611 | && surfaceDwgReadDouble(candidate, endBit, scaleFactor) | |||
| 1612 | && surfaceDwgReadDouble(candidate, endBit, alignAngle) | |||
| 1613 | && readMatrix(sweepEntityTransform) | |||
| 1614 | && readMatrix(pathEntityTransform) | |||
| 1615 | && surfaceDwgReadBit(candidate, endBit, solid) | |||
| 1616 | && surfaceDwgReadBitShort(candidate, endBit, sweepAlignmentFlags) | |||
| 1617 | && surfaceDwgReadBitShort(candidate, endBit, pathFlags) | |||
| 1618 | && surfaceDwgReadBit(candidate, endBit, alignStart) | |||
| 1619 | && surfaceDwgReadBit(candidate, endBit, bank) | |||
| 1620 | && surfaceDwgReadBit(candidate, endBit, basePointSet) | |||
| 1621 | && surfaceDwgReadBit(candidate, endBit, sweepEntityTransformComputed) | |||
| 1622 | && surfaceDwgReadBit(candidate, endBit, pathEntityTransformComputed) | |||
| 1623 | && surfaceDwgRead3BitDouble(candidate, endBit, referenceVector); | |||
| 1624 | if (valid) { | |||
| 1625 | info.sweptFieldsValid = true; | |||
| 1626 | info.sweptClassVersion = static_cast<std::uint32_t>(classVersion); | |||
| 1627 | info.sweptEntityId = static_cast<std::uint32_t>(sweepEntityId); | |||
| 1628 | info.sweptData = std::move(sweepData); | |||
| 1629 | info.sweptPathEntityId = static_cast<std::uint32_t>(pathEntityId); | |||
| 1630 | info.sweptPathData = std::move(pathData); | |||
| 1631 | info.sweptEntityTransform = sweepEntityTransform; | |||
| 1632 | info.sweptPathEntityTransform = pathEntityTransform; | |||
| 1633 | info.sweptDraftAngle = draftAngle; | |||
| 1634 | info.sweptDraftStartDistance = draftStartDistance; | |||
| 1635 | info.sweptDraftEndDistance = draftEndDistance; | |||
| 1636 | info.sweptTwistAngle = twistAngle; | |||
| 1637 | info.sweptScaleFactor = scaleFactor; | |||
| 1638 | info.sweptAlignAngle = alignAngle; | |||
| 1639 | info.sweptSolid = solid != 0; | |||
| 1640 | info.sweptAlignmentFlags = sweepAlignmentFlags; | |||
| 1641 | info.sweptPathFlags = pathFlags; | |||
| 1642 | info.sweptAlignStart = alignStart != 0; | |||
| 1643 | info.sweptBank = bank != 0; | |||
| 1644 | info.sweptBasePointSet = basePointSet != 0; | |||
| 1645 | info.sweptEntityTransformComputed = | |||
| 1646 | sweepEntityTransformComputed != 0; | |||
| 1647 | info.sweptPathEntityTransformComputed = | |||
| 1648 | pathEntityTransformComputed != 0; | |||
| 1649 | info.sweptReferenceVector = referenceVector; | |||
| 1650 | } | |||
| 1651 | } else if (type == DRW::NURBSURFACE && version >= DRW::AC1027) { | |||
| 1652 | dwgBuffer candidate = buffer; | |||
| 1653 | std::uint16_t short170 = 0; | |||
| 1654 | std::uint8_t cvHullDisplay = 0; | |||
| 1655 | DRW_Coord uvec1; | |||
| 1656 | DRW_Coord vvec1; | |||
| 1657 | DRW_Coord uvec2; | |||
| 1658 | DRW_Coord vvec2; | |||
| 1659 | const bool valid = surfaceDwgReadBitShort(candidate, endBit, short170) | |||
| 1660 | && surfaceDwgReadBit(candidate, endBit, cvHullDisplay) | |||
| 1661 | && surfaceDwgRead3BitDouble(candidate, endBit, uvec1) | |||
| 1662 | && surfaceDwgRead3BitDouble(candidate, endBit, vvec1) | |||
| 1663 | && surfaceDwgRead3BitDouble(candidate, endBit, uvec2) | |||
| 1664 | && surfaceDwgRead3BitDouble(candidate, endBit, vvec2); | |||
| 1665 | if (valid) { | |||
| 1666 | info.nurbsFieldsValid = true; | |||
| 1667 | info.nurbsShort170 = short170; | |||
| 1668 | info.nurbsCvHullDisplay = cvHullDisplay != 0; | |||
| 1669 | info.nurbsUvec1 = uvec1; | |||
| 1670 | info.nurbsVvec1 = vvec1; | |||
| 1671 | info.nurbsUvec2 = uvec2; | |||
| 1672 | info.nurbsVvec2 = vvec2; | |||
| 1673 | } | |||
| 1674 | } else if (type == DRW::REVOLVEDSURFACE) { | |||
| 1675 | // The AcDbRevolvedSurface tail is optional from the carrier's point | |||
| 1676 | // of view: retain the complete bounded body when a producer omits or | |||
| 1677 | // truncates it, but publish the typed values only as one transaction. | |||
| 1678 | dwgBuffer candidate = buffer; | |||
| 1679 | std::int32_t classVersion = 0; | |||
| 1680 | std::int32_t id = 0; | |||
| 1681 | DRW_Coord axisPoint; | |||
| 1682 | DRW_Coord axisVector; | |||
| 1683 | std::array<double, DRW_RevolvedSurface::kTransformSize> transform{}; | |||
| 1684 | double revolveAngle = 0.0; | |||
| 1685 | double startAngle = 0.0; | |||
| 1686 | double draftAngle = 0.0; | |||
| 1687 | double draftStartDistance = 0.0; | |||
| 1688 | double draftEndDistance = 0.0; | |||
| 1689 | double twistAngle = 0.0; | |||
| 1690 | std::uint8_t solid = 0; | |||
| 1691 | std::uint8_t closeToAxis = 0; | |||
| 1692 | bool valid = surfaceDwgReadBitLong(candidate, endBit, classVersion) | |||
| 1693 | && classVersion >= 0 && classVersion <= 10 | |||
| 1694 | && surfaceDwgReadBitLong(candidate, endBit, id) | |||
| 1695 | && id >= 0 | |||
| 1696 | && surfaceDwgRead3BitDouble(candidate, endBit, axisPoint) | |||
| 1697 | && surfaceDwgRead3BitDouble(candidate, endBit, axisVector) | |||
| 1698 | && surfaceDwgReadDouble(candidate, endBit, revolveAngle) | |||
| 1699 | && surfaceDwgReadDouble(candidate, endBit, startAngle); | |||
| 1700 | for (double& value : transform) { | |||
| 1701 | valid = valid && surfaceDwgReadDouble(candidate, endBit, value); | |||
| 1702 | } | |||
| 1703 | valid = valid | |||
| 1704 | && surfaceDwgReadDouble(candidate, endBit, draftAngle) | |||
| 1705 | && surfaceDwgReadDouble(candidate, endBit, draftStartDistance) | |||
| 1706 | && surfaceDwgReadDouble(candidate, endBit, draftEndDistance) | |||
| 1707 | && surfaceDwgReadDouble(candidate, endBit, twistAngle) | |||
| 1708 | && surfaceDwgReadBit(candidate, endBit, solid) | |||
| 1709 | && surfaceDwgReadBit(candidate, endBit, closeToAxis); | |||
| 1710 | if (valid) { | |||
| 1711 | info.revolvedFieldsValid = true; | |||
| 1712 | info.revolvedClassId = static_cast<std::uint32_t>(classVersion); | |||
| 1713 | info.revolvedId = static_cast<std::uint32_t>(id); | |||
| 1714 | info.revolvedAxisPoint = axisPoint; | |||
| 1715 | info.revolvedAxisVector = axisVector; | |||
| 1716 | info.revolvedAngle = revolveAngle; | |||
| 1717 | info.revolvedStartAngle = startAngle; | |||
| 1718 | info.revolvedTransform = transform; | |||
| 1719 | info.revolvedDraftAngle = draftAngle; | |||
| 1720 | info.revolvedDraftStartDistance = draftStartDistance; | |||
| 1721 | info.revolvedDraftEndDistance = draftEndDistance; | |||
| 1722 | info.revolvedTwistAngle = twistAngle; | |||
| 1723 | info.revolvedSolid = solid != 0; | |||
| 1724 | info.revolvedCloseToAxis = closeToAxis != 0; | |||
| 1725 | } | |||
| 1726 | } | |||
| 1727 | ||||
| 1728 | info.acisEmpty = acisEmpty; | |||
| 1729 | info.acisVersion = acisVersion; | |||
| 1730 | info.modelerFormatVersion = static_cast<int>(modelerFormatVersion); | |||
| 1731 | info.uIsolines = static_cast<int>(uIsolines); | |||
| 1732 | info.vIsolines = static_cast<int>(vIsolines); | |||
| 1733 | return true; | |||
| 1734 | } | |||
| 1735 | ||||
| 1736 | int proxyEntityDxfCode(std::uint8_t handleCode) { | |||
| 1737 | switch (handleCode) { | |||
| 1738 | case 3: return 340; | |||
| 1739 | case 4: | |||
| 1740 | case 6: | |||
| 1741 | case 8: | |||
| 1742 | case 10: | |||
| 1743 | case 12: return 350; | |||
| 1744 | case 5: return 360; | |||
| 1745 | default: return 330; | |||
| 1746 | } | |||
| 1747 | } | |||
| 1748 | ||||
| 1749 | DRW_DwgSubrecordRange makeDwgSubrecordRange(const char *name, std::uint64_t startBit, | |||
| 1750 | std::uint64_t endBit, DRW::Version version, | |||
| 1751 | std::uint32_t count, bool parseComplete) { | |||
| 1752 | DRW_DwgSubrecordRange range; | |||
| 1753 | range.m_name = name; | |||
| 1754 | range.m_startBit = startBit; | |||
| 1755 | range.m_bitSize = endBit >= startBit ? endBit - startBit : 0; | |||
| 1756 | range.m_version = version; | |||
| 1757 | range.m_count = count; | |||
| 1758 | range.m_parseComplete = parseComplete; | |||
| 1759 | return range; | |||
| 1760 | } | |||
| 1761 | ||||
| 1762 | bool isValidSplineDegree(int degree) { | |||
| 1763 | return degree >= 1 && degree <= kMaxSplineDegree; | |||
| 1764 | } | |||
| 1765 | ||||
| 1766 | bool isValidControlSplineLayout(int degree, std::int32_t knotCount, std::int32_t controlCount) { | |||
| 1767 | if (!isValidSplineDegree(degree) || !isValidCount(knotCount, kMaxSplineItems) || | |||
| 1768 | !isValidCount(controlCount, kMaxSplineItems)) { | |||
| 1769 | return false; | |||
| 1770 | } | |||
| 1771 | ||||
| 1772 | if (controlCount < degree + 1) { | |||
| 1773 | return false; | |||
| 1774 | } | |||
| 1775 | ||||
| 1776 | const std::int64_t expectedKnots = static_cast<std::int64_t>(controlCount) + degree + 1; | |||
| 1777 | return expectedKnots <= kMaxSplineItems && knotCount == expectedKnots; | |||
| 1778 | } | |||
| 1779 | ||||
| 1780 | bool isValidFitSplineLayout(int degree, std::int32_t fitCount) { | |||
| 1781 | return isValidSplineDegree(degree) && isValidCount(fitCount, kMaxSplineItems) && | |||
| 1782 | fitCount >= 2; | |||
| 1783 | } | |||
| 1784 | ||||
| 1785 | bool differsFromUnitWeight(double weight) { | |||
| 1786 | return std::fabs(weight - 1.0) > 1e-12; | |||
| 1787 | } | |||
| 1788 | ||||
| 1789 | //! \brief Compare two doubles by stored representation. | |||
| 1790 | //! For values a compact DWG form restores verbatim, the match has to be exact: | |||
| 1791 | //! dataFlags 3 makes the reader return exactly 1.0 and dataFlags 2 makes it | |||
| 1792 | //! return xscale for y and z (see DRW_Insert::parseDwg), so picking those forms | |||
| 1793 | //! on a tolerant match would silently round the scale that gets written. This | |||
| 1794 | //! asks the question that is actually meant - "will the reader reconstruct this | |||
| 1795 | //! value?" - without floating point comparison semantics, and as a side effect | |||
| 1796 | //! keeps -0.0 distinct from 0.0, which `==` does not. | |||
| 1797 | bool sameStoredDouble(double a, double b) { | |||
| 1798 | return std::memcmp(&a, &b, sizeof a) == 0; | |||
| 1799 | } | |||
| 1800 | ||||
| 1801 | void putDwgReference(dwgBufferW *buf, std::uint8_t code, | |||
| 1802 | std::uint32_t ref) { | |||
| 1803 | dwgHandle h; | |||
| 1804 | h.code = code; | |||
| 1805 | h.ref = ref; | |||
| 1806 | h.size = 0; | |||
| 1807 | if (ref != 0) { | |||
| 1808 | std::uint32_t t = ref; | |||
| 1809 | while (t != 0) { | |||
| 1810 | t >>= 8; | |||
| 1811 | ++h.size; | |||
| 1812 | } | |||
| 1813 | } | |||
| 1814 | buf->putHandle(h); | |||
| 1815 | } | |||
| 1816 | ||||
| 1817 | void putHardPointerHandle(dwgBufferW *buf, std::uint32_t ref) { | |||
| 1818 | putDwgReference(buf, DRW::DwgHardPointer, ref); | |||
| 1819 | } | |||
| 1820 | ||||
| 1821 | void appendBitBuffer(dwgBufferW *destination, const dwgBufferW& source) { | |||
| 1822 | if (destination == nullptr) | |||
| 1823 | return; | |||
| 1824 | const auto& bytes = source.data(); | |||
| 1825 | for (std::uint32_t bit = 0; bit < source.bitCount(); ++bit) { | |||
| 1826 | const std::uint8_t value = | |||
| 1827 | static_cast<std::uint8_t>((bytes[bit / 8] >> (7 - (bit % 8))) & 1); | |||
| 1828 | destination->putBit(value); | |||
| 1829 | } | |||
| 1830 | } | |||
| 1831 | ||||
| 1832 | void putNullableHardPointerHandle(dwgBufferW *buf, std::uint32_t ref) { | |||
| 1833 | dwgHandle h; | |||
| 1834 | h.code = ref == 0 ? 0 : 5; | |||
| 1835 | h.ref = ref; | |||
| 1836 | h.size = 0; | |||
| 1837 | if (ref != 0) { | |||
| 1838 | std::uint32_t t = ref; | |||
| 1839 | while (t != 0) { | |||
| 1840 | t >>= 8; | |||
| 1841 | ++h.size; | |||
| 1842 | } | |||
| 1843 | } | |||
| 1844 | buf->putHandle(h); | |||
| 1845 | } | |||
| 1846 | ||||
| 1847 | void putSurfaceHandle(dwgBufferW *buf, std::uint32_t ref) { | |||
| 1848 | dwgHandle h; | |||
| 1849 | h.code = 5; | |||
| 1850 | h.ref = ref; | |||
| 1851 | h.size = 0; | |||
| 1852 | for (std::uint32_t value = ref; value != 0; value >>= 8) | |||
| 1853 | ++h.size; | |||
| 1854 | buf->putHandle(h); | |||
| 1855 | } | |||
| 1856 | ||||
| 1857 | std::size_t surfaceRawBitCapacity(const std::vector<std::uint8_t>& data) { | |||
| 1858 | constexpr std::size_t maxBitSize = | |||
| 1859 | std::numeric_limits<std::uint32_t>::max(); | |||
| 1860 | constexpr std::size_t maxBytes = maxBitSize / 8u; | |||
| 1861 | return data.size() > maxBytes ? maxBitSize : data.size() * 8u; | |||
| 1862 | } | |||
| 1863 | ||||
| 1864 | bool putSurfaceRawBits(dwgBufferW *buf, const std::vector<std::uint8_t>& data, | |||
| 1865 | std::uint32_t bitSize) { | |||
| 1866 | const std::size_t bitCapacity = surfaceRawBitCapacity(data); | |||
| 1867 | if (buf == nullptr || bitSize == 0 || bitSize > bitCapacity) | |||
| 1868 | return false; | |||
| 1869 | for (std::uint32_t bit = 0; bit < bitSize; ++bit) { | |||
| 1870 | const std::uint8_t byte = data[bit >> 3]; | |||
| 1871 | buf->putBit((byte >> (7u - (bit & 7u))) & 1u); | |||
| 1872 | } | |||
| 1873 | return true; | |||
| 1874 | } | |||
| 1875 | ||||
| 1876 | bool finiteSurfaceCoord(const DRW_Coord& value) { | |||
| 1877 | return std::isfinite(value.x) && std::isfinite(value.y) | |||
| 1878 | && std::isfinite(value.z); | |||
| 1879 | } | |||
| 1880 | ||||
| 1881 | template <std::size_t N> | |||
| 1882 | bool finiteSurfaceMatrix(const std::array<double, N>& values) { | |||
| 1883 | return std::all_of(values.begin(), values.end(), | |||
| 1884 | [](double value) { return std::isfinite(value); }); | |||
| 1885 | } | |||
| 1886 | ||||
| 1887 | std::uint16_t bitShortFromInt(int value) { | |||
| 1888 | if (value < 0) | |||
| 1889 | return 0; | |||
| 1890 | if (value > 0xffff) | |||
| 1891 | return 0xffff; | |||
| 1892 | return static_cast<std::uint16_t>(value); | |||
| 1893 | } | |||
| 1894 | ||||
| 1895 | std::uint32_t readTableHandle( | |||
| 1896 | dwgBuffer *hdlBuf, | |||
| 1897 | std::uint64_t endBit = std::numeric_limits<std::uint64_t>::max()) { | |||
| 1898 | if (hdlBuf == nullptr || !hdlBuf->isGood()) | |||
| 1899 | return 0; | |||
| 1900 | dwgBuffer probe = hdlBuf->forkIndependent(); | |||
| 1901 | dwgHandle h; | |||
| 1902 | if (!readBoundedDwgHandle(probe, endBit, 0, false, h)) { | |||
| 1903 | hdlBuf->invalidate(); | |||
| 1904 | return 0; | |||
| 1905 | } | |||
| 1906 | *hdlBuf = probe; | |||
| 1907 | return h.ref; | |||
| 1908 | } | |||
| 1909 | ||||
| 1910 | void seekTableObjectHandleStream(DRW::Version version, dwgBuffer *buf, std::uint32_t objSize) { | |||
| 1911 | if (version > DRW::AC1018) { | |||
| 1912 | buf->setPosition(objSize >> 3); | |||
| 1913 | buf->setBitPos(objSize & 7); | |||
| 1914 | } | |||
| 1915 | } | |||
| 1916 | ||||
| 1917 | bool readTableObjectCommonHandles(dwgBuffer *buf, std::uint32_t baseHandle, | |||
| 1918 | std::int32_t numReactors, std::uint8_t xDictFlag, | |||
| 1919 | std::uint32_t *parentHandle, | |||
| 1920 | std::vector<std::uint32_t> *reactorHandles, | |||
| 1921 | std::uint32_t *xDictHandle, | |||
| 1922 | std::uint64_t handleEndBit = | |||
| 1923 | std::numeric_limits<std::uint64_t>::max()) { | |||
| 1924 | if (buf == nullptr || !buf->isGood() | |||
| 1925 | || !dwgSafety::validReactorCount(numReactors)) { | |||
| 1926 | if (buf != nullptr) | |||
| 1927 | buf->invalidate(); | |||
| 1928 | return false; | |||
| 1929 | } | |||
| 1930 | std::vector<std::uint32_t> parsedReactors; | |||
| 1931 | dwgHandle parentH; | |||
| 1932 | if (!readBoundedDwgHandle(*buf, handleEndBit, baseHandle, true, parentH)) | |||
| 1933 | return false; | |||
| 1934 | if (!DRW::reserve(parsedReactors, numReactors)) | |||
| 1935 | return false; | |||
| 1936 | for (std::int32_t i = 0; i < numReactors; ++i) { | |||
| 1937 | dwgHandle reactor; | |||
| 1938 | if (!readBoundedDwgHandle(*buf, handleEndBit, baseHandle, true, | |||
| 1939 | reactor)) | |||
| 1940 | return false; | |||
| 1941 | parsedReactors.push_back(reactor.ref); | |||
| 1942 | } | |||
| 1943 | ||||
| 1944 | std::uint32_t parsedXDictHandle = 0; | |||
| 1945 | if (xDictFlag != 1) { | |||
| 1946 | dwgHandle xDict; | |||
| 1947 | if (!readBoundedDwgHandle(*buf, handleEndBit, baseHandle, true, | |||
| 1948 | xDict)) | |||
| 1949 | return false; | |||
| 1950 | parsedXDictHandle = xDict.ref; | |||
| 1951 | } | |||
| 1952 | if (parentHandle) | |||
| 1953 | *parentHandle = parentH.ref; | |||
| 1954 | if (reactorHandles) | |||
| 1955 | *reactorHandles = std::move(parsedReactors); | |||
| 1956 | if (xDictHandle) | |||
| 1957 | *xDictHandle = parsedXDictHandle; | |||
| 1958 | return true; | |||
| 1959 | } | |||
| 1960 | ||||
| 1961 | bool readTableValueBytes(dwgBuffer *buf, std::uint64_t bodyEndBit, | |||
| 1962 | std::vector<std::uint8_t>& raw, const char *label) { | |||
| 1963 | std::int32_t parsedByteCount = 0; | |||
| 1964 | if (buf == nullptr | |||
| 1965 | || !readBoundedBitLong(*buf, bodyEndBit, parsedByteCount) | |||
| 1966 | || parsedByteCount < 0 | |||
| 1967 | || static_cast<std::uint32_t>(parsedByteCount) > kMaxTableStringBytes) { | |||
| 1968 | if (buf != nullptr) | |||
| 1969 | buf->invalidate(); | |||
| 1970 | return false; | |||
| 1971 | } | |||
| 1972 | const std::uint32_t byteCount = static_cast<std::uint32_t>(parsedByteCount); | |||
| 1973 | if (byteCount > kMaxTableStringBytes) { | |||
| 1974 | DRW_DBG(label)DRW_dbg::dbg(label); DRW_DBG(" too large: ")DRW_dbg::dbg(" too large: "); DRW_DBG(byteCount)DRW_dbg::dbg(byteCount); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 1975 | return false; | |||
| 1976 | } | |||
| 1977 | if (!DRW::resize(raw, static_cast<int>(byteCount))) | |||
| 1978 | return false; | |||
| 1979 | const bool good = readBoundedBytes(*buf, bodyEndBit, raw.data(), raw.size()); | |||
| 1980 | if (!good) { | |||
| 1981 | DRW_DBG(label)DRW_dbg::dbg(label); DRW_DBG(" byte payload read failed, size: ")DRW_dbg::dbg(" byte payload read failed, size: "); DRW_DBG(byteCount)DRW_dbg::dbg(byteCount); | |||
| 1982 | DRW_DBG(" remaining: ")DRW_dbg::dbg(" remaining: "); DRW_DBG(buf->numRemainingBytes())DRW_dbg::dbg(buf->numRemainingBytes()); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 1983 | } | |||
| 1984 | return good; | |||
| 1985 | } | |||
| 1986 | ||||
| 1987 | UTF8STRINGstd::string decodeTableValueText(DRW::Version version, dwgBuffer *buf, const std::vector<std::uint8_t>& raw) { | |||
| 1988 | if (raw.empty()) | |||
| 1989 | return UTF8STRINGstd::string(); | |||
| 1990 | std::string s(reinterpret_cast<const char*>(raw.data()), raw.size()); | |||
| 1991 | if (version > DRW::AC1018 && s.size() >= 2 && s[s.size() - 1] == '\0' | |||
| 1992 | && s[s.size() - 2] == '\0') { | |||
| 1993 | s.resize(s.size() - 2); | |||
| 1994 | } else { | |||
| 1995 | while (!s.empty() && s.back() == '\0') | |||
| 1996 | s.pop_back(); | |||
| 1997 | } | |||
| 1998 | if (buf->decoder) | |||
| 1999 | s = buf->decoder->toUtf8(s); | |||
| 2000 | return s; | |||
| 2001 | } | |||
| 2002 | ||||
| 2003 | UTF8STRINGstd::string readTableText(DRW::Version version, dwgBuffer *buf, | |||
| 2004 | std::uint64_t endBit) { | |||
| 2005 | if (!buf) | |||
| 2006 | return UTF8STRINGstd::string(); | |||
| 2007 | if (version <= DRW::AC1018) { | |||
| 2008 | UTF8STRINGstd::string value; | |||
| 2009 | if (!readBoundedVariableText(*buf, endBit, version, value)) | |||
| 2010 | buf->invalidate(); | |||
| 2011 | return value; | |||
| 2012 | } | |||
| 2013 | ||||
| 2014 | std::uint16_t parsedByteLen = 0; | |||
| 2015 | if (!readBoundedBitShort(*buf, endBit, parsedByteLen)) { | |||
| 2016 | buf->invalidate(); | |||
| 2017 | return UTF8STRINGstd::string(); | |||
| 2018 | } | |||
| 2019 | const std::uint32_t byteLen = parsedByteLen; | |||
| 2020 | if (byteLen == 0) | |||
| 2021 | return UTF8STRINGstd::string(); | |||
| 2022 | if (byteLen > kMaxTableStringBytes) { | |||
| 2023 | DRW_DBG("TABLE text byte length invalid: ")DRW_dbg::dbg("TABLE text byte length invalid: "); DRW_DBG(byteLen)DRW_dbg::dbg(byteLen); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 2024 | return UTF8STRINGstd::string(); | |||
| 2025 | } | |||
| 2026 | ||||
| 2027 | std::vector<std::uint8_t> raw; | |||
| 2028 | if (!DRW::resize(raw, static_cast<int>(byteLen + 2))) | |||
| 2029 | return UTF8STRINGstd::string(); | |||
| 2030 | std::fill(raw.begin(), raw.end(), 0); | |||
| 2031 | if (!readBoundedBytes(*buf, endBit, raw.data(), byteLen)) { | |||
| 2032 | buf->invalidate(); | |||
| 2033 | return UTF8STRINGstd::string(); | |||
| 2034 | } | |||
| 2035 | ||||
| 2036 | std::string s(reinterpret_cast<const char*>(raw.data()), byteLen); | |||
| 2037 | if (buf->decoder) | |||
| 2038 | s = buf->decoder->toUtf8(s); | |||
| 2039 | return s; | |||
| 2040 | } | |||
| 2041 | ||||
| 2042 | bool readTableValuePoint(dwgBuffer *buf, std::uint64_t bodyEndBit, | |||
| 2043 | DRW_CadValue& value, int dimensions) { | |||
| 2044 | std::int32_t parsedDataSize = 0; | |||
| 2045 | if (buf == nullptr | |||
| 2046 | || !readBoundedBitLong(*buf, bodyEndBit, parsedDataSize) | |||
| 2047 | || parsedDataSize < 0) { | |||
| 2048 | if (buf != nullptr) | |||
| 2049 | buf->invalidate(); | |||
| 2050 | return false; | |||
| 2051 | } | |||
| 2052 | value.m_dataSize = static_cast<std::uint32_t>(parsedDataSize); | |||
| 2053 | const std::uint32_t expectedSize = static_cast<std::uint32_t>(dimensions) * 8; | |||
| 2054 | if (value.m_dataSize > kMaxTableStringBytes) | |||
| 2055 | return false; | |||
| 2056 | if (value.m_dataSize < expectedSize) { | |||
| 2057 | if (!DRW::resize(value.m_rawData, | |||
| 2058 | static_cast<int>(value.m_dataSize))) | |||
| 2059 | return false; | |||
| 2060 | if (!readBoundedBytes(*buf, bodyEndBit, value.m_rawData.data(), | |||
| 2061 | value.m_rawData.size())) | |||
| 2062 | return false; | |||
| 2063 | value.m_value.addBinary(310, value.m_rawData); | |||
| 2064 | return true; | |||
| 2065 | } | |||
| 2066 | ||||
| 2067 | DRW_Coord c; | |||
| 2068 | if (!readBoundedRawDouble(*buf, bodyEndBit, c.x) | |||
| 2069 | || !readBoundedRawDouble(*buf, bodyEndBit, c.y) | |||
| 2070 | || (dimensions == 3 | |||
| 2071 | && !readBoundedRawDouble(*buf, bodyEndBit, c.z))) | |||
| 2072 | return false; | |||
| 2073 | if (dimensions != 3) | |||
| 2074 | c.z = 0.0; | |||
| 2075 | value.m_value.addCoord(11, c); | |||
| 2076 | ||||
| 2077 | const std::uint32_t extraBytes = value.m_dataSize - expectedSize; | |||
| 2078 | if (!DRW::resize(value.m_rawData, static_cast<int>(extraBytes))) | |||
| 2079 | return false; | |||
| 2080 | return readBoundedBytes(*buf, bodyEndBit, value.m_rawData.data(), | |||
| 2081 | value.m_rawData.size()); | |||
| 2082 | } | |||
| 2083 | ||||
| 2084 | bool readTableCadValue(DRW::Version version, dwgBuffer *buf, dwgBuffer *strBuf, | |||
| 2085 | dwgBuffer *hdlBuf, DRW_CadValue& value, | |||
| 2086 | const TableDwgBounds& bounds) { | |||
| 2087 | if (version > DRW::AC1018) { | |||
| 2088 | if (!readBoundedBitLong(*buf, bounds.bodyEndBit, value.m_formatFlags)) | |||
| 2089 | return false; | |||
| 2090 | } | |||
| 2091 | ||||
| 2092 | if (!readBoundedBitLong(*buf, bounds.bodyEndBit, value.m_dataType)) | |||
| 2093 | return false; | |||
| 2094 | const bool emptyR2007Value = version > DRW::AC1018 && (value.m_formatFlags & 3); | |||
| 2095 | if (!emptyR2007Value) { | |||
| 2096 | switch (value.m_dataType) { | |||
| 2097 | case 0: | |||
| 2098 | case 1: { | |||
| 2099 | std::int32_t intValue = 0; | |||
| 2100 | if (!readBoundedBitLong(*buf, bounds.bodyEndBit, intValue)) | |||
| 2101 | return false; | |||
| 2102 | value.m_value.addInt(91, intValue); | |||
| 2103 | break; | |||
| 2104 | } | |||
| 2105 | case 2: { | |||
| 2106 | double doubleValue = 0.0; | |||
| 2107 | if (!readBoundedBitDouble(*buf, bounds.bodyEndBit, doubleValue)) | |||
| 2108 | return false; | |||
| 2109 | value.m_value.addDouble(140, doubleValue); | |||
| 2110 | break; | |||
| 2111 | } | |||
| 2112 | case 4: | |||
| 2113 | case 512: | |||
| 2114 | if (!readTableValueBytes(buf, bounds.bodyEndBit, value.m_rawData, | |||
| 2115 | "TABLE value byte payload")) | |||
| 2116 | return false; | |||
| 2117 | value.m_dataSize = static_cast<std::uint32_t>(value.m_rawData.size()); | |||
| 2118 | value.m_value.addString(1, decodeTableValueText(version, buf, value.m_rawData)); | |||
| 2119 | break; | |||
| 2120 | case 8: { | |||
| 2121 | if (!readTableValueBytes(buf, bounds.bodyEndBit, value.m_rawData, | |||
| 2122 | "TABLE value date payload")) | |||
| 2123 | return false; | |||
| 2124 | value.m_dataSize = static_cast<std::uint32_t>(value.m_rawData.size()); | |||
| 2125 | value.m_value.addBinary(310, value.m_rawData); | |||
| 2126 | break; | |||
| 2127 | } | |||
| 2128 | case 16: | |||
| 2129 | if (!readTableValuePoint(buf, bounds.bodyEndBit, value, 2)) | |||
| 2130 | return false; | |||
| 2131 | break; | |||
| 2132 | case 32: | |||
| 2133 | if (!readTableValuePoint(buf, bounds.bodyEndBit, value, 3)) | |||
| 2134 | return false; | |||
| 2135 | break; | |||
| 2136 | case 64: | |||
| 2137 | value.m_handle = readTableHandle(hdlBuf, bounds.handleEndBit); | |||
| 2138 | value.m_value.addInt(330, static_cast<std::uint32_t>(value.m_handle)); | |||
| 2139 | break; | |||
| 2140 | case 128: | |||
| 2141 | case 256: | |||
| 2142 | DRW_DBG("unsupported TABLE CadValue buffer data type: ")DRW_dbg::dbg("unsupported TABLE CadValue buffer data type: "); DRW_DBG(value.m_dataType)DRW_dbg::dbg(value.m_dataType); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 2143 | return false; | |||
| 2144 | default: | |||
| 2145 | DRW_DBG("unsupported TABLE CadValue data type: ")DRW_dbg::dbg("unsupported TABLE CadValue data type: "); DRW_DBG(value.m_dataType)DRW_dbg::dbg(value.m_dataType); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 2146 | return false; | |||
| 2147 | } | |||
| 2148 | } | |||
| 2149 | ||||
| 2150 | if (version > DRW::AC1018) { | |||
| 2151 | dwgBuffer *textBuf = strBuf ? strBuf : buf; | |||
| 2152 | if (!readBoundedBitLong(*buf, bounds.bodyEndBit, value.m_unitType)) | |||
| 2153 | return false; | |||
| 2154 | const std::uint64_t textEndBit = tableTextEndBit(buf, textBuf, bounds); | |||
| 2155 | value.m_formatString = readTableText(version, textBuf, textEndBit); | |||
| 2156 | value.m_valueString = readTableText(version, textBuf, textEndBit); | |||
| 2157 | } | |||
| 2158 | ||||
| 2159 | const bool good = buf->isGood() && (!strBuf || strBuf->isGood()) && (!hdlBuf || hdlBuf->isGood()); | |||
| 2160 | if (!good) { | |||
| 2161 | DRW_DBG("TABLE CadValue stream failed, flags: ")DRW_dbg::dbg("TABLE CadValue stream failed, flags: "); DRW_DBG(value.m_formatFlags)DRW_dbg::dbg(value.m_formatFlags); | |||
| 2162 | DRW_DBG(" type: ")DRW_dbg::dbg(" type: "); DRW_DBG(value.m_dataType)DRW_dbg::dbg(value.m_dataType); | |||
| 2163 | DRW_DBG(" unit: ")DRW_dbg::dbg(" unit: "); DRW_DBG(value.m_unitType)DRW_dbg::dbg(value.m_unitType); | |||
| 2164 | DRW_DBG(" bufGood: ")DRW_dbg::dbg(" bufGood: "); DRW_DBG(buf->isGood() ? 1 : 0)DRW_dbg::dbg(buf->isGood() ? 1 : 0); | |||
| 2165 | DRW_DBG(" strGood: ")DRW_dbg::dbg(" strGood: "); DRW_DBG((!strBuf || strBuf->isGood()) ? 1 : 0)DRW_dbg::dbg((!strBuf || strBuf->isGood()) ? 1 : 0); | |||
| 2166 | DRW_DBG(" hdlGood: ")DRW_dbg::dbg(" hdlGood: "); DRW_DBG((!hdlBuf || hdlBuf->isGood()) ? 1 : 0)DRW_dbg::dbg((!hdlBuf || hdlBuf->isGood()) ? 1 : 0); | |||
| 2167 | DRW_DBG(" bufPos: ")DRW_dbg::dbg(" bufPos: "); DRW_DBG(buf->getPosition())DRW_dbg::dbg(buf->getPosition()); | |||
| 2168 | DRW_DBG(" strPos: ")DRW_dbg::dbg(" strPos: "); if (strBuf) DRW_DBG(strBuf->getPosition())DRW_dbg::dbg(strBuf->getPosition()); else DRW_DBG(-1)DRW_dbg::dbg(-1); | |||
| 2169 | DRW_DBG(" hdlPos: ")DRW_dbg::dbg(" hdlPos: "); if (hdlBuf) DRW_DBG(hdlBuf->getPosition())DRW_dbg::dbg(hdlBuf->getPosition()); else DRW_DBG(-1)DRW_dbg::dbg(-1); | |||
| 2170 | DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 2171 | } | |||
| 2172 | return good; | |||
| 2173 | } | |||
| 2174 | ||||
| 2175 | bool skipTableCustomData(DRW::Version version, dwgBuffer *buf, | |||
| 2176 | dwgBuffer *strBuf, dwgBuffer *hdlBuf, | |||
| 2177 | const TableDwgBounds& bounds) { | |||
| 2178 | dwgBuffer *textBuf = strBuf ? strBuf : buf; | |||
| 2179 | UTF8STRINGstd::string key = readTableText( | |||
| 2180 | version, textBuf, tableTextEndBit(buf, textBuf, bounds)); | |||
| 2181 | if (!textBuf->isGood()) { | |||
| 2182 | DRW_DBG("TABLE custom data key string read failed\n")DRW_dbg::dbg("TABLE custom data key string read failed\n"); | |||
| 2183 | return false; | |||
| 2184 | } | |||
| 2185 | DRW_CadValue value; | |||
| 2186 | const bool good = readTableCadValue(version, buf, strBuf, hdlBuf, value, | |||
| 2187 | bounds); | |||
| 2188 | if (!good) { | |||
| 2189 | DRW_DBG("TABLE custom data key failed: ")DRW_dbg::dbg("TABLE custom data key failed: "); DRW_DBG(key.c_str())DRW_dbg::dbg(key.c_str()); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 2190 | } | |||
| 2191 | return good; | |||
| 2192 | } | |||
| 2193 | ||||
| 2194 | bool readTableCmColor(DRW::Version version, dwgBuffer *buf, | |||
| 2195 | dwgBuffer *strBuf, const TableDwgBounds& bounds) { | |||
| 2196 | dwgBuffer *textBuf = strBuf ? strBuf : buf; | |||
| 2197 | if (version < DRW::AC1018) { | |||
| 2198 | std::uint16_t ignoredColor = 0; | |||
| 2199 | return readBoundedBitShort(*buf, bounds.bodyEndBit, ignoredColor); | |||
| 2200 | } | |||
| 2201 | ||||
| 2202 | std::uint16_t ignoredColorType = 0; | |||
| 2203 | std::int32_t rgb = 0; | |||
| 2204 | std::uint8_t colorFlags = 0; | |||
| 2205 | if (!readBoundedBitShort(*buf, bounds.bodyEndBit, ignoredColorType) | |||
| 2206 | || !readBoundedBitLong(*buf, bounds.bodyEndBit, rgb) | |||
| 2207 | || !readBoundedRawChar8(*buf, bounds.bodyEndBit, colorFlags)) | |||
| 2208 | return false; | |||
| 2209 | DRW_DBG("\ntype COLOR: ")DRW_dbg::dbg("\ntype COLOR: "); DRW_DBGH(rgb >> 24)DRW_dbg::dbgH(rgb >> 24); | |||
| 2210 | DRW_DBG("\nRGB COLOR: ")DRW_dbg::dbg("\nRGB COLOR: "); DRW_DBGH(rgb)DRW_dbg::dbgH(rgb); | |||
| 2211 | DRW_DBG("\nbyte COLOR: ")DRW_dbg::dbg("\nbyte COLOR: "); DRW_DBGH(colorFlags)DRW_dbg::dbgH(colorFlags); | |||
| 2212 | const std::uint64_t textEndBit = tableTextEndBit(buf, textBuf, bounds); | |||
| 2213 | if (colorFlags & 1) | |||
| 2214 | readTableText(version, textBuf, textEndBit); | |||
| 2215 | if (colorFlags & 2) | |||
| 2216 | readTableText(version, textBuf, textEndBit); | |||
| 2217 | return textBuf->isGood(); | |||
| 2218 | } | |||
| 2219 | ||||
| 2220 | bool skipR2007TableCellOverrides(DRW::Version version, dwgBuffer *buf, | |||
| 2221 | dwgBuffer *strBuf, dwgBuffer *hdlBuf, | |||
| 2222 | DRW_TableCell& cell, | |||
| 2223 | std::vector<DRW_DwgSubrecordRange> *ranges, | |||
| 2224 | const TableDwgBounds& bounds) { | |||
| 2225 | const std::uint64_t startBit = currentDwgBit(buf); | |||
| 2226 | std::int32_t overrideFlags = 0; | |||
| 2227 | std::uint8_t virtualEdgeFlags = 0; | |||
| 2228 | if (!readBoundedBitLong(*buf, bounds.bodyEndBit, overrideFlags) | |||
| 2229 | || !readBoundedRawChar8(*buf, bounds.bodyEndBit, virtualEdgeFlags)) | |||
| 2230 | return false; | |||
| 2231 | cell.m_overrideFlags = static_cast<std::uint32_t>(overrideFlags); | |||
| 2232 | cell.m_virtualEdgeFlags = virtualEdgeFlags; | |||
| 2233 | ||||
| 2234 | if (cell.m_overrideFlags & 0x00001 | |||
| 2235 | && !skipTableRawShort16(*buf, bounds.bodyEndBit)) | |||
| 2236 | return false; | |||
| 2237 | if (cell.m_overrideFlags & 0x00002 | |||
| 2238 | && !skipTableBit(*buf, bounds.bodyEndBit)) | |||
| 2239 | return false; | |||
| 2240 | if ((cell.m_overrideFlags & 0x00004) | |||
| 2241 | && !readTableCmColor(version, buf, strBuf, bounds)) | |||
| 2242 | return false; | |||
| 2243 | if ((cell.m_overrideFlags & 0x00008) | |||
| 2244 | && !readTableCmColor(version, buf, strBuf, bounds)) | |||
| 2245 | return false; | |||
| 2246 | if (cell.m_overrideFlags & 0x00010) | |||
| 2247 | cell.m_textStyleOverrideHandle = readTableHandle(hdlBuf, bounds.handleEndBit); | |||
| 2248 | if (cell.m_overrideFlags & 0x00020 | |||
| 2249 | && !skipTableBitDouble(*buf, bounds.bodyEndBit)) | |||
| 2250 | return false; | |||
| 2251 | if ((cell.m_overrideFlags & 0x00040) | |||
| 2252 | && !readTableCmColor(version, buf, strBuf, bounds)) | |||
| 2253 | return false; | |||
| 2254 | if (cell.m_overrideFlags & 0x00400 | |||
| 2255 | && !skipTableBitShort(*buf, bounds.bodyEndBit)) | |||
| 2256 | return false; | |||
| 2257 | if (cell.m_overrideFlags & 0x04000 | |||
| 2258 | && !skipTableBitShort(*buf, bounds.bodyEndBit)) | |||
| 2259 | return false; | |||
| 2260 | if ((cell.m_overrideFlags & 0x00080) | |||
| 2261 | && !readTableCmColor(version, buf, strBuf, bounds)) | |||
| 2262 | return false; | |||
| 2263 | if (cell.m_overrideFlags & 0x00800 | |||
| 2264 | && !skipTableBitShort(*buf, bounds.bodyEndBit)) | |||
| 2265 | return false; | |||
| 2266 | if (cell.m_overrideFlags & 0x08000 | |||
| 2267 | && !skipTableBitShort(*buf, bounds.bodyEndBit)) | |||
| 2268 | return false; | |||
| 2269 | if ((cell.m_overrideFlags & 0x00100) | |||
| 2270 | && !readTableCmColor(version, buf, strBuf, bounds)) | |||
| 2271 | return false; | |||
| 2272 | if (cell.m_overrideFlags & 0x01000 | |||
| 2273 | && !skipTableBitShort(*buf, bounds.bodyEndBit)) | |||
| 2274 | return false; | |||
| 2275 | if (cell.m_overrideFlags & 0x10000 | |||
| 2276 | && !skipTableBitShort(*buf, bounds.bodyEndBit)) | |||
| 2277 | return false; | |||
| 2278 | if ((cell.m_overrideFlags & 0x00200) | |||
| 2279 | && !readTableCmColor(version, buf, strBuf, bounds)) | |||
| 2280 | return false; | |||
| 2281 | if (cell.m_overrideFlags & 0x02000 | |||
| 2282 | && !skipTableBitShort(*buf, bounds.bodyEndBit)) | |||
| 2283 | return false; | |||
| 2284 | if (cell.m_overrideFlags & 0x20000 | |||
| 2285 | && !skipTableBitShort(*buf, bounds.bodyEndBit)) | |||
| 2286 | return false; | |||
| 2287 | ||||
| 2288 | const bool good = buf->isGood() && (!strBuf || strBuf->isGood()) && (!hdlBuf || hdlBuf->isGood()); | |||
| 2289 | if (ranges != nullptr) { | |||
| 2290 | ranges->push_back(makeDwgSubrecordRange( | |||
| 2291 | "r2007-table-cell-overrides", startBit, currentDwgBit(buf), | |||
| 2292 | version, cell.m_overrideFlags, good)); | |||
| 2293 | } | |||
| 2294 | return good; | |||
| 2295 | } | |||
| 2296 | ||||
| 2297 | bool parseR2007TableCell(DRW::Version version, dwgBuffer *buf, dwgBuffer *strBuf, | |||
| 2298 | dwgBuffer *hdlBuf, DRW_TableCell& cell, | |||
| 2299 | std::vector<DRW_DwgSubrecordRange> *ranges, | |||
| 2300 | const TableDwgBounds& bounds) { | |||
| 2301 | dwgBuffer *textBuf = strBuf ? strBuf : buf; | |||
| 2302 | std::uint16_t type = 0; | |||
| 2303 | std::uint8_t edgeFlags = 0; | |||
| 2304 | if (!readBoundedBitShort(*buf, bounds.bodyEndBit, type) | |||
| 2305 | || !readBoundedRawChar8(*buf, bounds.bodyEndBit, edgeFlags) | |||
| 2306 | || !readBoundedBit(*buf, bounds.bodyEndBit, cell.m_isMerged) | |||
| 2307 | || !readBoundedBit(*buf, bounds.bodyEndBit, cell.m_autoFit) | |||
| 2308 | || !readBoundedBitLong(*buf, bounds.bodyEndBit, cell.m_mergedWidth) | |||
| 2309 | || !readBoundedBitLong(*buf, bounds.bodyEndBit, cell.m_mergedHeight) | |||
| 2310 | || !readBoundedBitDouble(*buf, bounds.bodyEndBit, cell.m_rotation)) | |||
| 2311 | return false; | |||
| 2312 | cell.m_type = type; | |||
| 2313 | cell.m_edgeFlags = edgeFlags; | |||
| 2314 | cell.m_valueHandle = readTableHandle(hdlBuf, bounds.handleEndBit); | |||
| 2315 | ||||
| 2316 | if (cell.m_type == 1) { | |||
| 2317 | cell.m_textStyleHandle = cell.m_valueHandle; | |||
| 2318 | if (cell.m_textStyleHandle == 0 && version < DRW::AC1021) { | |||
| 2319 | DRW_TableCellContent content; | |||
| 2320 | content.m_type = 1; | |||
| 2321 | content.m_text = readTableText( | |||
| 2322 | version, textBuf, tableTextEndBit(buf, textBuf, bounds)); | |||
| 2323 | content.m_value.m_dataType = 4; | |||
| 2324 | content.m_value.m_value.addString(1, content.m_text); | |||
| 2325 | cell.m_contents.push_back(content); | |||
| 2326 | } | |||
| 2327 | } else if (cell.m_type == 2) { | |||
| 2328 | cell.m_blockHandle = cell.m_valueHandle; | |||
| 2329 | if (!readBoundedBitDouble(*buf, bounds.bodyEndBit, cell.m_blockScale)) | |||
| 2330 | return false; | |||
| 2331 | bool hasAttributes = false; | |||
| 2332 | if (!readBoundedBit(*buf, bounds.bodyEndBit, hasAttributes)) | |||
| 2333 | return false; | |||
| 2334 | if (hasAttributes) { | |||
| 2335 | std::uint16_t numAttributes = 0; | |||
| 2336 | if (!readBoundedBitShort(*buf, bounds.bodyEndBit, | |||
| 2337 | numAttributes) | |||
| 2338 | || numAttributes > kMaxTableCellAttributes) | |||
| 2339 | return false; | |||
| 2340 | if (!DRW::reserve(cell.m_attributes, numAttributes)) | |||
| 2341 | return false; | |||
| 2342 | for (std::uint16_t i = 0; i < numAttributes; ++i) { | |||
| 2343 | DRW_TableCellAttribute attribute; | |||
| 2344 | attribute.m_attdefHandle = readTableHandle( | |||
| 2345 | hdlBuf, bounds.handleEndBit); | |||
| 2346 | std::uint16_t attributeIndex = 0; | |||
| 2347 | if (!readBoundedBitShort(*buf, bounds.bodyEndBit, | |||
| 2348 | attributeIndex)) | |||
| 2349 | return false; | |||
| 2350 | attribute.m_index = attributeIndex; | |||
| 2351 | attribute.m_text = readTableText( | |||
| 2352 | version, textBuf, tableTextEndBit(buf, textBuf, bounds)); | |||
| 2353 | cell.m_attributes.push_back(attribute); | |||
| 2354 | } | |||
| 2355 | } | |||
| 2356 | ||||
| 2357 | DRW_TableCellContent content; | |||
| 2358 | content.m_type = 4; | |||
| 2359 | content.m_handle = cell.m_blockHandle; | |||
| 2360 | cell.m_contents.push_back(content); | |||
| 2361 | } | |||
| 2362 | ||||
| 2363 | bool hasOverrides = false; | |||
| 2364 | if (!readBoundedBit(*buf, bounds.bodyEndBit, hasOverrides)) | |||
| 2365 | return false; | |||
| 2366 | if (hasOverrides | |||
| 2367 | && !skipR2007TableCellOverrides(version, buf, strBuf, hdlBuf, cell, | |||
| 2368 | ranges, bounds)) | |||
| 2369 | return false; | |||
| 2370 | ||||
| 2371 | if (version > DRW::AC1018) { | |||
| 2372 | if (!skipTableBitLong(*buf, bounds.bodyEndBit)) | |||
| 2373 | return false; | |||
| 2374 | DRW_TableCellContent content; | |||
| 2375 | content.m_type = 1; | |||
| 2376 | if (!readTableCadValue(version, buf, strBuf, hdlBuf, content.m_value, | |||
| 2377 | bounds)) | |||
| 2378 | return false; | |||
| 2379 | if (content.m_value.m_value.type() == DRW_Variant::STRING) | |||
| 2380 | content.m_text = content.m_value.m_value.c_str(); | |||
| 2381 | else if (!content.m_value.m_valueString.empty()) | |||
| 2382 | content.m_text = content.m_value.m_valueString; | |||
| 2383 | cell.m_contents.push_back(content); | |||
| 2384 | } | |||
| 2385 | ||||
| 2386 | return buf->isGood() && (!strBuf || strBuf->isGood()) && (!hdlBuf || hdlBuf->isGood()); | |||
| 2387 | } | |||
| 2388 | ||||
| 2389 | bool skipR2007TableOverrides(DRW::Version version, dwgBuffer *buf, | |||
| 2390 | dwgBuffer *strBuf, dwgBuffer *hdlBuf, | |||
| 2391 | std::vector<DRW_DwgSubrecordRange> *ranges, | |||
| 2392 | const TableDwgBounds& bounds) { | |||
| 2393 | const std::uint64_t startBit = currentDwgBit(buf); | |||
| 2394 | std::uint32_t maskCount = 0; | |||
| 2395 | auto readFlags = [&](std::uint32_t& flags) { | |||
| 2396 | std::int32_t parsed = 0; | |||
| 2397 | if (!readBoundedBitLong(*buf, bounds.bodyEndBit, parsed)) | |||
| 2398 | return false; | |||
| 2399 | flags = static_cast<std::uint32_t>(parsed); | |||
| 2400 | return true; | |||
| 2401 | }; | |||
| 2402 | bool hasMask = false; | |||
| 2403 | if (!readBoundedBit(*buf, bounds.bodyEndBit, hasMask)) | |||
| 2404 | return false; | |||
| 2405 | if (hasMask) { | |||
| 2406 | std::uint32_t flags = 0; | |||
| 2407 | if (!readFlags(flags)) | |||
| 2408 | return false; | |||
| 2409 | ++maskCount; | |||
| 2410 | if (flags & 0x000001) | |||
| 2411 | if (!skipTableBit(*buf, bounds.bodyEndBit)) | |||
| 2412 | return false; | |||
| 2413 | if (flags & 0x000004) | |||
| 2414 | if (!skipTableBitShort(*buf, bounds.bodyEndBit)) | |||
| 2415 | return false; | |||
| 2416 | if (flags & 0x000008) | |||
| 2417 | if (!skipTableBitDouble(*buf, bounds.bodyEndBit)) | |||
| 2418 | return false; | |||
| 2419 | if (flags & 0x000010) | |||
| 2420 | if (!skipTableBitDouble(*buf, bounds.bodyEndBit)) | |||
| 2421 | return false; | |||
| 2422 | if ((flags & 0x000020) | |||
| 2423 | && !readTableCmColor(version, buf, strBuf, bounds)) | |||
| 2424 | return false; | |||
| 2425 | if ((flags & 0x000040) | |||
| 2426 | && !readTableCmColor(version, buf, strBuf, bounds)) | |||
| 2427 | return false; | |||
| 2428 | if ((flags & 0x000080) | |||
| 2429 | && !readTableCmColor(version, buf, strBuf, bounds)) | |||
| 2430 | return false; | |||
| 2431 | if (flags & 0x000100) | |||
| 2432 | if (!skipTableBit(*buf, bounds.bodyEndBit)) | |||
| 2433 | return false; | |||
| 2434 | if (flags & 0x000200) | |||
| 2435 | if (!skipTableBit(*buf, bounds.bodyEndBit)) | |||
| 2436 | return false; | |||
| 2437 | if (flags & 0x000400) | |||
| 2438 | if (!skipTableBit(*buf, bounds.bodyEndBit)) | |||
| 2439 | return false; | |||
| 2440 | if ((flags & 0x000800) | |||
| 2441 | && !readTableCmColor(version, buf, strBuf, bounds)) | |||
| 2442 | return false; | |||
| 2443 | if ((flags & 0x001000) | |||
| 2444 | && !readTableCmColor(version, buf, strBuf, bounds)) | |||
| 2445 | return false; | |||
| 2446 | if ((flags & 0x002000) | |||
| 2447 | && !readTableCmColor(version, buf, strBuf, bounds)) | |||
| 2448 | return false; | |||
| 2449 | if (flags & 0x004000) | |||
| 2450 | if (!skipTableBitShort(*buf, bounds.bodyEndBit)) | |||
| 2451 | return false; | |||
| 2452 | if (flags & 0x008000) | |||
| 2453 | if (!skipTableBitShort(*buf, bounds.bodyEndBit)) | |||
| 2454 | return false; | |||
| 2455 | if (flags & 0x010000) | |||
| 2456 | if (!skipTableBitShort(*buf, bounds.bodyEndBit)) | |||
| 2457 | return false; | |||
| 2458 | if (flags & 0x020000) | |||
| 2459 | if (readTableHandle(hdlBuf, bounds.handleEndBit) == 0 | |||
| 2460 | && hdlBuf != nullptr && !hdlBuf->isGood()) | |||
| 2461 | return false; | |||
| 2462 | if (flags & 0x040000) | |||
| 2463 | if (readTableHandle(hdlBuf, bounds.handleEndBit) == 0 | |||
| 2464 | && hdlBuf != nullptr && !hdlBuf->isGood()) | |||
| 2465 | return false; | |||
| 2466 | if (flags & 0x080000) | |||
| 2467 | if (readTableHandle(hdlBuf, bounds.handleEndBit) == 0 | |||
| 2468 | && hdlBuf != nullptr && !hdlBuf->isGood()) | |||
| 2469 | return false; | |||
| 2470 | if (flags & 0x100000) | |||
| 2471 | if (!skipTableBitDouble(*buf, bounds.bodyEndBit)) | |||
| 2472 | return false; | |||
| 2473 | if (flags & 0x200000) | |||
| 2474 | if (!skipTableBitDouble(*buf, bounds.bodyEndBit)) | |||
| 2475 | return false; | |||
| 2476 | if (flags & 0x400000) | |||
| 2477 | if (!skipTableBitDouble(*buf, bounds.bodyEndBit)) | |||
| 2478 | return false; | |||
| 2479 | } | |||
| 2480 | ||||
| 2481 | if (!readBoundedBit(*buf, bounds.bodyEndBit, hasMask)) | |||
| 2482 | return false; | |||
| 2483 | if (hasMask) { | |||
| 2484 | std::uint32_t flags = 0; | |||
| 2485 | if (!readFlags(flags)) | |||
| 2486 | return false; | |||
| 2487 | ++maskCount; | |||
| 2488 | for (int i = 0; i < 18; ++i) { | |||
| 2489 | if (flags & (1u << i) | |||
| 2490 | && !readTableCmColor(version, buf, strBuf, bounds)) | |||
| 2491 | return false; | |||
| 2492 | } | |||
| 2493 | } | |||
| 2494 | ||||
| 2495 | if (!readBoundedBit(*buf, bounds.bodyEndBit, hasMask)) | |||
| 2496 | return false; | |||
| 2497 | if (hasMask) { | |||
| 2498 | std::uint32_t flags = 0; | |||
| 2499 | if (!readFlags(flags)) | |||
| 2500 | return false; | |||
| 2501 | ++maskCount; | |||
| 2502 | for (int i = 0; i < 18; ++i) { | |||
| 2503 | if (flags & (1u << i)) | |||
| 2504 | if (!skipTableBitShort(*buf, bounds.bodyEndBit)) | |||
| 2505 | return false; | |||
| 2506 | } | |||
| 2507 | } | |||
| 2508 | ||||
| 2509 | if (!readBoundedBit(*buf, bounds.bodyEndBit, hasMask)) | |||
| 2510 | return false; | |||
| 2511 | if (hasMask) { | |||
| 2512 | std::uint32_t flags = 0; | |||
| 2513 | if (!readFlags(flags)) | |||
| 2514 | return false; | |||
| 2515 | ++maskCount; | |||
| 2516 | for (int i = 0; i < 18; ++i) { | |||
| 2517 | if (flags & (1u << i)) | |||
| 2518 | if (!skipTableBitShort(*buf, bounds.bodyEndBit)) | |||
| 2519 | return false; | |||
| 2520 | } | |||
| 2521 | } | |||
| 2522 | ||||
| 2523 | const bool good = buf->isGood() && (!strBuf || strBuf->isGood()) && (!hdlBuf || hdlBuf->isGood()); | |||
| 2524 | if (ranges != nullptr && (maskCount != 0 || currentDwgBit(buf) != startBit)) { | |||
| 2525 | ranges->push_back(makeDwgSubrecordRange( | |||
| 2526 | "r2007-table-overrides", startBit, currentDwgBit(buf), | |||
| 2527 | version, maskCount, good)); | |||
| 2528 | } | |||
| 2529 | return good; | |||
| 2530 | } | |||
| 2531 | ||||
| 2532 | bool skipTableContentFormat(DRW::Version version, dwgBuffer *buf, | |||
| 2533 | dwgBuffer *strBuf, dwgBuffer *hdlBuf, | |||
| 2534 | std::vector<DRW_DwgSubrecordRange> *ranges, | |||
| 2535 | const TableDwgBounds& bounds) { | |||
| 2536 | const std::uint64_t startBit = currentDwgBit(buf); | |||
| 2537 | dwgBuffer *textBuf = strBuf ? strBuf : buf; | |||
| 2538 | if (!skipTableBitLong(*buf, bounds.bodyEndBit) // property override flags | |||
| 2539 | || !skipTableBitLong(*buf, bounds.bodyEndBit) // property flags | |||
| 2540 | || !skipTableBitLong(*buf, bounds.bodyEndBit) // value data type | |||
| 2541 | || !skipTableBitLong(*buf, bounds.bodyEndBit)) { // value unit type | |||
| 2542 | return false; | |||
| 2543 | } | |||
| 2544 | readTableText(version, textBuf, tableTextEndBit(buf, textBuf, bounds)); | |||
| 2545 | if (!textBuf->isGood()) | |||
| 2546 | return false; | |||
| 2547 | if (!skipTableBitDouble(*buf, bounds.bodyEndBit) // rotation | |||
| 2548 | || !skipTableBitDouble(*buf, bounds.bodyEndBit) // block scale | |||
| 2549 | || !skipTableBitLong(*buf, bounds.bodyEndBit)) // alignment | |||
| 2550 | return false; | |||
| 2551 | std::int32_t rgb = -1; | |||
| 2552 | UTF8STRINGstd::string name; | |||
| 2553 | UTF8STRINGstd::string book; | |||
| 2554 | std::uint32_t color = 0; | |||
| 2555 | if (!readBoundedCmColor(*buf, strBuf, bounds.bodyEndBit, version, | |||
| 2556 | color, &rgb, nullptr, &name, &book, | |||
| 2557 | bounds.stringEndBit) | |||
| 2558 | || (hdlBuf != nullptr | |||
| 2559 | && readTableHandle(hdlBuf, bounds.handleEndBit) == 0 | |||
| 2560 | && !hdlBuf->isGood()) | |||
| 2561 | || !skipTableBitDouble(*buf, bounds.bodyEndBit)) // text height | |||
| 2562 | return false; | |||
| 2563 | const bool good = buf->isGood() && (!strBuf || strBuf->isGood()) && (!hdlBuf || hdlBuf->isGood()); | |||
| 2564 | if (ranges != nullptr) { | |||
| 2565 | ranges->push_back(makeDwgSubrecordRange( | |||
| 2566 | "table-content-format", startBit, currentDwgBit(buf), | |||
| 2567 | version, 1, good)); | |||
| 2568 | } | |||
| 2569 | return good; | |||
| 2570 | } | |||
| 2571 | ||||
| 2572 | bool skipTableCellStyle(DRW::Version version, dwgBuffer *buf, | |||
| 2573 | dwgBuffer *strBuf, dwgBuffer *hdlBuf, | |||
| 2574 | std::vector<DRW_DwgSubrecordRange> *ranges, | |||
| 2575 | const TableDwgBounds& bounds) { | |||
| 2576 | const std::uint64_t startBit = currentDwgBit(buf); | |||
| 2577 | if (!skipTableBitLong(*buf, bounds.bodyEndBit)) // style type | |||
| 2578 | return false; | |||
| 2579 | std::uint16_t dataFlags = 0; | |||
| 2580 | if (!readBoundedBitShort(*buf, bounds.bodyEndBit, dataFlags)) | |||
| 2581 | return false; | |||
| 2582 | const bool hasData = dataFlags != 0; | |||
| 2583 | if (!hasData) { | |||
| 2584 | if (ranges != nullptr) { | |||
| 2585 | ranges->push_back(makeDwgSubrecordRange( | |||
| 2586 | "table-cell-style", startBit, currentDwgBit(buf), | |||
| 2587 | version, 0, buf->isGood())); | |||
| 2588 | } | |||
| 2589 | return buf->isGood(); | |||
| 2590 | } | |||
| 2591 | ||||
| 2592 | if (!skipTableBitLong(*buf, bounds.bodyEndBit) // property override flags | |||
| 2593 | || !skipTableBitLong(*buf, bounds.bodyEndBit)) // merge flags | |||
| 2594 | return false; | |||
| 2595 | std::int32_t rgb = -1; | |||
| 2596 | UTF8STRINGstd::string name; | |||
| 2597 | UTF8STRINGstd::string book; | |||
| 2598 | dwgBuffer *textBuf = strBuf ? strBuf : buf; | |||
| 2599 | std::uint32_t color = 0; | |||
| 2600 | if (!readBoundedCmColor(*buf, strBuf, bounds.bodyEndBit, version, | |||
| 2601 | color, &rgb, nullptr, &name, &book, | |||
| 2602 | bounds.stringEndBit) | |||
| 2603 | || !skipTableBitLong(*buf, bounds.bodyEndBit)) // content layout | |||
| 2604 | return false; | |||
| 2605 | if (!skipTableContentFormat(version, buf, strBuf, hdlBuf, ranges, | |||
| 2606 | bounds)) | |||
| 2607 | return false; | |||
| 2608 | ||||
| 2609 | std::uint16_t marginFlags = 0; | |||
| 2610 | if (!readBoundedBitShort(*buf, bounds.bodyEndBit, marginFlags)) | |||
| 2611 | return false; | |||
| 2612 | if (marginFlags != 0) { | |||
| 2613 | for (int i = 0; i < 6; ++i) | |||
| 2614 | if (!skipTableBitDouble(*buf, bounds.bodyEndBit)) | |||
| 2615 | return false; | |||
| 2616 | } | |||
| 2617 | ||||
| 2618 | std::uint32_t borders = 0; | |||
| 2619 | if (!readTableBodyCount(version, buf, bounds.bodyEndBit, 6, 2, | |||
| 2620 | borders)) { | |||
| 2621 | DRW_DBG("TABLE cell style border count out of range: ")DRW_dbg::dbg("TABLE cell style border count out of range: "); DRW_DBG(borders)DRW_dbg::dbg(borders); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 2622 | return false; | |||
| 2623 | } | |||
| 2624 | for (std::uint32_t i = 0; i < borders; ++i) { | |||
| 2625 | std::int32_t edgeFlags = 0; | |||
| 2626 | if (!readBoundedBitLong(*buf, bounds.bodyEndBit, edgeFlags)) | |||
| 2627 | return false; | |||
| 2628 | if (edgeFlags == 0) | |||
| 2629 | continue; | |||
| 2630 | if (!skipTableBitLong(*buf, bounds.bodyEndBit) // border overrides | |||
| 2631 | || !skipTableBitLong(*buf, bounds.bodyEndBit)) // border type | |||
| 2632 | return false; | |||
| 2633 | if (!readBoundedCmColor(*buf, strBuf, bounds.bodyEndBit, version, | |||
| 2634 | color, &rgb, nullptr, &name, &book, | |||
| 2635 | bounds.stringEndBit) | |||
| 2636 | || (hdlBuf != nullptr | |||
| 2637 | && readTableHandle(hdlBuf, bounds.handleEndBit) == 0 | |||
| 2638 | && !hdlBuf->isGood()) | |||
| 2639 | || !skipTableBitLong(*buf, bounds.bodyEndBit) // visible/invisible | |||
| 2640 | || !skipTableBitDouble(*buf, bounds.bodyEndBit)) // double line spacing | |||
| 2641 | return false; | |||
| 2642 | } | |||
| 2643 | ||||
| 2644 | const bool good = buf->isGood() && (!strBuf || strBuf->isGood()) && (!hdlBuf || hdlBuf->isGood()); | |||
| 2645 | if (ranges != nullptr) { | |||
| 2646 | ranges->push_back(makeDwgSubrecordRange( | |||
| 2647 | "table-cell-style", startBit, currentDwgBit(buf), | |||
| 2648 | version, borders, good)); | |||
| 2649 | } | |||
| 2650 | return good; | |||
| 2651 | } | |||
| 2652 | ||||
| 2653 | bool parseTableCell(DRW::Version version, dwgBuffer *buf, dwgBuffer *strBuf, | |||
| 2654 | dwgBuffer *hdlBuf, DRW_TableCell& cell, | |||
| 2655 | std::vector<DRW_DwgSubrecordRange> *ranges, | |||
| 2656 | const TableDwgBounds& bounds) { | |||
| 2657 | dwgBuffer *textBuf = strBuf ? strBuf : buf; | |||
| 2658 | if (!readBoundedBitLong(*buf, bounds.bodyEndBit, cell.m_flags)) | |||
| 2659 | return false; | |||
| 2660 | cell.m_toolTip = readTableText( | |||
| 2661 | version, textBuf, tableTextEndBit(buf, textBuf, bounds)); | |||
| 2662 | if (!textBuf->isGood()) { | |||
| 2663 | DRW_DBG("TABLE cell tooltip string read failed\n")DRW_dbg::dbg("TABLE cell tooltip string read failed\n"); | |||
| 2664 | return false; | |||
| 2665 | } | |||
| 2666 | if (!skipTableBitLong(*buf, bounds.bodyEndBit)) // custom data | |||
| 2667 | return false; | |||
| 2668 | ||||
| 2669 | std::uint32_t customItems = 0; | |||
| 2670 | if (!readTableBodyCount(version, buf, bounds.bodyEndBit, kMaxTableItems, 2, | |||
| 2671 | customItems)) { | |||
| 2672 | DRW_DBG("TABLE cell custom item count out of range: ")DRW_dbg::dbg("TABLE cell custom item count out of range: "); DRW_DBG(customItems)DRW_dbg::dbg(customItems); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 2673 | return false; | |||
| 2674 | } | |||
| 2675 | for (std::uint32_t i = 0; i < customItems; ++i) { | |||
| 2676 | if (!skipTableCustomData(version, buf, strBuf, hdlBuf, bounds)) { | |||
| 2677 | DRW_DBG("TABLE cell custom data parse incomplete\n")DRW_dbg::dbg("TABLE cell custom data parse incomplete\n"); | |||
| 2678 | return false; | |||
| 2679 | } | |||
| 2680 | } | |||
| 2681 | ||||
| 2682 | std::int32_t hasLinkedData = 0; | |||
| 2683 | if (!readBoundedBitLong(*buf, bounds.bodyEndBit, hasLinkedData)) | |||
| 2684 | return false; | |||
| 2685 | if (hasLinkedData != 0) { | |||
| 2686 | if (hdlBuf != nullptr | |||
| 2687 | && readTableHandle(hdlBuf, bounds.handleEndBit) == 0 | |||
| 2688 | && !hdlBuf->isGood()) | |||
| 2689 | return false; | |||
| 2690 | if (!skipTableBitLong(*buf, bounds.bodyEndBit) | |||
| 2691 | || !skipTableBitLong(*buf, bounds.bodyEndBit) | |||
| 2692 | || !skipTableBitLong(*buf, bounds.bodyEndBit)) | |||
| 2693 | return false; | |||
| 2694 | } | |||
| 2695 | ||||
| 2696 | std::uint32_t contentCount = 0; | |||
| 2697 | if (!readTableBodyCount(version, buf, bounds.bodyEndBit, kMaxTableItems, 2, | |||
| 2698 | contentCount)) { | |||
| 2699 | DRW_DBG("TABLE cell content count out of range: ")DRW_dbg::dbg("TABLE cell content count out of range: "); DRW_DBG(contentCount)DRW_dbg::dbg(contentCount); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 2700 | return false; | |||
| 2701 | } | |||
| 2702 | if (!DRW::reserve(cell.m_contents, static_cast<int>(contentCount))) | |||
| 2703 | return false; | |||
| 2704 | for (std::uint32_t i = 0; i < contentCount; ++i) { | |||
| 2705 | DRW_TableCellContent content; | |||
| 2706 | if (!readBoundedBitLong(*buf, bounds.bodyEndBit, content.m_type)) | |||
| 2707 | return false; | |||
| 2708 | if (content.m_type == 1) { | |||
| 2709 | if (!readTableCadValue(version, buf, strBuf, hdlBuf, | |||
| 2710 | content.m_value, bounds)) { | |||
| 2711 | DRW_DBG("TABLE cell value parse incomplete\n")DRW_dbg::dbg("TABLE cell value parse incomplete\n"); | |||
| 2712 | return false; | |||
| 2713 | } | |||
| 2714 | if (content.m_value.m_value.type() == DRW_Variant::STRING) | |||
| 2715 | content.m_text = content.m_value.m_value.c_str(); | |||
| 2716 | else if (!content.m_value.m_valueString.empty()) | |||
| 2717 | content.m_text = content.m_value.m_valueString; | |||
| 2718 | } else if (content.m_type == 2 || content.m_type == 4) { | |||
| 2719 | content.m_handle = readTableHandle(hdlBuf, bounds.handleEndBit); | |||
| 2720 | } | |||
| 2721 | ||||
| 2722 | std::uint32_t numAttrs = 0; | |||
| 2723 | if (!readTableBodyCount(version, buf, bounds.bodyEndBit, kMaxTableItems, 2, | |||
| 2724 | numAttrs)) { | |||
| 2725 | DRW_DBG("TABLE cell attribute count out of range: ")DRW_dbg::dbg("TABLE cell attribute count out of range: "); DRW_DBG(numAttrs)DRW_dbg::dbg(numAttrs); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 2726 | return false; | |||
| 2727 | } | |||
| 2728 | for (std::uint32_t attr = 0; attr < numAttrs; ++attr) { | |||
| 2729 | if (hdlBuf != nullptr | |||
| 2730 | && readTableHandle(hdlBuf, bounds.handleEndBit) == 0 | |||
| 2731 | && !hdlBuf->isGood()) | |||
| 2732 | return false; | |||
| 2733 | readTableText(version, textBuf, | |||
| 2734 | tableTextEndBit(buf, textBuf, bounds)); | |||
| 2735 | if (!textBuf->isGood() | |||
| 2736 | || !skipTableBitLong(*buf, bounds.bodyEndBit)) | |||
| 2737 | return false; | |||
| 2738 | } | |||
| 2739 | ||||
| 2740 | std::uint16_t contentFormatFlag = 0; | |||
| 2741 | if (!readBoundedBitShort(*buf, bounds.bodyEndBit, contentFormatFlag)) | |||
| 2742 | return false; | |||
| 2743 | const bool hasContentFormat = contentFormatFlag != 0; | |||
| 2744 | if (hasContentFormat | |||
| 2745 | && !skipTableContentFormat(version, buf, strBuf, hdlBuf, ranges, | |||
| 2746 | bounds)) { | |||
| 2747 | DRW_DBG("TABLE cell content format parse incomplete\n")DRW_dbg::dbg("TABLE cell content format parse incomplete\n"); | |||
| 2748 | return false; | |||
| 2749 | } | |||
| 2750 | cell.m_contents.push_back(content); | |||
| 2751 | } | |||
| 2752 | ||||
| 2753 | if (!skipTableCellStyle(version, buf, strBuf, hdlBuf, ranges, bounds)) { | |||
| 2754 | DRW_DBG("TABLE cell style override parse incomplete\n")DRW_dbg::dbg("TABLE cell style override parse incomplete\n"); | |||
| 2755 | return false; | |||
| 2756 | } | |||
| 2757 | ||||
| 2758 | if (!readBoundedBitLong(*buf, bounds.bodyEndBit, cell.m_styleId)) | |||
| 2759 | return false; | |||
| 2760 | const std::uint64_t geometryStartBit = currentDwgBit(buf); | |||
| 2761 | std::int32_t hasGeometry = 0; | |||
| 2762 | if (!readBoundedBitLong(*buf, bounds.bodyEndBit, hasGeometry)) | |||
| 2763 | return false; | |||
| 2764 | if (hasGeometry != 0) { | |||
| 2765 | std::int32_t geometryFlags = 0; | |||
| 2766 | if (!skipTableBitLong(*buf, bounds.bodyEndBit) // unknown AC1027+ geometry marker | |||
| 2767 | || !readBoundedBitDouble(*buf, bounds.bodyEndBit, cell.m_width) | |||
| 2768 | || !readBoundedBitDouble(*buf, bounds.bodyEndBit, cell.m_height) | |||
| 2769 | || !readBoundedBitLong(*buf, bounds.bodyEndBit, geometryFlags)) | |||
| 2770 | return false; | |||
| 2771 | cell.m_geometryFlags = geometryFlags; | |||
| 2772 | cell.m_geometryHandle = readTableHandle(hdlBuf, bounds.handleEndBit); | |||
| 2773 | if (cell.m_geometryFlags != 0) { | |||
| 2774 | std::int32_t geometryRecordFlags = 0; | |||
| 2775 | if (!readBounded3BitDouble(*buf, bounds.bodyEndBit, | |||
| 2776 | cell.m_geometryTopLeft) | |||
| 2777 | || !readBounded3BitDouble(*buf, bounds.bodyEndBit, | |||
| 2778 | cell.m_geometryCenter) | |||
| 2779 | || !readBoundedBitDouble(*buf, bounds.bodyEndBit, | |||
| 2780 | cell.m_contentWidth) | |||
| 2781 | || !readBoundedBitDouble(*buf, bounds.bodyEndBit, | |||
| 2782 | cell.m_contentHeight) | |||
| 2783 | || !readBoundedBitDouble(*buf, bounds.bodyEndBit, | |||
| 2784 | cell.m_geometryWidth) | |||
| 2785 | || !readBoundedBitDouble(*buf, bounds.bodyEndBit, | |||
| 2786 | cell.m_geometryHeight) | |||
| 2787 | || !readBoundedBitLong(*buf, bounds.bodyEndBit, | |||
| 2788 | geometryRecordFlags)) | |||
| 2789 | return false; | |||
| 2790 | cell.m_geometryRecordFlags = geometryRecordFlags; | |||
| 2791 | } | |||
| 2792 | if (ranges != nullptr) { | |||
| 2793 | const bool geometryGood = buf->isGood() && (!hdlBuf || hdlBuf->isGood()); | |||
| 2794 | ranges->push_back(makeDwgSubrecordRange( | |||
| 2795 | "table-cell-geometry-tail", geometryStartBit, currentDwgBit(buf), | |||
| 2796 | version, cell.m_geometryFlags, geometryGood)); | |||
| 2797 | } | |||
| 2798 | } | |||
| 2799 | ||||
| 2800 | const bool good = buf->isGood() && (!strBuf || strBuf->isGood()) && (!hdlBuf || hdlBuf->isGood()); | |||
| 2801 | if (!good) | |||
| 2802 | DRW_DBG("TABLE cell stream ended unexpectedly\n")DRW_dbg::dbg("TABLE cell stream ended unexpectedly\n"); | |||
| 2803 | return good; | |||
| 2804 | } | |||
| 2805 | ||||
| 2806 | bool parseTableContent(DRW::Version version, dwgBuffer *buf, dwgBuffer *strBuf, | |||
| 2807 | dwgBuffer *hdlBuf, DRW_TableContent& content, | |||
| 2808 | const TableDwgBounds& bounds) { | |||
| 2809 | dwgBuffer *textBuf = strBuf ? strBuf : buf; | |||
| 2810 | const std::uint64_t textEndBit = tableTextEndBit(buf, textBuf, bounds); | |||
| 2811 | content.m_name = readTableText(version, textBuf, textEndBit); | |||
| 2812 | content.m_description = readTableText(version, textBuf, textEndBit); | |||
| 2813 | if (!textBuf->isGood()) | |||
| 2814 | return false; | |||
| 2815 | ||||
| 2816 | std::uint32_t columns = 0; | |||
| 2817 | if (!readTableBodyCount(version, buf, bounds.bodyEndBit, | |||
| 2818 | kMaxTableColumns, 2, | |||
| 2819 | columns)) { | |||
| 2820 | DRW_DBG("TABLECONTENT column count out of range: ")DRW_dbg::dbg("TABLECONTENT column count out of range: "); DRW_DBG(columns)DRW_dbg::dbg(columns); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 2821 | return false; | |||
| 2822 | } | |||
| 2823 | content.m_columns.clear(); | |||
| 2824 | if (!DRW::reserve(content.m_columns, static_cast<int>(columns))) | |||
| 2825 | return false; | |||
| 2826 | for (std::uint32_t col = 0; col < columns; ++col) { | |||
| 2827 | DRW_TableColumn column; | |||
| 2828 | column.m_name = readTableText(version, textBuf, textEndBit); | |||
| 2829 | if (!textBuf->isGood() | |||
| 2830 | || !skipTableBitLong(*buf, bounds.bodyEndBit)) // custom data | |||
| 2831 | return false; | |||
| 2832 | std::uint32_t customItems = 0; | |||
| 2833 | if (!readTableBodyCount(version, buf, bounds.bodyEndBit, | |||
| 2834 | kMaxTableItems, 2, | |||
| 2835 | customItems)) { | |||
| 2836 | DRW_DBG("TABLECONTENT column custom item count out of range: ")DRW_dbg::dbg("TABLECONTENT column custom item count out of range: " ); DRW_DBG(customItems)DRW_dbg::dbg(customItems); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 2837 | return false; | |||
| 2838 | } | |||
| 2839 | for (std::uint32_t i = 0; i < customItems; ++i) { | |||
| 2840 | if (!skipTableCustomData(version, buf, strBuf, hdlBuf, bounds)) { | |||
| 2841 | DRW_DBG("TABLECONTENT column custom data parse incomplete\n")DRW_dbg::dbg("TABLECONTENT column custom data parse incomplete\n" ); | |||
| 2842 | return false; | |||
| 2843 | } | |||
| 2844 | } | |||
| 2845 | if (!skipTableCellStyle(version, buf, strBuf, hdlBuf, | |||
| 2846 | &content.m_subrecordRanges, bounds)) { | |||
| 2847 | DRW_DBG("TABLECONTENT column cell style parse incomplete\n")DRW_dbg::dbg("TABLECONTENT column cell style parse incomplete\n" ); | |||
| 2848 | return false; | |||
| 2849 | } | |||
| 2850 | if (!skipTableBitLong(*buf, bounds.bodyEndBit) // style id | |||
| 2851 | || !readBoundedBitDouble(*buf, bounds.bodyEndBit, | |||
| 2852 | column.m_width)) | |||
| 2853 | return false; | |||
| 2854 | content.m_columns.push_back(column); | |||
| 2855 | } | |||
| 2856 | ||||
| 2857 | std::uint32_t rows = 0; | |||
| 2858 | if (!readTableBodyCount(version, buf, bounds.bodyEndBit, | |||
| 2859 | kMaxTableRows, 2, | |||
| 2860 | rows) | |||
| 2861 | || (columns != 0 && rows > kMaxTableCells / columns)) { | |||
| 2862 | DRW_DBG("TABLECONTENT row count out of range: ")DRW_dbg::dbg("TABLECONTENT row count out of range: "); DRW_DBG(rows)DRW_dbg::dbg(rows); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 2863 | return false; | |||
| 2864 | } | |||
| 2865 | content.m_rows.clear(); | |||
| 2866 | if (!DRW::reserve(content.m_rows, static_cast<int>(rows))) | |||
| 2867 | return false; | |||
| 2868 | for (std::uint32_t rowIndex = 0; rowIndex < rows; ++rowIndex) { | |||
| 2869 | DRW_TableRow row; | |||
| 2870 | std::uint32_t cells = 0; | |||
| 2871 | if (!readTableBodyCount(version, buf, bounds.bodyEndBit, | |||
| 2872 | kMaxTableColumns, 2, | |||
| 2873 | cells) | |||
| 2874 | || cells > kMaxTableItems) { | |||
| 2875 | DRW_DBG("TABLECONTENT row cell count out of range: ")DRW_dbg::dbg("TABLECONTENT row cell count out of range: "); DRW_DBG(cells)DRW_dbg::dbg(cells); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 2876 | return false; | |||
| 2877 | } | |||
| 2878 | if (!DRW::reserve(row.m_cells, static_cast<int>(cells))) | |||
| 2879 | return false; | |||
| 2880 | for (std::uint32_t cellIndex = 0; cellIndex < cells; ++cellIndex) { | |||
| 2881 | DRW_TableCell cell; | |||
| 2882 | if (!parseTableCell(version, buf, strBuf, hdlBuf, cell, | |||
| 2883 | &content.m_subrecordRanges, bounds)) { | |||
| 2884 | DRW_DBG("TABLECONTENT cell parse incomplete at row ")DRW_dbg::dbg("TABLECONTENT cell parse incomplete at row "); DRW_DBG(rowIndex)DRW_dbg::dbg(rowIndex); | |||
| 2885 | DRW_DBG(" cell ")DRW_dbg::dbg(" cell "); DRW_DBG(cellIndex)DRW_dbg::dbg(cellIndex); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 2886 | return false; | |||
| 2887 | } | |||
| 2888 | row.m_cells.push_back(cell); | |||
| 2889 | } | |||
| 2890 | ||||
| 2891 | if (!skipTableBitLong(*buf, bounds.bodyEndBit)) // custom data | |||
| 2892 | return false; | |||
| 2893 | std::uint32_t customItems = 0; | |||
| 2894 | if (!readTableBodyCount(version, buf, bounds.bodyEndBit, | |||
| 2895 | kMaxTableItems, 2, | |||
| 2896 | customItems)) { | |||
| 2897 | DRW_DBG("TABLECONTENT row custom item count out of range: ")DRW_dbg::dbg("TABLECONTENT row custom item count out of range: " ); DRW_DBG(customItems)DRW_dbg::dbg(customItems); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 2898 | return false; | |||
| 2899 | } | |||
| 2900 | for (std::uint32_t i = 0; i < customItems; ++i) { | |||
| 2901 | if (!skipTableCustomData(version, buf, strBuf, hdlBuf, bounds)) { | |||
| 2902 | DRW_DBG("TABLECONTENT row custom data parse incomplete\n")DRW_dbg::dbg("TABLECONTENT row custom data parse incomplete\n" ); | |||
| 2903 | return false; | |||
| 2904 | } | |||
| 2905 | } | |||
| 2906 | if (!skipTableCellStyle(version, buf, strBuf, hdlBuf, | |||
| 2907 | &content.m_subrecordRanges, bounds)) { | |||
| 2908 | DRW_DBG("TABLECONTENT row cell style parse incomplete\n")DRW_dbg::dbg("TABLECONTENT row cell style parse incomplete\n" ); | |||
| 2909 | return false; | |||
| 2910 | } | |||
| 2911 | if (!skipTableBitLong(*buf, bounds.bodyEndBit) // style id | |||
| 2912 | || !readBoundedBitDouble(*buf, bounds.bodyEndBit, row.m_height)) | |||
| 2913 | return false; | |||
| 2914 | content.m_rows.push_back(row); | |||
| 2915 | } | |||
| 2916 | ||||
| 2917 | std::uint32_t fieldRefs = 0; | |||
| 2918 | if (!readTableBodyCount(version, buf, bounds.bodyEndBit, | |||
| 2919 | kMaxTableItems, 0, | |||
| 2920 | fieldRefs)) { | |||
| 2921 | DRW_DBG("TABLECONTENT field reference count out of range: ")DRW_dbg::dbg("TABLECONTENT field reference count out of range: " ); DRW_DBG(fieldRefs)DRW_dbg::dbg(fieldRefs); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 2922 | return false; | |||
| 2923 | } | |||
| 2924 | content.m_fieldHandles.clear(); | |||
| 2925 | if (!DRW::reserve(content.m_fieldHandles, static_cast<int>(fieldRefs))) | |||
| 2926 | return false; | |||
| 2927 | for (std::uint32_t i = 0; i < fieldRefs; ++i) { | |||
| 2928 | const std::uint32_t ref = readTableHandle(hdlBuf, bounds.handleEndBit); | |||
| 2929 | if (hdlBuf != nullptr && !hdlBuf->isGood()) | |||
| 2930 | return false; | |||
| 2931 | if (ref != 0) | |||
| 2932 | content.m_fieldHandles.push_back(ref); | |||
| 2933 | } | |||
| 2934 | ||||
| 2935 | if (!skipTableCellStyle(version, buf, strBuf, hdlBuf, | |||
| 2936 | &content.m_subrecordRanges, bounds)) { | |||
| 2937 | DRW_DBG("TABLECONTENT table cell style parse incomplete\n")DRW_dbg::dbg("TABLECONTENT table cell style parse incomplete\n" ); | |||
| 2938 | return false; | |||
| 2939 | } | |||
| 2940 | ||||
| 2941 | std::uint32_t mergedRanges = 0; | |||
| 2942 | if (!readTableBodyCount(version, buf, bounds.bodyEndBit, | |||
| 2943 | kMaxTableItems, 8, | |||
| 2944 | mergedRanges)) { | |||
| 2945 | DRW_DBG("TABLECONTENT merged range count out of range: ")DRW_dbg::dbg("TABLECONTENT merged range count out of range: " ); DRW_DBG(mergedRanges)DRW_dbg::dbg(mergedRanges); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 2946 | return false; | |||
| 2947 | } | |||
| 2948 | content.m_mergedRanges.clear(); | |||
| 2949 | if (!DRW::reserve(content.m_mergedRanges, | |||
| 2950 | static_cast<int>(mergedRanges))) | |||
| 2951 | return false; | |||
| 2952 | for (std::uint32_t i = 0; i < mergedRanges; ++i) { | |||
| 2953 | DRW_TableMergedRange range; | |||
| 2954 | if (!readBoundedBitLong(*buf, bounds.bodyEndBit, range.m_topRow) | |||
| 2955 | || !readBoundedBitLong(*buf, bounds.bodyEndBit, | |||
| 2956 | range.m_leftColumn) | |||
| 2957 | || !readBoundedBitLong(*buf, bounds.bodyEndBit, | |||
| 2958 | range.m_bottomRow) | |||
| 2959 | || !readBoundedBitLong(*buf, bounds.bodyEndBit, | |||
| 2960 | range.m_rightColumn)) | |||
| 2961 | return false; | |||
| 2962 | content.m_mergedRanges.push_back(range); | |||
| 2963 | } | |||
| 2964 | ||||
| 2965 | content.m_tableStyleHandle = readTableHandle(hdlBuf, bounds.handleEndBit); | |||
| 2966 | const bool good = buf->isGood() && (!strBuf || strBuf->isGood()) && (!hdlBuf || hdlBuf->isGood()); | |||
| 2967 | if (!good) | |||
| 2968 | DRW_DBG("TABLECONTENT stream ended unexpectedly\n")DRW_dbg::dbg("TABLECONTENT stream ended unexpectedly\n"); | |||
| 2969 | return good; | |||
| 2970 | } | |||
| 2971 | ||||
| 2972 | } // namespace | |||
| 2973 | ||||
| 2974 | //! Calculate arbitrary axis | |||
| 2975 | /*! | |||
| 2976 | * Calculate arbitrary axis for apply extrusions | |||
| 2977 | * @author Rallaz | |||
| 2978 | */ | |||
| 2979 | void DRW_Entity::calculateAxis(DRW_Coord extPoint){ | |||
| 2980 | //Follow the arbitrary DXF definitions for extrusion axes. | |||
| 2981 | if (fabs(extPoint.x) < 0.015625 && fabs(extPoint.y) < 0.015625) { | |||
| 2982 | //If we get here, implement Ax = Wy x N where Wy is [0,1,0] per the DXF spec. | |||
| 2983 | //The cross product works out to Wy.y*N.z-Wy.z*N.y, Wy.z*N.x-Wy.x*N.z, Wy.x*N.y-Wy.y*N.x | |||
| 2984 | //Factoring in the fixed values for Wy gives N.z,0,-N.x | |||
| 2985 | extAxisX.x = extPoint.z; | |||
| 2986 | extAxisX.y = 0; | |||
| 2987 | extAxisX.z = -extPoint.x; | |||
| 2988 | } else { | |||
| 2989 | //Otherwise, implement Ax = Wz x N where Wz is [0,0,1] per the DXF spec. | |||
| 2990 | //The cross product works out to Wz.y*N.z-Wz.z*N.y, Wz.z*N.x-Wz.x*N.z, Wz.x*N.y-Wz.y*N.x | |||
| 2991 | //Factoring in the fixed values for Wz gives -N.y,N.x,0. | |||
| 2992 | extAxisX.x = -extPoint.y; | |||
| 2993 | extAxisX.y = extPoint.x; | |||
| 2994 | extAxisX.z = 0; | |||
| 2995 | } | |||
| 2996 | ||||
| 2997 | extAxisX.unitize(); | |||
| 2998 | ||||
| 2999 | //Ay = N x Ax | |||
| 3000 | extAxisY.x = (extPoint.y * extAxisX.z) - (extAxisX.y * extPoint.z); | |||
| 3001 | extAxisY.y = (extPoint.z * extAxisX.x) - (extAxisX.z * extPoint.x); | |||
| 3002 | extAxisY.z = (extPoint.x * extAxisX.y) - (extAxisX.x * extPoint.y); | |||
| 3003 | ||||
| 3004 | extAxisY.unitize(); | |||
| 3005 | } | |||
| 3006 | ||||
| 3007 | //! Extrude a point using arbitrary axis | |||
| 3008 | /*! | |||
| 3009 | * apply extrusion in a point using arbitrary axis (previous calculated) | |||
| 3010 | * @author Rallaz | |||
| 3011 | */ | |||
| 3012 | void DRW_Entity::extrudePoint(DRW_Coord extPoint, DRW_Coord *point){ | |||
| 3013 | double px, py, pz; | |||
| 3014 | px = (extAxisX.x*point->x)+(extAxisY.x*point->y)+(extPoint.x*point->z); | |||
| 3015 | py = (extAxisX.y*point->x)+(extAxisY.y*point->y)+(extPoint.y*point->z); | |||
| 3016 | pz = (extAxisX.z*point->x)+(extAxisY.z*point->y)+(extPoint.z*point->z); | |||
| 3017 | ||||
| 3018 | point->x = px; | |||
| 3019 | point->y = py; | |||
| 3020 | point->z = pz; | |||
| 3021 | } | |||
| 3022 | ||||
| 3023 | bool DRW_Entity::parseCode(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 3024 | try { | |||
| 3025 | switch (code) { | |||
| 3026 | case DRW::dxfCode::HANDLE: | |||
| 3027 | // A damaged file's empty or repeated handle on a typed entity is | |||
| 3028 | // dropped; the entity loads and gets a new handle when saved. | |||
| 3029 | if (reader->getString().empty()) | |||
| 3030 | break; | |||
| 3031 | if (!reader->isValidHandleString()) | |||
| 3032 | return false; | |||
| 3033 | if (reader->registerSelfHandle()) | |||
| 3034 | handle = reader->getHandleString(); | |||
| 3035 | break; | |||
| 3036 | case DRW::dxfCode::OWNER_HANDLE: | |||
| 3037 | parentHandle = reader->getHandleString(); | |||
| 3038 | break; | |||
| 3039 | case DRW::dxfCode::LAYER: | |||
| 3040 | layer = reader->getUtf8String(); | |||
| 3041 | break; | |||
| 3042 | case 6: | |||
| 3043 | lineType = reader->getUtf8String(); | |||
| 3044 | break; | |||
| 3045 | case DRW::dxfCode::COLOR: | |||
| 3046 | color = reader->getInt32(); | |||
| 3047 | break; | |||
| 3048 | case DRW::dxfCode::LINEWEIGHT: | |||
| 3049 | lWeight = DRW_LW_Conv::dxfInt2lineWidth(reader->getInt32()); | |||
| 3050 | break; | |||
| 3051 | case 48: | |||
| 3052 | ltypeScale = reader->getDouble(); | |||
| 3053 | break; | |||
| 3054 | case DRW::dxfCode::INVISIBLE: | |||
| 3055 | visible = (reader->getInt32() & 1) == 0; | |||
| 3056 | break; | |||
| 3057 | case 420: | |||
| 3058 | color24 = reader->getInt32(); | |||
| 3059 | break; | |||
| 3060 | case 430: | |||
| 3061 | colorName = reader->getString(); | |||
| 3062 | break; | |||
| 3063 | case 67: | |||
| 3064 | { | |||
| 3065 | const int value = reader->getInt32(); | |||
| 3066 | if (value < DRW::ModelSpace || value > DRW::PaperSpace) | |||
| 3067 | return false; | |||
| 3068 | space = static_cast<DRW::Space>(value); | |||
| 3069 | } | |||
| 3070 | break; | |||
| 3071 | case 102: | |||
| 3072 | return parseDxfGroups(code, reader); | |||
| 3073 | case 284: | |||
| 3074 | { | |||
| 3075 | int value = 0; | |||
| 3076 | if (!readDxfIntInRange(reader, DRW::CastAndReceieveShadows, | |||
| 3077 | DRW::IgnoreShadows, value)) | |||
| 3078 | return false; | |||
| 3079 | shadow = static_cast<DRW::ShadowMode>(value); | |||
| 3080 | } | |||
| 3081 | break; | |||
| 3082 | case 347: | |||
| 3083 | material = static_cast<std::uint32_t>(reader->getHandleString()); | |||
| 3084 | break; | |||
| 3085 | case 348: | |||
| 3086 | fullVisualStyleHandle = reader->getHandleString(); | |||
| 3087 | break; | |||
| 3088 | case 360: | |||
| 3089 | xDictHandle = reader->getHandleString(); | |||
| 3090 | break; | |||
| 3091 | case DRW::dxfCode::PLOTSTYLE: | |||
| 3092 | plotStyle = reader->getHandleString(); | |||
| 3093 | break; | |||
| 3094 | case 440: | |||
| 3095 | transparency = reader->getInt32(); | |||
| 3096 | break; | |||
| 3097 | case 92: { | |||
| 3098 | // Proxy entity graphics byte count (ODA §20.4.95): 92 for R13–R2007. | |||
| 3099 | // Entities that repurpose 92 (for example MESH) handle it before this | |||
| 3100 | // base parser is reached. | |||
| 3101 | const std::int32_t value = reader->getInt32(); | |||
| 3102 | if (value < 0 | |||
| 3103 | || static_cast<std::uint32_t>(value) | |||
| 3104 | > DRW::kMaxDxfBinaryPayloadBytes) | |||
| 3105 | return false; | |||
| 3106 | numProxyGraph = value; | |||
| 3107 | proxyGraphics.clear(); | |||
| 3108 | break; | |||
| 3109 | } | |||
| 3110 | case 160: { | |||
| 3111 | // R2010+ uses a 64-bit DXF count (group 160), not group 92's 32-bit | |||
| 3112 | // storage. Keep the public legacy field bounded and representable. | |||
| 3113 | const std::int64_t value = reader->getInt64(); | |||
| 3114 | if (value < 0 | |||
| 3115 | || static_cast<std::uint64_t>(value) | |||
| 3116 | > DRW::kMaxDxfBinaryPayloadBytes) | |||
| 3117 | return false; | |||
| 3118 | numProxyGraph = static_cast<int>(value); | |||
| 3119 | proxyGraphics.clear(); | |||
| 3120 | break; | |||
| 3121 | } | |||
| 3122 | case 310: | |||
| 3123 | if (numProxyGraph != 0) { | |||
| 3124 | // Proxy graphics binary, hex-encoded across many ≤254-char chunks. | |||
| 3125 | const std::string& hex = reader->getString(); | |||
| 3126 | if (!appendHexBytesChecked( | |||
| 3127 | proxyGraphics, hex, | |||
| 3128 | std::min<std::size_t>( | |||
| 3129 | DRW::kMaxDxfBinaryPayloadBytes, | |||
| 3130 | static_cast<std::size_t>(numProxyGraph)))) | |||
| 3131 | return false; | |||
| 3132 | } | |||
| 3133 | break; | |||
| 3134 | case 1000: | |||
| 3135 | case 1001: | |||
| 3136 | case 1002: | |||
| 3137 | case 1003: | |||
| 3138 | case 1004: | |||
| 3139 | case 1005: | |||
| 3140 | if (extData.size() >= DRW_TableEntry::kMaxExtendedDataItems) | |||
| 3141 | return false; | |||
| 3142 | extData.push_back(std::make_shared<DRW_Variant>(code, | |||
| 3143 | reader->getString())); | |||
| 3144 | break; | |||
| 3145 | case 1010: | |||
| 3146 | case 1011: | |||
| 3147 | case 1012: | |||
| 3148 | case 1013: | |||
| 3149 | if (extData.size() >= DRW_TableEntry::kMaxExtendedDataItems) | |||
| 3150 | return false; | |||
| 3151 | curr = std::make_shared<DRW_Variant>( | |||
| 3152 | code, DRW_Coord(reader->getDouble(), 0.0, 0.0)); | |||
| 3153 | extData.push_back(curr); | |||
| 3154 | break; | |||
| 3155 | // Files repeat Y and Z after a point's Z (R12 ACAD_MATERIAL_MAPPER and | |||
| 3156 | // ASC_SEEDPOINT); a component with no open point is dropped. | |||
| 3157 | case 1020: | |||
| 3158 | case 1021: | |||
| 3159 | case 1022: | |||
| 3160 | case 1023: | |||
| 3161 | if (curr) | |||
| 3162 | curr->setCoordY(reader->getDouble()); | |||
| 3163 | break; | |||
| 3164 | case 1030: | |||
| 3165 | case 1031: | |||
| 3166 | case 1032: | |||
| 3167 | case 1033: | |||
| 3168 | if (curr) | |||
| 3169 | curr->setCoordZ(reader->getDouble()); | |||
| 3170 | curr.reset(); | |||
| 3171 | break; | |||
| 3172 | case 1040: | |||
| 3173 | case 1041: | |||
| 3174 | case 1042: | |||
| 3175 | if (extData.size() >= DRW_TableEntry::kMaxExtendedDataItems) | |||
| 3176 | return false; | |||
| 3177 | extData.push_back(std::make_shared<DRW_Variant>(code, | |||
| 3178 | reader->getDouble())); | |||
| 3179 | break; | |||
| 3180 | case 1070: | |||
| 3181 | case 1071: | |||
| 3182 | if (extData.size() >= DRW_TableEntry::kMaxExtendedDataItems) | |||
| 3183 | return false; | |||
| 3184 | extData.push_back(std::make_shared<DRW_Variant>(code, | |||
| 3185 | reader->getInt32())); | |||
| 3186 | break; | |||
| 3187 | default: | |||
| 3188 | break; | |||
| 3189 | } | |||
| 3190 | return true; | |||
| 3191 | } catch (...) { | |||
| 3192 | reset(); | |||
| 3193 | return false; | |||
| 3194 | } | |||
| 3195 | } | |||
| 3196 | ||||
| 3197 | //parses dxf 102 groups to read entity | |||
| 3198 | bool DRW_Entity::parseDxfGroups(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 3199 | if (appData.size() >= DRW::kMaxDxfApplicationGroups) | |||
| 3200 | return false; | |||
| 3201 | std::list<DRW_Variant> ls; | |||
| 3202 | DRW_Variant curr; | |||
| 3203 | std::string appName= reader->getString(); | |||
| 3204 | if (appName.size() <= 1 || appName.front() != '{') | |||
| 3205 | return false; | |||
| 3206 | ||||
| 3207 | const bool isReactors = appName == "{ACAD_REACTORS"; | |||
| 3208 | const bool isXDictionary = appName == "{ACAD_XDICTIONARY"; | |||
| 3209 | std::vector<std::uint32_t> parsedReactors; | |||
| 3210 | std::uint32_t parsedXDictionary = 0; | |||
| 3211 | ||||
| 3212 | curr.addString(code, appName.substr(1)); | |||
| 3213 | ls.push_back(curr); | |||
| 3214 | int depth = 1; | |||
| 3215 | int nextCode = 0; | |||
| 3216 | while (depth > 0 && reader->readRec(&nextCode)) { | |||
| 3217 | if (ls.size() >= DRW::kMaxDxfApplicationGroupPairs) | |||
| 3218 | return false; | |||
| 3219 | ||||
| 3220 | // A section/entity boundary before the matching 102 close would be | |||
| 3221 | // consumed irreversibly and leave the caller out of sync. | |||
| 3222 | if (nextCode == 0) | |||
| 3223 | return false; | |||
| 3224 | ||||
| 3225 | DRW_Variant value; | |||
| 3226 | if (nextCode == 102) { | |||
| 3227 | const std::string marker = reader->getString(); | |||
| 3228 | if (marker.empty() || (marker.front() == '{' && marker.size() == 1)) | |||
| 3229 | return false; | |||
| 3230 | if (marker.front() == '{') { | |||
| 3231 | if (++depth > DRW::kMaxDxfApplicationGroupNesting) | |||
| 3232 | return false; | |||
| 3233 | } else if (marker == "}") { | |||
| 3234 | --depth; | |||
| 3235 | } else { | |||
| 3236 | return false; | |||
| 3237 | } | |||
| 3238 | value.addString(nextCode, marker); | |||
| 3239 | } else if ((nextCode >= 320 && nextCode <= 369) | |||
| 3240 | || (nextCode >= 390 && nextCode <= 399) | |||
| 3241 | || nextCode == 480 || nextCode == 481 | |||
| 3242 | || nextCode == 1005) { | |||
| 3243 | const std::string rawHandle = reader->getString(); | |||
| 3244 | value.addString(nextCode, rawHandle); | |||
| 3245 | if (depth == 1 && isReactors && nextCode == 330) { | |||
| 3246 | const auto reactor = reader->getHandleString(); | |||
| 3247 | if (reactor != 0) { | |||
| 3248 | if (parsedReactors.size() >= dwgSafety::MaxReactorCount) | |||
| 3249 | return false; | |||
| 3250 | parsedReactors.push_back(static_cast<std::uint32_t>(reactor)); | |||
| 3251 | } | |||
| 3252 | } else if (depth == 1 && isXDictionary && nextCode == 360 | |||
| 3253 | && parsedXDictionary == 0) { | |||
| 3254 | parsedXDictionary = static_cast<std::uint32_t>( | |||
| 3255 | reader->getHandleString()); | |||
| 3256 | } | |||
| 3257 | } else { | |||
| 3258 | switch (reader->type) { | |||
| 3259 | case dxfReader::STRING: | |||
| 3260 | case dxfReader::BINARY: | |||
| 3261 | value.addString(nextCode, reader->getString()); | |||
| 3262 | break; | |||
| 3263 | case dxfReader::INT32: | |||
| 3264 | case dxfReader::BOOL: | |||
| 3265 | value.addInt(nextCode, reader->getInt32()); | |||
| 3266 | break; | |||
| 3267 | case dxfReader::INT64: | |||
| 3268 | value.addInt64(nextCode, static_cast<std::int64_t>(reader->getInt64())); | |||
| 3269 | break; | |||
| 3270 | case dxfReader::DOUBLE: | |||
| 3271 | value.addDouble(nextCode, reader->getDouble()); | |||
| 3272 | break; | |||
| 3273 | default: | |||
| 3274 | return false; | |||
| 3275 | } | |||
| 3276 | } | |||
| 3277 | ls.push_back(value); | |||
| 3278 | } | |||
| 3279 | ||||
| 3280 | if (depth != 0) | |||
| 3281 | return false; | |||
| 3282 | if (isReactors) | |||
| 3283 | reactorHandles = std::move(parsedReactors); | |||
| 3284 | if (isXDictionary && parsedXDictionary != 0) | |||
| 3285 | xDictHandle = parsedXDictionary; | |||
| 3286 | appData.push_back(std::move(ls)); | |||
| 3287 | return true; | |||
| 3288 | } | |||
| 3289 | ||||
| 3290 | bool DRW_Entity::parseDwg(DRW::Version version, dwgBuffer *buf, dwgBuffer* strBuf, std::uint32_t bs){ | |||
| 3291 | // This overload is also used by the two-stage common/handle tests and | |||
| 3292 | // callers; concrete record parsers own carrier reset so handle parsing can | |||
| 3293 | // remain transactional. | |||
| 3294 | if (buf == nullptr) | |||
| 3295 | return false; | |||
| 3296 | ||||
| 3297 | DRW_DBG("\n***************************** parsing entity *********************************************\n")DRW_dbg::dbg("\n***************************** parsing entity *********************************************\n" ); | |||
| 3298 | oType = buf->getObjType(version); | |||
| 3299 | if (!buf->isGood()) | |||
| 3300 | return false; | |||
| 3301 | DRW_DBG("Object type: ")DRW_dbg::dbg("Object type: "); DRW_DBG(oType)DRW_dbg::dbg(oType); DRW_DBG(", ")DRW_dbg::dbg(", "); DRW_DBGH(oType)DRW_dbg::dbgH(oType); | |||
| 3302 | ||||
| 3303 | if (version > DRW::AC1014 && version < DRW::AC1024) {//2000 & 2004 | |||
| 3304 | const std::uint64_t totalBits = static_cast<std::uint64_t>(buf->size()) * 8u; | |||
| 3305 | std::uint32_t parsedObjectSize = 0; | |||
| 3306 | if (!readBoundedRawLong32(*buf, totalBits, parsedObjectSize)) | |||
| 3307 | return false; | |||
| 3308 | objSize = parsedObjectSize; //RL 32bits object size in bits | |||
| 3309 | DRW_DBG(" Object size: ")DRW_dbg::dbg(" Object size: "); DRW_DBG(objSize)DRW_dbg::dbg(objSize); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 3310 | } | |||
| 3311 | if (version > DRW::AC1021) {//2010+ | |||
| 3312 | const std::uint64_t totalBits = static_cast<std::uint64_t>(buf->size()) * 8u; | |||
| 3313 | // Clamp: a corrupt bs > ms*8 would underflow objSize (unsigned) to a | |||
| 3314 | // huge value and drive strBuf->moveBitPos(objSize-1) past the buffer. | |||
| 3315 | if (totalBits > std::numeric_limits<std::uint32_t>::max() | |||
| 3316 | || bs > totalBits) | |||
| 3317 | return false; | |||
| 3318 | objSize = static_cast<std::uint32_t>(totalBits - bs); | |||
| 3319 | DRW_DBG(" Object size: ")DRW_dbg::dbg(" Object size: "); DRW_DBG(objSize)DRW_dbg::dbg(objSize); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 3320 | } | |||
| 3321 | ||||
| 3322 | if (strBuf != NULL__null && version > DRW::AC1018) {//2007+ | |||
| 3323 | if (!strBuf->seekR2007StringStream(objSize)) | |||
| 3324 | return false; | |||
| 3325 | DRW_DBG(" strBuf strbit pos 2007: ")DRW_dbg::dbg(" strBuf strbit pos 2007: "); DRW_DBG(strBuf->getPosition())DRW_dbg::dbg(strBuf->getPosition()); DRW_DBG(" strBuf bpos 2007: ")DRW_dbg::dbg(" strBuf bpos 2007: "); DRW_DBG(strBuf->getBitPos())DRW_dbg::dbg(strBuf->getBitPos()); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 3326 | DRW_DBG("strBuf start pos 2007: ")DRW_dbg::dbg("strBuf start pos 2007: "); DRW_DBG(strBuf->getPosition())DRW_dbg::dbg(strBuf->getPosition()); DRW_DBG(" strBuf bpos 2007: ")DRW_dbg::dbg(" strBuf bpos 2007: "); DRW_DBG(strBuf->getBitPos())DRW_dbg::dbg(strBuf->getBitPos()); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 3327 | } | |||
| 3328 | ||||
| 3329 | // R2007+ objSize includes the detached string stream and its footer. A | |||
| 3330 | // common entity prefix must stay in the data portion just like the | |||
| 3331 | // entity-specific readers below. Only a caller that supplies the real | |||
| 3332 | // modern string cursor can require the footer here; the null-cursor form | |||
| 3333 | // is retained for isolated common-prefix tests without object framing. | |||
| 3334 | std::uint64_t bodyEndBit = proxyEntityEndBit(*buf, objSize); | |||
| 3335 | if (version > DRW::AC1021 && strBuf != nullptr) { | |||
| 3336 | dwgBuffer stringBoundary = strBuf->forkIndependent(); | |||
| 3337 | if (!stringBoundary.seekR2007StringStream(objSize)) | |||
| 3338 | return false; | |||
| 3339 | bodyEndBit = currentDwgBit(&stringBoundary); | |||
| 3340 | } | |||
| 3341 | dwgDataEndBit = bodyEndBit; | |||
| 3342 | const auto bodyWithinBounds = [buf, &bodyEndBit]() { | |||
| 3343 | return currentDwgBit(buf) <= bodyEndBit; | |||
| 3344 | }; | |||
| 3345 | ||||
| 3346 | dwgHandle ho; | |||
| 3347 | if (!readBoundedDwgHandle(*buf, bodyEndBit, 0, false, ho)) | |||
| 3348 | return false; | |||
| 3349 | handle = ho.ref; | |||
| 3350 | DRW_DBG("Entity Handle: ")DRW_dbg::dbg("Entity Handle: "); DRW_DBGHL(ho.code, ho.size, ho.ref)DRW_dbg::dbgHL(ho.code, ho.size, ho.ref); | |||
| 3351 | // EED is a bounded, repeated chunk stream. Parse all chunks before | |||
| 3352 | // changing the entity so a malformed item cannot leak partial metadata. | |||
| 3353 | std::vector<DwgEedChunk> eedChunks; | |||
| 3354 | if (!readDwgEed(version, *buf, eedChunks, bodyEndBit)) | |||
| 3355 | return false; | |||
| 3356 | if (!bodyWithinBounds()) | |||
| 3357 | return false; | |||
| 3358 | std::vector<std::shared_ptr<DRW_Variant>> parsedExtData; | |||
| 3359 | std::vector<PendingHandleRef> parsedAppIdResolutions; | |||
| 3360 | std::vector<PendingHandleRef> parsedLayerRefResolutions; | |||
| 3361 | try { | |||
| 3362 | for (const DwgEedChunk& chunk : eedChunks) { | |||
| 3363 | const std::size_t appIndex = | |||
| 3364 | extData.size() + parsedExtData.size(); | |||
| 3365 | parsedExtData.push_back( | |||
| 3366 | std::make_shared<DRW_Variant>(1001, std::string{})); | |||
| 3367 | parsedAppIdResolutions.push_back({appIndex, chunk.appHandle}); | |||
| 3368 | for (const DRW_Variant& item : chunk.items) | |||
| 3369 | parsedExtData.push_back(std::make_shared<DRW_Variant>(item)); | |||
| 3370 | for (const DwgEedHandleRef& ref : chunk.layerRefs) { | |||
| 3371 | parsedLayerRefResolutions.push_back( | |||
| 3372 | {appIndex + 1 + ref.itemIndex, ref.handleRef}); | |||
| 3373 | } | |||
| 3374 | } | |||
| 3375 | } catch (...) { | |||
| 3376 | return false; | |||
| 3377 | } | |||
| 3378 | DRW_DBG(" [bidi-debug pre-graphFlag bufpos=")DRW_dbg::dbg(" [bidi-debug pre-graphFlag bufpos="); DRW_DBG(buf->getPosition())DRW_dbg::dbg(buf->getPosition()); DRW_DBG(" bitpos=")DRW_dbg::dbg(" bitpos="); DRW_DBG(buf->getBitPos())DRW_dbg::dbg(buf->getBitPos()); DRW_DBG("]\n")DRW_dbg::dbg("]\n"); | |||
| 3379 | bool graphFlag = false; | |||
| 3380 | if (!readBoundedBit(*buf, bodyEndBit, graphFlag)) | |||
| 3381 | return false; | |||
| 3382 | DRW_DBG(" graphFlag: ")DRW_dbg::dbg(" graphFlag: "); DRW_DBG(graphFlag)DRW_dbg::dbg(graphFlag); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 3383 | if (!bodyWithinBounds()) | |||
| 3384 | return false; | |||
| 3385 | if (graphFlag) { | |||
| 3386 | DRW_DBG(" [bidi-debug pre-graphSize bufpos=")DRW_dbg::dbg(" [bidi-debug pre-graphSize bufpos="); DRW_DBG(buf->getPosition())DRW_dbg::dbg(buf->getPosition()); DRW_DBG(" bitpos=")DRW_dbg::dbg(" bitpos="); DRW_DBG(buf->getBitPos())DRW_dbg::dbg(buf->getBitPos()); DRW_DBG("]\n")DRW_dbg::dbg("]\n"); | |||
| 3387 | std::uint64_t graphDataSize = 0; | |||
| 3388 | if (version >= DRW::AC1024) { | |||
| 3389 | if (!readBoundedBitLongLong(*buf, bodyEndBit, graphDataSize)) | |||
| 3390 | return false; | |||
| 3391 | } else { | |||
| 3392 | std::uint32_t parsedGraphDataSize = 0; | |||
| 3393 | if (!readBoundedRawLong32(*buf, bodyEndBit, | |||
| 3394 | parsedGraphDataSize)) | |||
| 3395 | return false; | |||
| 3396 | graphDataSize = parsedGraphDataSize; | |||
| 3397 | } | |||
| 3398 | DRW_DBG("graphData in bytes: ")DRW_dbg::dbg("graphData in bytes: "); DRW_DBG(static_cast<std::uint32_t>(graphDataSize))DRW_dbg::dbg(static_cast<std::uint32_t>(graphDataSize)); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 3399 | if (!bodyWithinBounds()) | |||
| 3400 | return false; | |||
| 3401 | const std::uint64_t maxMoveBytes = static_cast<std::uint64_t>(std::numeric_limits<std::int32_t>::max() / 8); | |||
| 3402 | const std::uint64_t currentBit = currentDwgBit(buf); | |||
| 3403 | std::uint64_t graphBits = 0; | |||
| 3404 | if (!dwgSafety::multiply(graphDataSize, 8, graphBits) | |||
| 3405 | || currentBit > bodyEndBit | |||
| 3406 | || graphBits > bodyEndBit - currentBit | |||
| 3407 | || graphDataSize > static_cast<std::uint64_t>(buf->numRemainingBytes()) | |||
| 3408 | || graphDataSize > maxMoveBytes) { | |||
| 3409 | DRW_DBG("graphData size outside object body\n")DRW_dbg::dbg("graphData size outside object body\n"); | |||
| 3410 | return false; | |||
| 3411 | } | |||
| 3412 | // Capture the proxy-graphics byte stream instead of skipping it. These | |||
| 3413 | // are cached drawable primitives (lines/arcs/polylines/text) that any | |||
| 3414 | // reader can render for proxy/custom entities (STDPART2D, AEC_*, tables) | |||
| 3415 | // — previously discarded via moveBitPos, leaving proxyGraphics empty. | |||
| 3416 | // dwgBuffer::getBytes is bit-aware (reconstructs each byte at a non-zero | |||
| 3417 | // bitPos), so it lands at the exact same position moveBitPos(8N) did. | |||
| 3418 | // (write-review #32 / read-coverage gap #1) | |||
| 3419 | if (graphDataSize > 0) { | |||
| 3420 | if (!DRW::resize(proxyGraphics, static_cast<int>(graphDataSize))) | |||
| 3421 | return false; | |||
| 3422 | if (!readBoundedBytes( | |||
| 3423 | *buf, bodyEndBit, | |||
| 3424 | reinterpret_cast<std::uint8_t*>(&proxyGraphics[0]), | |||
| 3425 | static_cast<std::size_t>(graphDataSize))) | |||
| 3426 | return false; | |||
| 3427 | numProxyGraph = static_cast<int>(graphDataSize); | |||
| 3428 | } | |||
| 3429 | } | |||
| 3430 | if (version < DRW::AC1015) {//14- | |||
| 3431 | std::uint32_t parsedObjectSize = 0; | |||
| 3432 | if (!readBoundedRawLong32(*buf, proxyEntityEndBit(*buf, 0), | |||
| 3433 | parsedObjectSize)) | |||
| 3434 | return false; | |||
| 3435 | objSize = parsedObjectSize; //RL 32bits object size in bits | |||
| 3436 | DRW_DBG(" Object size in bits: ")DRW_dbg::dbg(" Object size in bits: "); DRW_DBG(objSize)DRW_dbg::dbg(objSize); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 3437 | bodyEndBit = proxyEntityEndBit(*buf, objSize); | |||
| 3438 | } | |||
| 3439 | ||||
| 3440 | std::uint8_t entmode = 0; | |||
| 3441 | if (!readBounded2Bits(*buf, bodyEndBit, entmode)) | |||
| 3442 | return false; | |||
| 3443 | if (entmode == 0) | |||
| 3444 | ownerHandle= true; | |||
| 3445 | // entmode = 2; | |||
| 3446 | else if(entmode ==2) | |||
| 3447 | entmode = 0; | |||
| 3448 | space = (DRW::Space)entmode; //RLZ verify cast values | |||
| 3449 | DRW_DBG("entmode: ")DRW_dbg::dbg("entmode: "); DRW_DBG(entmode)DRW_dbg::dbg(entmode); | |||
| 3450 | if (!readBoundedBitLong(*buf, bodyEndBit, numReactors)) | |||
| 3451 | return false; //BL per spec §20.4.1 | |||
| 3452 | DRW_DBG(", numReactors: ")DRW_dbg::dbg(", numReactors: "); DRW_DBG(numReactors)DRW_dbg::dbg(numReactors); | |||
| 3453 | if (!buf->isGood() || !dwgSafety::validReactorCount(numReactors)) | |||
| 3454 | return false; | |||
| 3455 | ||||
| 3456 | if (version < DRW::AC1015) {//14- | |||
| 3457 | bool isByLayer = false; | |||
| 3458 | if (!readBoundedBit(*buf, bodyEndBit, isByLayer)) | |||
| 3459 | return false; | |||
| 3460 | if (isByLayer) {//is bylayer line type | |||
| 3461 | lineType = "BYLAYER"; | |||
| 3462 | ltFlags = 0; | |||
| 3463 | } else { | |||
| 3464 | lineType = ""; | |||
| 3465 | ltFlags = 3; | |||
| 3466 | } | |||
| 3467 | DRW_DBG(" lineType: ")DRW_dbg::dbg(" lineType: "); DRW_DBG(lineType.c_str())DRW_dbg::dbg(lineType.c_str()); | |||
| 3468 | DRW_DBG(" ltFlags: ")DRW_dbg::dbg(" ltFlags: "); DRW_DBG(ltFlags)DRW_dbg::dbg(ltFlags); | |||
| 3469 | } | |||
| 3470 | if (version > DRW::AC1015) {//2004+ | |||
| 3471 | bool xDict = false; | |||
| 3472 | if (!readBoundedBit(*buf, bodyEndBit, xDict)) | |||
| 3473 | return false; | |||
| 3474 | xDictFlag = xDict; | |||
| 3475 | DRW_DBG(" xDictFlag: ")DRW_dbg::dbg(" xDictFlag: "); DRW_DBG(xDictFlag)DRW_dbg::dbg(xDictFlag); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 3476 | } | |||
| 3477 | ||||
| 3478 | // libreDWG common_entity_data.spec — the bit at this stream position has two | |||
| 3479 | // disjoint meanings by version: | |||
| 3480 | // * R13..R2002 (version < AC1018): `nolinks` (B). 1 = no prev/next handles | |||
| 3481 | // in the handle section; 0 = read prev+next at parseDwgEntHandle. | |||
| 3482 | // * R2004..R2010 (AC1018..AC1024): NO bit in the stream — reader forces | |||
| 3483 | // haveNextLinks=1 to skip the prev/next handle reads. | |||
| 3484 | // * R2013+ (version > AC1024): `has_ds_data` (B). 1 = inline ACIS SAB | |||
| 3485 | // datastore present. Stored separately because it gates SAB handling, | |||
| 3486 | // not prev/next links (which are already version<AC1018 gated). | |||
| 3487 | // Total bit consumption is unchanged for every version. | |||
| 3488 | if (version < DRW::AC1018) { | |||
| 3489 | bool parsedHaveNextLinks = false; | |||
| 3490 | if (!readBoundedBit(*buf, bodyEndBit, parsedHaveNextLinks)) | |||
| 3491 | return false; //nolinks //B | |||
| 3492 | haveNextLinks = parsedHaveNextLinks ? 1 : 0; | |||
| 3493 | DRW_DBG(", haveNextLinks (0 yes, 1 prev next): ")DRW_dbg::dbg(", haveNextLinks (0 yes, 1 prev next): "); DRW_DBG(haveNextLinks)DRW_dbg::dbg(haveNextLinks); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 3494 | } else { | |||
| 3495 | haveNextLinks = 1; //AC1018+: not in stream, force 1 (no prev/next) | |||
| 3496 | DRW_DBG(", haveNextLinks (forced): ")DRW_dbg::dbg(", haveNextLinks (forced): "); DRW_DBG(haveNextLinks)DRW_dbg::dbg(haveNextLinks); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 3497 | } | |||
| 3498 | if (version > DRW::AC1024) { | |||
| 3499 | bool parsedHasDsData = false; | |||
| 3500 | if (!readBoundedBit(*buf, bodyEndBit, parsedHasDsData)) | |||
| 3501 | return false; //has_ds_data //B (R2013+) | |||
| 3502 | hasDsData = parsedHasDsData ? 1 : 0; | |||
| 3503 | DRW_DBG(", hasDsData (R2013+): ")DRW_dbg::dbg(", hasDsData (R2013+): "); DRW_DBG(hasDsData)DRW_dbg::dbg(hasDsData); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 3504 | } | |||
| 3505 | //ENC color | |||
| 3506 | std::uint32_t parsedColor = 0; | |||
| 3507 | if (!readBoundedEnColor(*buf, bodyEndBit, version, parsedColor)) | |||
| 3508 | return false; //BS or CMC //ok for R14 or negate | |||
| 3509 | color = static_cast<int>(parsedColor); | |||
| 3510 | // Capture the AcDbColor side-channel before the common handle stream. | |||
| 3511 | // The handle follows owner/reactors/xdictionary and precedes layer in the | |||
| 3512 | // R2004+ common entity handle data. | |||
| 3513 | hasAcDbColorH = buf->lastEnColorHadDbColorRef; | |||
| 3514 | // libreDWG common_entity_data.spec:432-453 — ENC alpha_raw (DXF code | |||
| 3515 | // 440) is encoded as (alpha_type<<24) | alpha. Stored verbatim; the | |||
| 3516 | // filter (RS_FilterDXFRW::setEntityAttributes) decodes alpha_type==3 | |||
| 3517 | // into a per-entity pen alpha, otherwise inherits from layer/block. | |||
| 3518 | if (buf->lastEnColorAlphaRaw != 0) { | |||
| 3519 | transparency = static_cast<int>(buf->lastEnColorAlphaRaw); | |||
| 3520 | } | |||
| 3521 | // libreDWG common_entity_data.spec:468-475 — inline TV name/book name | |||
| 3522 | // (flags 0x41/0x42) override any dbColorMap-resolved name. Captured | |||
| 3523 | // immediately; entryParse will skip the override only if colorName is | |||
| 3524 | // already populated here. | |||
| 3525 | if (!buf->lastEnColorName.empty()) { | |||
| 3526 | colorName = buf->lastEnColorBookName.empty() | |||
| 3527 | ? buf->lastEnColorName | |||
| 3528 | : (buf->lastEnColorBookName + "$" + buf->lastEnColorName); | |||
| 3529 | } | |||
| 3530 | color24 = buf->lastEnColorRgb; | |||
| 3531 | if (!readBoundedBitDouble(*buf, bodyEndBit, ltypeScale)) | |||
| 3532 | return false; //BD | |||
| 3533 | DRW_DBG(" entity color: ")DRW_dbg::dbg(" entity color: "); DRW_DBG(color)DRW_dbg::dbg(color); | |||
| 3534 | DRW_DBG(" ltScale: ")DRW_dbg::dbg(" ltScale: "); DRW_DBG(ltypeScale)DRW_dbg::dbg(ltypeScale); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 3535 | if (version > DRW::AC1014) {//2000+ — §19.4.1: linetype-flags BB then plot-flags BB | |||
| 3536 | std::uint8_t parsedLtFlags = 0; | |||
| 3537 | if (!readBounded2Bits(*buf, bodyEndBit, parsedLtFlags)) | |||
| 3538 | return false; //BB | |||
| 3539 | ltFlags = parsedLtFlags; | |||
| 3540 | if (ltFlags == 0) lineType = "BYLAYER"; | |||
| 3541 | else if (ltFlags == 1) lineType = "BYBLOCK"; | |||
| 3542 | else if (ltFlags == 2) lineType = "CONTINUOUS"; | |||
| 3543 | else lineType = ""; //3 → handle at end | |||
| 3544 | DRW_DBG("ltFlags: ")DRW_dbg::dbg("ltFlags: "); DRW_DBG(ltFlags)DRW_dbg::dbg(ltFlags); | |||
| 3545 | DRW_DBG(" lineType: ")DRW_dbg::dbg(" lineType: "); DRW_DBG(lineType.c_str())DRW_dbg::dbg(lineType.c_str()); | |||
| 3546 | ||||
| 3547 | std::uint8_t parsedPlotFlags = 0; | |||
| 3548 | if (!readBounded2Bits(*buf, bodyEndBit, parsedPlotFlags)) | |||
| 3549 | return false; //BB | |||
| 3550 | plotFlags = parsedPlotFlags; | |||
| 3551 | DRW_DBG(", plotFlags: ")DRW_dbg::dbg(", plotFlags: "); DRW_DBG(plotFlags)DRW_dbg::dbg(plotFlags); | |||
| 3552 | } | |||
| 3553 | if (version > DRW::AC1018) {//2007+ | |||
| 3554 | std::uint8_t parsedMaterialFlag = 0; | |||
| 3555 | if (!readBounded2Bits(*buf, bodyEndBit, parsedMaterialFlag)) | |||
| 3556 | return false; //BB | |||
| 3557 | materialFlag = parsedMaterialFlag; | |||
| 3558 | DRW_DBG("materialFlag: ")DRW_dbg::dbg("materialFlag: "); DRW_DBG(materialFlag)DRW_dbg::dbg(materialFlag); | |||
| 3559 | std::uint8_t parsedShadowFlag = 0; | |||
| 3560 | if (!readBoundedRawChar8(*buf, bodyEndBit, parsedShadowFlag)) | |||
| 3561 | return false; //RC, low 2 bits is shadow mode 0..3 | |||
| 3562 | shadowFlag = parsedShadowFlag; | |||
| 3563 | DRW_DBG("shadowFlag: ")DRW_dbg::dbg("shadowFlag: "); DRW_DBG(shadowFlag)DRW_dbg::dbg(shadowFlag); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 3564 | shadow = static_cast<DRW::ShadowMode>(shadowFlag & 0x3); | |||
| 3565 | } | |||
| 3566 | if (version > DRW::AC1021) {//2010+ — §19.4.1: three single-bit flags | |||
| 3567 | // Ground-truth: libreDWG common_entity_data.spec lines 523-528 | |||
| 3568 | // and ODA spec v5.4.1 §19.4.1 both define three FIELD_B (single bit) | |||
| 3569 | // flags here, one each for full/face/edge visual style. Total bit | |||
| 3570 | // consumption (3 bits) is identical to the historical BB+B shape; | |||
| 3571 | // only the semantics differ. The corresponding handles are read | |||
| 3572 | // conditionally in parseDwgEntHandle after the plotstyle handle. | |||
| 3573 | bool parsedHasFullVisualStyle = false; | |||
| 3574 | bool parsedHasFaceVisualStyle = false; | |||
| 3575 | bool parsedHasEdgeVisualStyle = false; | |||
| 3576 | if (!readBoundedBit(*buf, bodyEndBit, parsedHasFullVisualStyle) | |||
| 3577 | || !readBoundedBit(*buf, bodyEndBit, parsedHasFaceVisualStyle) | |||
| 3578 | || !readBoundedBit(*buf, bodyEndBit, parsedHasEdgeVisualStyle)) | |||
| 3579 | return false; //B | |||
| 3580 | hasFullVisualStyle = parsedHasFullVisualStyle ? 1 : 0; | |||
| 3581 | hasFaceVisualStyle = parsedHasFaceVisualStyle ? 1 : 0; | |||
| 3582 | hasEdgeVisualStyle = parsedHasEdgeVisualStyle ? 1 : 0; | |||
| 3583 | DRW_DBG("hasFull/Face/Edge VisualStyle: ")DRW_dbg::dbg("hasFull/Face/Edge VisualStyle: "); | |||
| 3584 | DRW_DBG(hasFullVisualStyle)DRW_dbg::dbg(hasFullVisualStyle); DRW_DBG(" ")DRW_dbg::dbg(" "); | |||
| 3585 | DRW_DBG(hasFaceVisualStyle)DRW_dbg::dbg(hasFaceVisualStyle); DRW_DBG(" ")DRW_dbg::dbg(" "); | |||
| 3586 | DRW_DBG(hasEdgeVisualStyle)DRW_dbg::dbg(hasEdgeVisualStyle); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 3587 | } | |||
| 3588 | std::uint16_t parsedInvisibleFlag = 0; | |||
| 3589 | if (!readBoundedBitShort(*buf, bodyEndBit, parsedInvisibleFlag)) | |||
| 3590 | return false; //BS | |||
| 3591 | const std::int16_t invisibleFlag = | |||
| 3592 | static_cast<std::int16_t>(parsedInvisibleFlag); | |||
| 3593 | DRW_DBG(" invisibleFlag: ")DRW_dbg::dbg(" invisibleFlag: "); DRW_DBG(invisibleFlag)DRW_dbg::dbg(invisibleFlag); | |||
| 3594 | // DXF group 60: bit 0 = invisible (1) / visible (0). libreDWG | |||
| 3595 | // common_entity_data.spec masks bit 0 only (`invisible & 1`) and ignores | |||
| 3596 | // the higher bits, so use the same mask rather than `== 0`. Paired with | |||
| 3597 | // the encode emit below. | |||
| 3598 | visible = ((invisibleFlag & 1) == 0); | |||
| 3599 | if (version > DRW::AC1014) {//2000+ | |||
| 3600 | std::uint8_t parsedLineWeight = 0; | |||
| 3601 | if (!readBoundedRawChar8(*buf, bodyEndBit, parsedLineWeight)) | |||
| 3602 | return false; //RC | |||
| 3603 | lWeight = DRW_LW_Conv::dwgInt2lineWidth(parsedLineWeight); | |||
| 3604 | DRW_DBG(" lwFlag (lWeight): ")DRW_dbg::dbg(" lwFlag (lWeight): "); DRW_DBG(lWeight)DRW_dbg::dbg(lWeight); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 3605 | } | |||
| 3606 | //Only in blocks ???????? | |||
| 3607 | // if (version > DRW::AC1018) {//2007+ | |||
| 3608 | // std::uint8_t unk = buf->getBit(); | |||
| 3609 | // DRW_DBG("unknown bit: "); DRW_DBG(unk); DRW_DBG("\n"); | |||
| 3610 | // } | |||
| 3611 | if (!buf->isGood() || !bodyWithinBounds()) | |||
| 3612 | return false; | |||
| 3613 | ||||
| 3614 | const std::size_t oldExtDataSize = extData.size(); | |||
| 3615 | const std::size_t oldAppResolutionSize = | |||
| 3616 | pendingAppIdResolutions.size(); | |||
| 3617 | const std::size_t oldLayerResolutionSize = | |||
| 3618 | pendingLayerRefResolutions.size(); | |||
| 3619 | const auto rollbackEed = [this, oldExtDataSize, | |||
| 3620 | oldAppResolutionSize, oldLayerResolutionSize]() { | |||
| 3621 | extData.resize(oldExtDataSize); | |||
| 3622 | pendingAppIdResolutions.resize(oldAppResolutionSize); | |||
| 3623 | pendingLayerRefResolutions.resize(oldLayerResolutionSize); | |||
| 3624 | }; | |||
| 3625 | if (parsedExtData.size() > DRW_TableEntry::kMaxExtendedDataItems | |||
| 3626 | || extData.size() > DRW_TableEntry::kMaxExtendedDataItems | |||
| 3627 | || parsedExtData.size() | |||
| 3628 | > DRW_TableEntry::kMaxExtendedDataItems - extData.size()) | |||
| 3629 | return false; | |||
| 3630 | try { | |||
| 3631 | extData.insert(extData.end(), parsedExtData.begin(), | |||
| 3632 | parsedExtData.end()); | |||
| 3633 | pendingAppIdResolutions.insert( | |||
| 3634 | pendingAppIdResolutions.end(), parsedAppIdResolutions.begin(), | |||
| 3635 | parsedAppIdResolutions.end()); | |||
| 3636 | pendingLayerRefResolutions.insert( | |||
| 3637 | pendingLayerRefResolutions.end(), | |||
| 3638 | parsedLayerRefResolutions.begin(), parsedLayerRefResolutions.end()); | |||
| 3639 | } catch (...) { | |||
| 3640 | rollbackEed(); | |||
| 3641 | return false; | |||
| 3642 | } | |||
| 3643 | return true; | |||
| 3644 | } | |||
| 3645 | ||||
| 3646 | bool DRW_Entity::parseDwgEntHandle( | |||
| 3647 | DRW::Version version, dwgBuffer *buf, bool resetHandleStream, | |||
| 3648 | std::uint64_t handleEndBit){ | |||
| 3649 | if (buf == nullptr || !buf->isGood() | |||
| 3650 | || !dwgSafety::validReactorCount(numReactors)) | |||
| 3651 | return false; | |||
| 3652 | if (resetHandleStream && version > DRW::AC1018) {//2007+ skip string area | |||
| 3653 | if (!buf->setPosition(objSize >> 3)) | |||
| 3654 | return false; | |||
| 3655 | buf->setBitPos(objSize & 7); | |||
| 3656 | if (!buf->isGood()) | |||
| 3657 | return false; | |||
| 3658 | } | |||
| 3659 | if (handleEndBit != std::numeric_limits<std::uint64_t>::max() | |||
| 3660 | && currentDwgBit(buf) > handleEndBit) | |||
| 3661 | return false; | |||
| 3662 | ||||
| 3663 | std::uint32_t newAcDbColorHandle = acDbColorHandle; | |||
| 3664 | std::uint32_t newParentHandle = ownerHandle ? parentHandle : DRW::NoHandle; | |||
| 3665 | std::vector<std::uint32_t> newReactorHandles; | |||
| 3666 | const bool hasXDictionary = version <= DRW::AC1015 || xDictFlag != 1; | |||
| 3667 | std::uint32_t newXDictHandle = hasXDictionary ? xDictHandle : 0; | |||
| 3668 | dwgHandle newLayerH = layerH; | |||
| 3669 | dwgHandle newLTypeH = lTypeH; | |||
| 3670 | std::uint32_t newNextEntLink = nextEntLink; | |||
| 3671 | std::uint32_t newPrevEntLink = prevEntLink; | |||
| 3672 | const DRW::ShadowMode newShadow = version > DRW::AC1018 | |||
| 3673 | ? shadow : DRW::CastAndReceieveShadows; | |||
| 3674 | std::uint32_t newMaterial = materialFlag == 3 ? material | |||
| 3675 | : DRW::MaterialByLayer; | |||
| 3676 | int newPlotStyle = plotFlags == 3 ? plotStyle | |||
| 3677 | : DRW::DefaultPlotStyle; | |||
| 3678 | std::uint32_t newShadowHandle = shadowFlag == 3 ? shadowHandle : 0; | |||
| 3679 | std::uint32_t newFullVisualStyleHandle = hasFullVisualStyle | |||
| 3680 | ? fullVisualStyleHandle : 0; | |||
| 3681 | std::uint32_t newFaceVisualStyleHandle = hasFaceVisualStyle | |||
| 3682 | ? faceVisualStyleHandle : 0; | |||
| 3683 | std::uint32_t newEdgeVisualStyleHandle = hasEdgeVisualStyle | |||
| 3684 | ? edgeVisualStyleHandle : 0; | |||
| 3685 | if (version <= DRW::AC1018) { | |||
| 3686 | newMaterial = DRW::MaterialByLayer; | |||
| 3687 | newShadowHandle = 0; | |||
| 3688 | } | |||
| 3689 | if (version <= DRW::AC1021) { | |||
| 3690 | newFullVisualStyleHandle = 0; | |||
| 3691 | newFaceVisualStyleHandle = 0; | |||
| 3692 | newEdgeVisualStyleHandle = 0; | |||
| 3693 | } | |||
| 3694 | auto readOffsetHandle = [&](dwgHandle& out) { | |||
| 3695 | return handleEndBit == std::numeric_limits<std::uint64_t>::max() | |||
| 3696 | ? readDwgHandleChecked(*buf, handle, true, out) | |||
| 3697 | : readBoundedDwgHandle(*buf, handleEndBit, handle, true, out); | |||
| 3698 | }; | |||
| 3699 | auto readRawHandle = [&](dwgHandle& out) { | |||
| 3700 | return handleEndBit == std::numeric_limits<std::uint64_t>::max() | |||
| 3701 | ? readDwgHandleChecked(*buf, handle, false, out) | |||
| 3702 | : readBoundedDwgHandle(*buf, handleEndBit, handle, false, out); | |||
| 3703 | }; | |||
| 3704 | auto readHandleList = [&]() { | |||
| 3705 | if (handleEndBit == std::numeric_limits<std::uint64_t>::max()) | |||
| 3706 | return readDwgHandleList(*buf, handle, numReactors, false, | |||
| 3707 | &newReactorHandles); | |||
| 3708 | if (!dwgSafety::validReactorCount(numReactors)) | |||
| 3709 | return false; | |||
| 3710 | std::vector<std::uint32_t> parsed; | |||
| 3711 | if (!DRW::reserve(parsed, numReactors)) | |||
| 3712 | return false; | |||
| 3713 | for (std::int32_t i = 0; i < numReactors; ++i) { | |||
| 3714 | dwgHandle reactor; | |||
| 3715 | if (!readBoundedDwgHandle(*buf, handleEndBit, handle, false, | |||
| 3716 | reactor)) | |||
| 3717 | return false; | |||
| 3718 | parsed.push_back(reactor.ref); | |||
| 3719 | } | |||
| 3720 | newReactorHandles = std::move(parsed); | |||
| 3721 | return true; | |||
| 3722 | }; | |||
| 3723 | ||||
| 3724 | if(ownerHandle){//entity are in block or in a polyline | |||
| 3725 | dwgHandle ownerH; | |||
| 3726 | if (!readOffsetHandle(ownerH)) | |||
| 3727 | return false; | |||
| 3728 | DRW_DBG("owner (parent) Handle: ")DRW_dbg::dbg("owner (parent) Handle: "); DRW_DBGHL(ownerH.code, ownerH.size, ownerH.ref)DRW_dbg::dbgHL(ownerH.code, ownerH.size, ownerH.ref); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 3729 | DRW_DBG(" Remaining bytes: ")DRW_dbg::dbg(" Remaining bytes: "); DRW_DBG(buf->numRemainingBytes())DRW_dbg::dbg(buf->numRemainingBytes()); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 3730 | newParentHandle = ownerH.ref; | |||
| 3731 | DRW_DBG("Block (parent) Handle: ")DRW_dbg::dbg("Block (parent) Handle: "); DRW_DBGHL(ownerH.code, ownerH.size, newParentHandle)DRW_dbg::dbgHL(ownerH.code, ownerH.size, newParentHandle); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 3732 | } else | |||
| 3733 | DRW_DBG("NO Block (parent) Handle\n")DRW_dbg::dbg("NO Block (parent) Handle\n"); | |||
| 3734 | ||||
| 3735 | DRW_DBG("\n Remaining bytes: ")DRW_dbg::dbg("\n Remaining bytes: "); DRW_DBG(buf->numRemainingBytes())DRW_dbg::dbg(buf->numRemainingBytes()); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 3736 | if (!readHandleList()) | |||
| 3737 | return false; | |||
| 3738 | if (xDictFlag !=1){//linetype in 2004 seems not have XDicObjH or NULL handle | |||
| 3739 | dwgHandle XDicObjH; | |||
| 3740 | if (!readRawHandle(XDicObjH)) | |||
| 3741 | return false; | |||
| 3742 | newXDictHandle = XDicObjH.ref; // 2a.2: persist xdict | |||
| 3743 | DRW_DBG(" XDicObj control Handle: ")DRW_dbg::dbg(" XDicObj control Handle: "); DRW_DBGHL(XDicObjH.code, XDicObjH.size, XDicObjH.ref)DRW_dbg::dbgHL(XDicObjH.code, XDicObjH.size, XDicObjH.ref); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 3744 | } | |||
| 3745 | DRW_DBG("Remaining bytes: ")DRW_dbg::dbg("Remaining bytes: "); DRW_DBG(buf->numRemainingBytes())DRW_dbg::dbg(buf->numRemainingBytes()); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 3746 | ||||
| 3747 | // ENC's optional AcDbColor reference follows the common owner, reactor, | |||
| 3748 | // and xdictionary handles in R2004+ files. The dwgReader resolves this | |||
| 3749 | // handle against dbColorMap after parsing the complete entity. | |||
| 3750 | if (hasAcDbColorH && version > DRW::AC1015) { | |||
| 3751 | dwgHandle dbcH; | |||
| 3752 | if (!readOffsetHandle(dbcH)) | |||
| 3753 | return false; | |||
| 3754 | newAcDbColorHandle = dbcH.ref; | |||
| 3755 | DRW_DBG(" AcDbColor Handle: ")DRW_dbg::dbg(" AcDbColor Handle: "); | |||
| 3756 | DRW_DBGHL(dbcH.code, dbcH.size, dbcH.ref)DRW_dbg::dbgHL(dbcH.code, dbcH.size, dbcH.ref); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 3757 | } | |||
| 3758 | ||||
| 3759 | if (version < DRW::AC1015) {//R14- | |||
| 3760 | //layer handle | |||
| 3761 | if (!readOffsetHandle(newLayerH)) | |||
| 3762 | return false; | |||
| 3763 | DRW_DBG(" layer Handle: ")DRW_dbg::dbg(" layer Handle: "); DRW_DBGHL(newLayerH.code, newLayerH.size, newLayerH.ref)DRW_dbg::dbgHL(newLayerH.code, newLayerH.size, newLayerH.ref); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 3764 | DRW_DBG(" Remaining bytes: ")DRW_dbg::dbg(" Remaining bytes: "); DRW_DBG(buf->numRemainingBytes())DRW_dbg::dbg(buf->numRemainingBytes()); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 3765 | //lineType handle | |||
| 3766 | if(ltFlags == 3){ | |||
| 3767 | if (!readOffsetHandle(newLTypeH)) | |||
| 3768 | return false; | |||
| 3769 | DRW_DBG("linetype Handle: ")DRW_dbg::dbg("linetype Handle: "); DRW_DBGHL(newLTypeH.code, newLTypeH.size, newLTypeH.ref)DRW_dbg::dbgHL(newLTypeH.code, newLTypeH.size, newLTypeH.ref); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 3770 | DRW_DBG(" Remaining bytes: ")DRW_dbg::dbg(" Remaining bytes: "); DRW_DBG(buf->numRemainingBytes())DRW_dbg::dbg(buf->numRemainingBytes()); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 3771 | } | |||
| 3772 | } | |||
| 3773 | if (version < DRW::AC1018) {//2000+ | |||
| 3774 | if (haveNextLinks == 0) { | |||
| 3775 | dwgHandle nextLinkH; | |||
| 3776 | if (!readOffsetHandle(nextLinkH)) | |||
| 3777 | return false; | |||
| 3778 | DRW_DBG(" prev nextLinkers Handle: ")DRW_dbg::dbg(" prev nextLinkers Handle: "); DRW_DBGHL(nextLinkH.code, nextLinkH.size, nextLinkH.ref)DRW_dbg::dbgHL(nextLinkH.code, nextLinkH.size, nextLinkH.ref); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 3779 | DRW_DBG("\n Remaining bytes: ")DRW_dbg::dbg("\n Remaining bytes: "); DRW_DBG(buf->numRemainingBytes())DRW_dbg::dbg(buf->numRemainingBytes()); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 3780 | const std::uint32_t prevLink = nextLinkH.ref; | |||
| 3781 | if (!readOffsetHandle(nextLinkH)) | |||
| 3782 | return false; | |||
| 3783 | DRW_DBG(" next nextLinkers Handle: ")DRW_dbg::dbg(" next nextLinkers Handle: "); DRW_DBGHL(nextLinkH.code, nextLinkH.size, nextLinkH.ref)DRW_dbg::dbgHL(nextLinkH.code, nextLinkH.size, nextLinkH.ref); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 3784 | DRW_DBG("\n Remaining bytes: ")DRW_dbg::dbg("\n Remaining bytes: "); DRW_DBG(buf->numRemainingBytes())DRW_dbg::dbg(buf->numRemainingBytes()); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 3785 | newPrevEntLink = prevLink; | |||
| 3786 | newNextEntLink = nextLinkH.ref; | |||
| 3787 | } else { | |||
| 3788 | if (handle == 0 || handle == std::numeric_limits<std::uint32_t>::max()) | |||
| 3789 | return false; | |||
| 3790 | newNextEntLink = handle + 1; | |||
| 3791 | newPrevEntLink = handle - 1; | |||
| 3792 | } | |||
| 3793 | } | |||
| 3794 | if (version > DRW::AC1015) {//2004+ | |||
| 3795 | //Parses Bookcolor handle | |||
| 3796 | } | |||
| 3797 | if (version > DRW::AC1014) {//2000+ | |||
| 3798 | //layer handle | |||
| 3799 | if (!readOffsetHandle(newLayerH)) | |||
| 3800 | return false; | |||
| 3801 | DRW_DBG(" layer Handle: ")DRW_dbg::dbg(" layer Handle: "); DRW_DBGHL(newLayerH.code, newLayerH.size, newLayerH.ref)DRW_dbg::dbgHL(newLayerH.code, newLayerH.size, newLayerH.ref); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 3802 | DRW_DBG(" Remaining bytes: ")DRW_dbg::dbg(" Remaining bytes: "); DRW_DBG(buf->numRemainingBytes())DRW_dbg::dbg(buf->numRemainingBytes()); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 3803 | //lineType handle | |||
| 3804 | if(ltFlags == 3){ | |||
| 3805 | if (!readOffsetHandle(newLTypeH)) | |||
| 3806 | return false; | |||
| 3807 | DRW_DBG("linetype Handle: ")DRW_dbg::dbg("linetype Handle: "); DRW_DBGHL(newLTypeH.code, newLTypeH.size, newLTypeH.ref)DRW_dbg::dbgHL(newLTypeH.code, newLTypeH.size, newLTypeH.ref); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 3808 | DRW_DBG(" Remaining bytes: ")DRW_dbg::dbg(" Remaining bytes: "); DRW_DBG(buf->numRemainingBytes())DRW_dbg::dbg(buf->numRemainingBytes()); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 3809 | } | |||
| 3810 | } | |||
| 3811 | if (version > DRW::AC1014) {//2000+ | |||
| 3812 | if (version > DRW::AC1018) {//2007+ | |||
| 3813 | if (materialFlag == 3) { | |||
| 3814 | dwgHandle materialH; | |||
| 3815 | if (!readOffsetHandle(materialH)) | |||
| 3816 | return false; | |||
| 3817 | newMaterial = materialH.ref; | |||
| 3818 | DRW_DBG(" material Handle: ")DRW_dbg::dbg(" material Handle: "); DRW_DBGHL(materialH.code, materialH.size, materialH.ref)DRW_dbg::dbgHL(materialH.code, materialH.size, materialH.ref); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 3819 | DRW_DBG("\n Remaining bytes: ")DRW_dbg::dbg("\n Remaining bytes: "); DRW_DBG(buf->numRemainingBytes())DRW_dbg::dbg(buf->numRemainingBytes()); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 3820 | } | |||
| 3821 | if (shadowFlag == 3) { | |||
| 3822 | // AcDbShadow object handle is separate from the mode encoded | |||
| 3823 | // in shadowFlag. Keep it even though LibreCAD has no render | |||
| 3824 | // consumer for the shadow object itself. | |||
| 3825 | dwgHandle shadowH; | |||
| 3826 | if (!readOffsetHandle(shadowH)) | |||
| 3827 | return false; | |||
| 3828 | newShadowHandle = shadowH.ref; | |||
| 3829 | DRW_DBG(" shadow Handle: ")DRW_dbg::dbg(" shadow Handle: "); DRW_DBGHL(shadowH.code, shadowH.size, shadowH.ref)DRW_dbg::dbgHL(shadowH.code, shadowH.size, shadowH.ref); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 3830 | DRW_DBG("\n Remaining bytes: ")DRW_dbg::dbg("\n Remaining bytes: "); DRW_DBG(buf->numRemainingBytes())DRW_dbg::dbg(buf->numRemainingBytes()); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 3831 | } | |||
| 3832 | } | |||
| 3833 | if (plotFlags == 3) { | |||
| 3834 | dwgHandle plotStyleH; | |||
| 3835 | if (!readOffsetHandle(plotStyleH)) | |||
| 3836 | return false; | |||
| 3837 | newPlotStyle = static_cast<int>(plotStyleH.ref); | |||
| 3838 | DRW_DBG(" plot style Handle: ")DRW_dbg::dbg(" plot style Handle: "); DRW_DBGHL(plotStyleH.code, plotStyleH.size, plotStyleH.ref)DRW_dbg::dbgHL(plotStyleH.code, plotStyleH.size, plotStyleH.ref ); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 3839 | DRW_DBG("\n Remaining bytes: ")DRW_dbg::dbg("\n Remaining bytes: "); DRW_DBG(buf->numRemainingBytes())DRW_dbg::dbg(buf->numRemainingBytes()); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 3840 | } | |||
| 3841 | if (version > DRW::AC1021) {//2010+ — §19.4.2: visual-style handles | |||
| 3842 | // Ground-truth: libreDWG common_entity_handle_data.spec lines | |||
| 3843 | // 141-150 and ODA spec v5.4.1 §19.4.2. Order matches: full, | |||
| 3844 | // face, edge — each conditional on its single-bit flag from | |||
| 3845 | // §19.4.1 (set in parseDwg above). All three are hard pointers | |||
| 3846 | // (libreDWG FIELD_HANDLE code 5), matching the existing | |||
| 3847 | // material/shadow/plotstyle handles in this block. | |||
| 3848 | if (hasFullVisualStyle) { | |||
| 3849 | dwgHandle h; | |||
| 3850 | if (!readOffsetHandle(h)) | |||
| 3851 | return false; | |||
| 3852 | newFullVisualStyleHandle = h.ref; | |||
| 3853 | DRW_DBG(" full visual-style H: ")DRW_dbg::dbg(" full visual-style H: "); | |||
| 3854 | DRW_DBGHL(h.code, h.size, h.ref)DRW_dbg::dbgHL(h.code, h.size, h.ref); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 3855 | } | |||
| 3856 | if (hasFaceVisualStyle) { | |||
| 3857 | dwgHandle h; | |||
| 3858 | if (!readOffsetHandle(h)) | |||
| 3859 | return false; | |||
| 3860 | newFaceVisualStyleHandle = h.ref; | |||
| 3861 | DRW_DBG(" face visual-style H: ")DRW_dbg::dbg(" face visual-style H: "); | |||
| 3862 | DRW_DBGHL(h.code, h.size, h.ref)DRW_dbg::dbgHL(h.code, h.size, h.ref); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 3863 | } | |||
| 3864 | if (hasEdgeVisualStyle) { | |||
| 3865 | dwgHandle h; | |||
| 3866 | if (!readOffsetHandle(h)) | |||
| 3867 | return false; | |||
| 3868 | newEdgeVisualStyleHandle = h.ref; | |||
| 3869 | DRW_DBG(" edge visual-style H: ")DRW_dbg::dbg(" edge visual-style H: "); | |||
| 3870 | DRW_DBGHL(h.code, h.size, h.ref)DRW_dbg::dbgHL(h.code, h.size, h.ref); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 3871 | } | |||
| 3872 | } | |||
| 3873 | } | |||
| 3874 | const int rb = buf->numRemainingBytes(); | |||
| 3875 | DRW_DBG("\n DRW_Entity::parseDwgEntHandle Remaining bytes: ")DRW_dbg::dbg("\n DRW_Entity::parseDwgEntHandle Remaining bytes: " ); DRW_DBG(rb)DRW_dbg::dbg(rb); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 3876 | if (rb > 4) { // 2-byte CRC + slack | |||
| 3877 | DRW_DBG("\n*** parseDwgEntHandle leftover ")DRW_dbg::dbg("\n*** parseDwgEntHandle leftover "); | |||
| 3878 | DRW_DBG(rb)DRW_dbg::dbg(rb); | |||
| 3879 | DRW_DBG(" bytes; entity handle ")DRW_dbg::dbg(" bytes; entity handle "); | |||
| 3880 | DRW_DBGH(handle)DRW_dbg::dbgH(handle); | |||
| 3881 | DRW_DBG(" oType ")DRW_dbg::dbg(" oType "); | |||
| 3882 | DRW_DBG(oType)DRW_dbg::dbg(oType); | |||
| 3883 | DRW_DBG(" — possible bit-stream misalignment ***\n")DRW_dbg::dbg(" — possible bit-stream misalignment ***\n"); | |||
| 3884 | } | |||
| 3885 | if (!buf->isGood() | |||
| 3886 | || (handleEndBit != std::numeric_limits<std::uint64_t>::max() | |||
| 3887 | && currentDwgBit(buf) > handleEndBit)) | |||
| 3888 | return false; | |||
| 3889 | ||||
| 3890 | acDbColorHandle = newAcDbColorHandle; | |||
| 3891 | parentHandle = newParentHandle; | |||
| 3892 | reactorHandles = std::move(newReactorHandles); | |||
| 3893 | xDictHandle = newXDictHandle; | |||
| 3894 | layerH = newLayerH; | |||
| 3895 | lTypeH = newLTypeH; | |||
| 3896 | nextEntLink = newNextEntLink; | |||
| 3897 | prevEntLink = newPrevEntLink; | |||
| 3898 | material = newMaterial; | |||
| 3899 | plotStyle = newPlotStyle; | |||
| 3900 | shadow = newShadow; | |||
| 3901 | if (version <= DRW::AC1018) { | |||
| 3902 | materialFlag = 0; | |||
| 3903 | shadowFlag = 0; | |||
| 3904 | } | |||
| 3905 | shadowHandle = newShadowHandle; | |||
| 3906 | if (version <= DRW::AC1021) { | |||
| 3907 | hasFullVisualStyle = false; | |||
| 3908 | hasFaceVisualStyle = false; | |||
| 3909 | hasEdgeVisualStyle = false; | |||
| 3910 | } | |||
| 3911 | fullVisualStyleHandle = newFullVisualStyleHandle; | |||
| 3912 | faceVisualStyleHandle = newFaceVisualStyleHandle; | |||
| 3913 | edgeVisualStyleHandle = newEdgeVisualStyleHandle; | |||
| 3914 | // R2007+ separates this tail from the object data stream. Earlier typed | |||
| 3915 | // parsers may consume inline handles but cannot give raw metadata an | |||
| 3916 | // independently bounded common-link proof. | |||
| 3917 | commonLinkTailValidated = version > DRW::AC1018; | |||
| 3918 | return true; | |||
| 3919 | } | |||
| 3920 | ||||
| 3921 | bool DRW_Entity::parseDwgCommon(DRW::Version version, dwgBuffer *buf, | |||
| 3922 | std::uint32_t bs) { | |||
| 3923 | if (buf == nullptr) | |||
| 3924 | return false; | |||
| 3925 | // R2007 (AC1021) omits the footer when an object has no string stream; | |||
| 3926 | // the concrete readers using this helper have no detached text fields. | |||
| 3927 | if (version <= DRW::AC1021) | |||
| 3928 | return parseDwg(version, buf, nullptr, bs); | |||
| 3929 | ||||
| 3930 | // Keep the publishing cursor transactional: a missing string footer is | |||
| 3931 | // legal for body-only R2007-era inputs and for the low-level entity test | |||
| 3932 | // API, but must not leave the cursor half-consumed before that fallback. | |||
| 3933 | dwgBuffer bodyProbe = buf->forkIndependent(); | |||
| 3934 | dwgBuffer stringProbe = bodyProbe.forkIndependent(); | |||
| 3935 | if (parseDwg(version, &bodyProbe, &stringProbe, bs)) { | |||
| 3936 | *buf = bodyProbe; | |||
| 3937 | return true; | |||
| 3938 | } | |||
| 3939 | return parseDwg(version, buf, nullptr, bs); | |||
| 3940 | } | |||
| 3941 | ||||
| 3942 | bool DRW_ProxyEntity::parseDwg(DRW::Version version, dwgBuffer *buf, | |||
| 3943 | std::uint32_t bs) { | |||
| 3944 | if (buf == nullptr || version < DRW::AC1012) | |||
| 3945 | return false; | |||
| 3946 | ||||
| 3947 | DRW_Entity::reset(); | |||
| 3948 | eType = DRW::PROXYENTITY; | |||
| 3949 | m_hasProxyClassId = false; | |||
| 3950 | m_proxyClassId = 0; | |||
| 3951 | m_hasProxyCarrierId = false; | |||
| 3952 | m_proxyCarrierId = 0; | |||
| 3953 | m_proxySubclass.clear(); | |||
| 3954 | m_hasProxyDrawingFormat = false; | |||
| 3955 | m_proxyDrawingFormat = 0; | |||
| 3956 | m_proxyDwgVersion = 0; | |||
| 3957 | m_proxyMaintenanceVersion = 0; | |||
| 3958 | m_hasFromDxf = false; | |||
| 3959 | m_fromDxf = false; | |||
| 3960 | m_hasProxyGraphicsByteSize = false; | |||
| 3961 | m_proxyGraphicsByteSize = 0; | |||
| 3962 | m_hasEntityDataBitSize = false; | |||
| 3963 | m_entityData.clear(); | |||
| 3964 | m_entityDataBitSize = 0; | |||
| 3965 | m_hasUnknownDataByteSize = false; | |||
| 3966 | m_unknownDataByteSize = 0; | |||
| 3967 | m_unknownData.clear(); | |||
| 3968 | m_objectIdRefs.clear(); | |||
| 3969 | ||||
| 3970 | dwgBuffer stringBuffer = *buf; | |||
| 3971 | dwgBuffer *stringBuf = version > DRW::AC1018 ? &stringBuffer : buf; | |||
| 3972 | if (!DRW_Entity::parseDwg(version, buf, stringBuf, bs)) | |||
| 3973 | return false; | |||
| 3974 | ||||
| 3975 | std::uint64_t dataEndBit = 0; | |||
| 3976 | std::uint64_t stringEndBit = 0; | |||
| 3977 | if (!entityBodyDataEndBit(*stringBuf, version, objSize, dataEndBit, | |||
| 3978 | &stringEndBit) | |||
| 3979 | || dataEndBit > proxyEntityEndBit(*buf, 0)) | |||
| 3980 | return false; | |||
| 3981 | ||||
| 3982 | bool present = false; | |||
| 3983 | std::int32_t value = 0; | |||
| 3984 | if (!readProxyEntityOptionalBitLong(*buf, dataEndBit, present, value)) | |||
| 3985 | return false; | |||
| 3986 | if (present) { | |||
| 3987 | m_hasProxyCarrierId = true; | |||
| 3988 | m_proxyCarrierId = value; | |||
| 3989 | } | |||
| 3990 | ||||
| 3991 | if (version >= DRW::AC1018 | |||
| 3992 | && proxyEntityHasBits(*stringBuf, stringEndBit, 2)) { | |||
| 3993 | if (!readBoundedVariableText(*stringBuf, stringEndBit, version, | |||
| 3994 | m_proxySubclass)) | |||
| 3995 | return false; | |||
| 3996 | } | |||
| 3997 | ||||
| 3998 | if (version >= DRW::AC1032) { | |||
| 3999 | bool hasDwgVersion = false; | |||
| 4000 | bool hasMaintenanceVersion = false; | |||
| 4001 | std::int32_t dwgVersion = 0; | |||
| 4002 | std::int32_t maintenanceVersion = 0; | |||
| 4003 | if (!readProxyEntityOptionalBitLong(*buf, dataEndBit, | |||
| 4004 | hasDwgVersion, dwgVersion) | |||
| 4005 | || !readProxyEntityOptionalBitLong(*buf, dataEndBit, | |||
| 4006 | hasMaintenanceVersion, | |||
| 4007 | maintenanceVersion)) { | |||
| 4008 | return false; | |||
| 4009 | } | |||
| 4010 | if (hasDwgVersion || hasMaintenanceVersion) { | |||
| 4011 | m_hasProxyDrawingFormat = true; | |||
| 4012 | m_proxyDwgVersion = static_cast<std::uint16_t>(dwgVersion); | |||
| 4013 | m_proxyMaintenanceVersion = | |||
| 4014 | static_cast<std::uint16_t>(maintenanceVersion); | |||
| 4015 | m_proxyDrawingFormat = | |||
| 4016 | (static_cast<std::uint32_t>(m_proxyMaintenanceVersion) << 16u) | |||
| 4017 | | m_proxyDwgVersion; | |||
| 4018 | } | |||
| 4019 | } else if (!readProxyEntityOptionalBitLong(*buf, dataEndBit, | |||
| 4020 | present, value)) { | |||
| 4021 | return false; | |||
| 4022 | } else if (present) { | |||
| 4023 | m_hasProxyDrawingFormat = true; | |||
| 4024 | m_proxyDrawingFormat = static_cast<std::uint32_t>(value); | |||
| 4025 | m_proxyDwgVersion = static_cast<std::uint16_t>(value); | |||
| 4026 | m_proxyMaintenanceVersion = static_cast<std::uint16_t>( | |||
| 4027 | static_cast<std::uint32_t>(value) >> 16u); | |||
| 4028 | } | |||
| 4029 | ||||
| 4030 | if (version >= DRW::AC1015 && proxyEntityHasBits(*buf, dataEndBit, 1)) { | |||
| 4031 | if (!readBoundedBit(*buf, dataEndBit, m_fromDxf)) | |||
| 4032 | return false; | |||
| 4033 | m_hasFromDxf = true; | |||
| 4034 | } | |||
| 4035 | ||||
| 4036 | const std::uint64_t payloadStartBit = currentDwgBit(buf); | |||
| 4037 | if (payloadStartBit > dataEndBit | |||
| 4038 | || !copyDwgBitRange(*buf, payloadStartBit, dataEndBit, m_entityData)) { | |||
| 4039 | return false; | |||
| 4040 | } | |||
| 4041 | m_entityDataBitSize = static_cast<std::uint32_t>( | |||
| 4042 | dataEndBit - payloadStartBit); | |||
| 4043 | ||||
| 4044 | dwgBuffer handleBuffer = *buf; | |||
| 4045 | if (!handleBuffer.setPosition(dataEndBit >> 3)) | |||
| 4046 | return false; | |||
| 4047 | handleBuffer.setBitPos(static_cast<std::uint8_t>(dataEndBit & 7u)); | |||
| 4048 | if (!handleBuffer.isGood()) | |||
| 4049 | return false; | |||
| 4050 | std::uint64_t handleEndBit = 0; | |||
| 4051 | if (!dwgHandleStreamEndBit(*buf, version, objSize, bs, handleEndBit) | |||
| 4052 | || !DRW_Entity::parseDwgEntHandle(version, &handleBuffer, true, | |||
| 4053 | handleEndBit)) | |||
| 4054 | return false; | |||
| 4055 | while (proxyEntityHasBits(handleBuffer, handleEndBit, 8)) { | |||
| 4056 | dwgHandle rawHandle; | |||
| 4057 | dwgHandle resolvedHandle; | |||
| 4058 | if (!readBoundedDwgObjectId(handleBuffer, handleEndBit, handle, | |||
| 4059 | rawHandle, resolvedHandle)) | |||
| 4060 | return false; | |||
| 4061 | if (rawHandle.code == 0 && rawHandle.ref64 == 0) | |||
| 4062 | break; | |||
| 4063 | ||||
| 4064 | DRW_ProxyObjectIdRef ref; | |||
| 4065 | ref.m_dxfCode = proxyEntityDxfCode(rawHandle.code); | |||
| 4066 | ref.m_handleCode = rawHandle.code; | |||
| 4067 | ref.m_handle = resolvedHandle.ref64; | |||
| 4068 | ref.m_rawHandle = rawHandle.ref64; | |||
| 4069 | m_objectIdRefs.push_back(ref); | |||
| 4070 | } | |||
| 4071 | ||||
| 4072 | return buf->isGood() && stringBuf->isGood() && handleBuffer.isGood(); | |||
| 4073 | } | |||
| 4074 | ||||
| 4075 | bool DRW_Point::parseCode(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 4076 | switch (code) { | |||
| 4077 | case 10: | |||
| 4078 | basePoint.x = reader->getDouble(); | |||
| 4079 | break; | |||
| 4080 | case 20: | |||
| 4081 | basePoint.y = reader->getDouble(); | |||
| 4082 | break; | |||
| 4083 | case 30: | |||
| 4084 | basePoint.z = reader->getDouble(); | |||
| 4085 | break; | |||
| 4086 | case 39: | |||
| 4087 | thickness = reader->getDouble(); | |||
| 4088 | break; | |||
| 4089 | case 50: | |||
| 4090 | // DXF code 50 is in degrees; the field is radians (matching the DWG | |||
| 4091 | // path, drw_entities.cpp:1787). degrees -> radians is /ARAD (x pi/180); | |||
| 4092 | // the prior *ARAD only canceled with the writer's /ARAD on DXF->DXF and | |||
| 4093 | // corrupted the value for DXF->DWG. ARAD = 180/pi. | |||
| 4094 | xAxisAngle = reader->getDouble() / ARAD57.29577951308232; // DXF degrees -> radians | |||
| 4095 | break; | |||
| 4096 | case 210: | |||
| 4097 | haveExtrusion = true; | |||
| 4098 | extPoint.x = reader->getDouble(); | |||
| 4099 | break; | |||
| 4100 | case 220: | |||
| 4101 | extPoint.y = reader->getDouble(); | |||
| 4102 | break; | |||
| 4103 | case 230: | |||
| 4104 | extPoint.z = reader->getDouble(); | |||
| 4105 | break; | |||
| 4106 | default: | |||
| 4107 | return DRW_Entity::parseCode(code, reader); | |||
| 4108 | } | |||
| 4109 | ||||
| 4110 | return true; | |||
| 4111 | } | |||
| 4112 | ||||
| 4113 | // --------------------------------------------------------------------------- | |||
| 4114 | // Phase 4a (drafted 2026-05-15) | |||
| 4115 | // --------------------------------------------------------------------------- | |||
| 4116 | // `DRW_Entity::encodeDwgCommon` and `encodeDwgEntHandle` mirror the common | |||
| 4117 | // entity-header fragments parsed above. Version gates intentionally follow | |||
| 4118 | // the DWG reader so newer headers retain their reference flags and handles. | |||
| 4119 | // | |||
| 4120 | // Discarded fields (Risk 4i): | |||
| 4121 | // - haveNextLinks B — we emit 1 (no prev/next chain). | |||
| 4122 | // - none of the common color side channels are discarded for R2004+; | |||
| 4123 | // ENC names remain the byte-oriented TV fields defined by the DWG | |||
| 4124 | // common-entity specification, while ordinary entity text uses strBuf. | |||
| 4125 | // | |||
| 4126 | // We still emit these fixed defaults: | |||
| 4127 | // - entmode = 2 (modelspace, no owner-handle in stream — caller can | |||
| 4128 | // override before calling encodeDwgCommon if entity needs an owner). | |||
| 4129 | // - numReactors = 0 (reactor handles are emitted by the handle phase when | |||
| 4130 | // present). | |||
| 4131 | // - ltFlags = 0 (BYLAYER); plotFlags follows plotStyle. | |||
| 4132 | // - invisibleFlag = 0 (visible) | |||
| 4133 | // | |||
| 4134 | // Caller must: | |||
| 4135 | // - Pre-populate `eType`, `handle`, `color`, `ltypeScale`, `lWeight`, | |||
| 4136 | // `layerH.ref` (handle of the layer this entity belongs to). | |||
| 4137 | // - The body emit between encodeDwgCommon and encodeDwgEntHandle is | |||
| 4138 | // per-entity (3BD basePoint for Point, etc.). | |||
| 4139 | ||||
| 4140 | // Phase-2a kill switch for the full common-entity-header write contract | |||
| 4141 | // (entity reactors/xdict/EED/visibility/entmode emission). Default ON. The | |||
| 4142 | // emission is gated by DATA PRESENCE (empty reactorHandles/extData + visible | |||
| 4143 | // == today's hardcoded zeros), so flipping this OFF restores the legacy | |||
| 4144 | // byte-identical output as an emergency escape hatch. The per-field emission | |||
| 4145 | // arms land in 2a.1..2a.5; this scaffolding commit changes no bytes. | |||
| 4146 | #ifndef LIBDXFRW_FULL_COMMON_HEADER1 | |||
| 4147 | #define LIBDXFRW_FULL_COMMON_HEADER1 1 | |||
| 4148 | #endif | |||
| 4149 | ||||
| 4150 | namespace { | |||
| 4151 | ||||
| 4152 | const DRW_Entity::PendingHandleRef* findEedWriteRef( | |||
| 4153 | const std::vector<DRW_Entity::PendingHandleRef>& refs, | |||
| 4154 | std::size_t index) { | |||
| 4155 | const auto it = std::find_if(refs.cbegin(), refs.cend(), | |||
| 4156 | [index](const auto& ref) { | |||
| 4157 | return ref.indexInExtData == index; | |||
| 4158 | }); | |||
| 4159 | if (it == refs.cend()) | |||
| 4160 | return nullptr; | |||
| 4161 | return &*it; | |||
| 4162 | } | |||
| 4163 | ||||
| 4164 | bool parseEedHexHandle(const std::string& text, std::uint64_t& handle) { | |||
| 4165 | if (text.empty()) | |||
| 4166 | return false; | |||
| 4167 | std::size_t index = 0; | |||
| 4168 | if (text.size() > 2 && text[0] == '0' | |||
| 4169 | && (text[1] == 'x' || text[1] == 'X')) { | |||
| 4170 | index = 2; | |||
| 4171 | } | |||
| 4172 | if (index == text.size()) | |||
| 4173 | return false; | |||
| 4174 | ||||
| 4175 | std::uint64_t parsed = 0; | |||
| 4176 | for (; index < text.size(); ++index) { | |||
| 4177 | const unsigned char character = | |||
| 4178 | static_cast<unsigned char>(text[index]); | |||
| 4179 | std::uint8_t digit = 0; | |||
| 4180 | if (character >= '0' && character <= '9') | |||
| 4181 | digit = static_cast<std::uint8_t>(character - '0'); | |||
| 4182 | else if (character >= 'a' && character <= 'f') | |||
| 4183 | digit = static_cast<std::uint8_t>(character - 'a' + 10); | |||
| 4184 | else if (character >= 'A' && character <= 'F') | |||
| 4185 | digit = static_cast<std::uint8_t>(character - 'A' + 10); | |||
| 4186 | else | |||
| 4187 | return false; | |||
| 4188 | if (parsed > (std::numeric_limits<std::uint64_t>::max() - digit) / 16U) | |||
| 4189 | return false; | |||
| 4190 | parsed = parsed * 16U + digit; | |||
| 4191 | } | |||
| 4192 | handle = parsed; | |||
| 4193 | return true; | |||
| 4194 | } | |||
| 4195 | ||||
| 4196 | void putEedRawHandleBE(dwgBufferW& buffer, std::uint64_t handle) { | |||
| 4197 | for (int index = 7; index >= 0; --index) { | |||
| 4198 | buffer.putRawChar8(static_cast<std::uint8_t>( | |||
| 4199 | (handle >> (index * 8)) & 0xFFU)); | |||
| 4200 | } | |||
| 4201 | } | |||
| 4202 | ||||
| 4203 | void putEedRawHandleLE(dwgBufferW& buffer, std::uint64_t handle) { | |||
| 4204 | for (unsigned index = 0; index < 8; ++index) { | |||
| 4205 | buffer.putRawChar8(static_cast<std::uint8_t>( | |||
| 4206 | (handle >> (index * 8U)) & 0xFFU)); | |||
| 4207 | } | |||
| 4208 | } | |||
| 4209 | ||||
| 4210 | bool encodeEedItem(DRW::Version version, const DRW_Variant& value, | |||
| 4211 | dwgBufferW& textEncoder, dwgBufferW& output, | |||
| 4212 | std::uint64_t resolvedLayerHandle, | |||
| 4213 | std::uint16_t codePage) { | |||
| 4214 | const int groupCode = value.code(); | |||
| 4215 | switch (groupCode) { | |||
| 4216 | case 1000: { | |||
| 4217 | if (value.type() != DRW_Variant::STRING || value.content.s == nullptr) | |||
| 4218 | return false; | |||
| 4219 | const std::string encoded = textEncoder.encodeTextAreaString( | |||
| 4220 | *value.content.s, version > DRW::AC1018); | |||
| 4221 | if (version > DRW::AC1018) { | |||
| 4222 | if ((encoded.size() & 1U) != 0 | |||
| 4223 | || encoded.size() / 2U > std::numeric_limits<std::uint16_t>::max()) { | |||
| 4224 | return false; | |||
| 4225 | } | |||
| 4226 | output.putRawChar8(0); | |||
| 4227 | output.putRawShort16(static_cast<std::uint16_t>(encoded.size() / 2U)); | |||
| 4228 | } else { | |||
| 4229 | if (encoded.size() > std::numeric_limits<std::uint8_t>::max()) | |||
| 4230 | return false; | |||
| 4231 | output.putRawChar8(0); | |||
| 4232 | output.putRawChar8(static_cast<std::uint8_t>(encoded.size())); | |||
| 4233 | output.putBERawShort16(codePage); | |||
| 4234 | } | |||
| 4235 | output.putBytes(reinterpret_cast<const std::uint8_t*>(encoded.data()), | |||
| 4236 | encoded.size()); | |||
| 4237 | return output.isGood(); | |||
| 4238 | } | |||
| 4239 | case 1002: { | |||
| 4240 | if (value.type() != DRW_Variant::STRING || value.content.s == nullptr | |||
| 4241 | || (*value.content.s != "{" && *value.content.s != "}")) { | |||
| 4242 | return false; | |||
| 4243 | } | |||
| 4244 | output.putRawChar8(2); | |||
| 4245 | output.putRawChar8(*value.content.s == "{" ? 0 : 1); | |||
| 4246 | return output.isGood(); | |||
| 4247 | } | |||
| 4248 | case 1003: | |||
| 4249 | if (value.type() != DRW_Variant::STRING || resolvedLayerHandle == 0) | |||
| 4250 | return false; | |||
| 4251 | output.putRawChar8(3); | |||
| 4252 | putEedRawHandleLE(output, resolvedLayerHandle); | |||
| 4253 | return output.isGood(); | |||
| 4254 | case 1004: { | |||
| 4255 | if (value.type() != DRW_Variant::BINARY || value.binary() == nullptr | |||
| 4256 | || value.binary()->size() > std::numeric_limits<std::uint8_t>::max()) { | |||
| 4257 | return false; | |||
| 4258 | } | |||
| 4259 | output.putRawChar8(4); | |||
| 4260 | output.putRawChar8(static_cast<std::uint8_t>(value.binary()->size())); | |||
| 4261 | output.putBytes(value.binary()->data(), value.binary()->size()); | |||
| 4262 | return output.isGood(); | |||
| 4263 | } | |||
| 4264 | case 1005: { | |||
| 4265 | if (value.type() != DRW_Variant::STRING || value.content.s == nullptr) | |||
| 4266 | return false; | |||
| 4267 | std::uint64_t handle = 0; | |||
| 4268 | if (!parseEedHexHandle(*value.content.s, handle)) | |||
| 4269 | return false; | |||
| 4270 | output.putRawChar8(5); | |||
| 4271 | putEedRawHandleBE(output, handle); | |||
| 4272 | return output.isGood(); | |||
| 4273 | } | |||
| 4274 | case 1010: | |||
| 4275 | case 1011: | |||
| 4276 | case 1012: | |||
| 4277 | case 1013: { | |||
| 4278 | if (value.type() != DRW_Variant::COORD || value.coord() == nullptr) | |||
| 4279 | return false; | |||
| 4280 | const DRW_Coord& coordinate = *value.coord(); | |||
| 4281 | if (!std::isfinite(coordinate.x) || !std::isfinite(coordinate.y) | |||
| 4282 | || !std::isfinite(coordinate.z)) { | |||
| 4283 | return false; | |||
| 4284 | } | |||
| 4285 | output.putRawChar8(static_cast<std::uint8_t>(groupCode - 1000)); | |||
| 4286 | output.putRawDouble(coordinate.x); | |||
| 4287 | output.putRawDouble(coordinate.y); | |||
| 4288 | output.putRawDouble(coordinate.z); | |||
| 4289 | return output.isGood(); | |||
| 4290 | } | |||
| 4291 | case 1040: | |||
| 4292 | case 1041: | |||
| 4293 | case 1042: | |||
| 4294 | if (value.type() != DRW_Variant::DOUBLE || !std::isfinite(value.d_val())) | |||
| 4295 | return false; | |||
| 4296 | output.putRawChar8(static_cast<std::uint8_t>(groupCode - 1000)); | |||
| 4297 | output.putRawDouble(value.d_val()); | |||
| 4298 | return output.isGood(); | |||
| 4299 | case 1070: | |||
| 4300 | if (value.type() != DRW_Variant::INTEGER | |||
| 4301 | || value.i_val() < std::numeric_limits<std::int16_t>::min() | |||
| 4302 | || value.i_val() > std::numeric_limits<std::int16_t>::max()) { | |||
| 4303 | return false; | |||
| 4304 | } | |||
| 4305 | output.putRawChar8(70); | |||
| 4306 | output.putRawShort16(static_cast<std::uint16_t>( | |||
| 4307 | static_cast<std::int16_t>(value.i_val()))); | |||
| 4308 | return output.isGood(); | |||
| 4309 | case 1071: { | |||
| 4310 | std::int64_t integer = 0; | |||
| 4311 | if (value.type() == DRW_Variant::INTEGER) | |||
| 4312 | integer = value.i_val(); | |||
| 4313 | else if (value.type() == DRW_Variant::INTEGER64) | |||
| 4314 | integer = value.i64_val(); | |||
| 4315 | else | |||
| 4316 | return false; | |||
| 4317 | if (integer < std::numeric_limits<std::int32_t>::min() | |||
| 4318 | || integer > std::numeric_limits<std::int32_t>::max()) { | |||
| 4319 | return false; | |||
| 4320 | } | |||
| 4321 | output.putRawChar8(71); | |||
| 4322 | output.putRawLong32(static_cast<std::uint32_t>( | |||
| 4323 | static_cast<std::int32_t>(integer))); | |||
| 4324 | return output.isGood(); | |||
| 4325 | } | |||
| 4326 | default: | |||
| 4327 | return false; | |||
| 4328 | } | |||
| 4329 | } | |||
| 4330 | ||||
| 4331 | } // namespace | |||
| 4332 | ||||
| 4333 | bool DRW_Entity::encodeDwgEed( | |||
| 4334 | DRW::Version version, const std::vector<DRW_Variant*>& extData, | |||
| 4335 | const std::vector<PendingHandleRef>& appIdRefs, | |||
| 4336 | const std::vector<PendingHandleRef>& layerRefs, | |||
| 4337 | std::uint16_t codePage, dwgBufferW& output) { | |||
| 4338 | if (extData.empty()) { | |||
| 4339 | output.putBitShort(0); | |||
| 4340 | return output.isGood(); | |||
| 4341 | } | |||
| 4342 | if (extData.size() > dwgSafety::MaxEedTotalItems) | |||
| 4343 | return false; | |||
| 4344 | ||||
| 4345 | std::size_t currentAppStart = 0; | |||
| 4346 | std::uint32_t appHandle = 0; | |||
| 4347 | std::uint32_t groupDepth = 0; | |||
| 4348 | std::uint32_t chunkCount = 0; | |||
| 4349 | dwgBufferW payload; | |||
| 4350 | const auto flush = [&]() { | |||
| 4351 | if (payload.data().empty() || payload.data().size() | |||
| 4352 | > std::numeric_limits<std::uint16_t>::max() | |||
| 4353 | || appHandle == 0 || ++chunkCount > dwgSafety::MaxEedChunks) { | |||
| 4354 | return false; | |||
| 4355 | } | |||
| 4356 | output.putBitShort(static_cast<std::uint16_t>(payload.data().size())); | |||
| 4357 | dwgHandle appId; | |||
| 4358 | appId.code = 5; | |||
| 4359 | appId.ref = appHandle; | |||
| 4360 | output.putHandle(appId); | |||
| 4361 | output.putBytes(payload.data().data(), payload.data().size()); | |||
| 4362 | payload.reset(); | |||
| 4363 | return output.isGood(); | |||
| 4364 | }; | |||
| 4365 | ||||
| 4366 | for (std::size_t index = 0; index < extData.size(); ++index) { | |||
| 4367 | const DRW_Variant* value = extData[index]; | |||
| 4368 | if (value == nullptr) | |||
| 4369 | return false; | |||
| 4370 | if (value->code() == 1001) { | |||
| 4371 | if (index != currentAppStart) { | |||
| 4372 | if (groupDepth != 0 || !flush()) | |||
| 4373 | return false; | |||
| 4374 | } | |||
| 4375 | const PendingHandleRef* appIdRef = findEedWriteRef(appIdRefs, index); | |||
| 4376 | if (appIdRef == nullptr || appIdRef->handleRef == 0) { | |||
| 4377 | return false; | |||
| 4378 | } | |||
| 4379 | appHandle = appIdRef->handleRef; | |||
| 4380 | currentAppStart = index + 1; | |||
| 4381 | groupDepth = 0; | |||
| 4382 | continue; | |||
| 4383 | } | |||
| 4384 | if (index < currentAppStart) | |||
| 4385 | return false; | |||
| 4386 | if (value->code() == 1002) { | |||
| 4387 | if (value->type() != DRW_Variant::STRING || value->content.s == nullptr) | |||
| 4388 | return false; | |||
| 4389 | if (*value->content.s == "{") { | |||
| 4390 | ++groupDepth; | |||
| 4391 | } else if (*value->content.s == "}") { | |||
| 4392 | if (groupDepth == 0) | |||
| 4393 | return false; | |||
| 4394 | --groupDepth; | |||
| 4395 | } else { | |||
| 4396 | return false; | |||
| 4397 | } | |||
| 4398 | } | |||
| 4399 | ||||
| 4400 | std::uint64_t layerHandle = 0; | |||
| 4401 | if (value->code() == 1003) { | |||
| 4402 | const PendingHandleRef* layerRef = findEedWriteRef(layerRefs, index); | |||
| 4403 | if (layerRef == nullptr) | |||
| 4404 | return false; | |||
| 4405 | layerHandle = layerRef->useRawHandleRef | |||
| 4406 | ? layerRef->rawHandleRef : layerRef->handleRef; | |||
| 4407 | if (layerHandle == 0) | |||
| 4408 | return false; | |||
| 4409 | } | |||
| 4410 | dwgBufferW item; | |||
| 4411 | if (!encodeEedItem(version, *value, output, item, layerHandle, | |||
| 4412 | codePage)) | |||
| 4413 | return false; | |||
| 4414 | if (item.data().size() > std::numeric_limits<std::uint16_t>::max()) | |||
| 4415 | return false; | |||
| 4416 | if (!payload.data().empty() | |||
| 4417 | && payload.data().size() + item.data().size() | |||
| 4418 | > std::numeric_limits<std::uint16_t>::max()) { | |||
| 4419 | if (groupDepth != 0 || !flush()) | |||
| 4420 | return false; | |||
| 4421 | } | |||
| 4422 | payload.putBytes(item.data().data(), item.data().size()); | |||
| 4423 | } | |||
| 4424 | if (currentAppStart == 0 || groupDepth != 0 || !flush()) | |||
| 4425 | return false; | |||
| 4426 | output.putBitShort(0); | |||
| 4427 | return output.isGood(); | |||
| 4428 | } | |||
| 4429 | ||||
| 4430 | bool DRW_Entity::encodeDwgCommon(DRW::Version version, dwgBufferW *buf, | |||
| 4431 | dwgBufferW *strBuf) { | |||
| 4432 | (void)strBuf; // ENC names are byte-oriented TV fields in the data stream | |||
| 4433 | if (buf == nullptr || reactorHandles.size() > dwgSafety::MaxReactorCount || | |||
| 4434 | (version != DRW::AC1015 && version != DRW::AC1018 && | |||
| 4435 | version != DRW::AC1021 && | |||
| 4436 | version != DRW::AC1024 && version != DRW::AC1027 && | |||
| 4437 | version != DRW::AC1032)) return false; | |||
| 4438 | ||||
| 4439 | // Object type: BS for AC1015/AC1018, OT for AC1024+. | |||
| 4440 | buf->putObjType(version, static_cast<std::uint16_t>(oType)); | |||
| 4441 | ||||
| 4442 | // objSize stub — back-patched for AC1015/AC1018 only. AC1024 derives | |||
| 4443 | // objSize from the body buffer size, so no RL is emitted. | |||
| 4444 | if (version < DRW::AC1024) { | |||
| 4445 | buf->putRawLong32(0); | |||
| 4446 | } | |||
| 4447 | ||||
| 4448 | // Own handle: code 0 per spec §20.4.1. | |||
| 4449 | dwgHandle ownH; | |||
| 4450 | ownH.code = 0; | |||
| 4451 | ownH.ref = handle; | |||
| 4452 | ownH.size = 0; | |||
| 4453 | if (handle != 0) { | |||
| 4454 | std::uint32_t t = handle; | |||
| 4455 | while (t != 0) { t >>= 8; ++ownH.size; } | |||
| 4456 | } | |||
| 4457 | buf->putHandle(ownH); | |||
| 4458 | ||||
| 4459 | std::vector<DRW_Variant*> eedValues; | |||
| 4460 | try { | |||
| 4461 | eedValues.reserve(extData.size()); | |||
| 4462 | for (const auto& value : extData) | |||
| 4463 | eedValues.push_back(value.get()); | |||
| 4464 | } catch (...) { | |||
| 4465 | return false; | |||
| 4466 | } | |||
| 4467 | if (!encodeDwgEed(version, eedValues, dwgEedAppIdWriteRefs, | |||
| 4468 | dwgEedLayerWriteRefs, dwgEedCodePage, *buf)) | |||
| 4469 | return false; | |||
| 4470 | ||||
| 4471 | // Proxy graphics lives in the common data stream. Preserve it when the | |||
| 4472 | // entity has a bounded byte stream; it is the cached fallback geometry | |||
| 4473 | // used for unrecognised custom/proxy entities. | |||
| 4474 | if (proxyGraphics.size() | |||
| 4475 | > static_cast<std::size_t>(std::numeric_limits<std::int32_t>::max() | |||
| 4476 | / 8)) { | |||
| 4477 | return false; | |||
| 4478 | } | |||
| 4479 | const bool hasProxyGraphics = !proxyGraphics.empty(); | |||
| 4480 | buf->putBit(hasProxyGraphics); | |||
| 4481 | if (hasProxyGraphics) { | |||
| 4482 | const auto graphDataSize = static_cast<std::uint64_t>( | |||
| 4483 | proxyGraphics.size()); | |||
| 4484 | if (version >= DRW::AC1024) | |||
| 4485 | buf->putBitLongLong(graphDataSize); | |||
| 4486 | else | |||
| 4487 | buf->putRawLong32(static_cast<std::uint32_t>(graphDataSize)); | |||
| 4488 | buf->putBytes(reinterpret_cast<const std::uint8_t*>( | |||
| 4489 | proxyGraphics.data()), | |||
| 4490 | proxyGraphics.size()); | |||
| 4491 | if (!buf->isGood()) | |||
| 4492 | return false; | |||
| 4493 | } | |||
| 4494 | ||||
| 4495 | const bool hasOwner = parentHandle != DRW::NoHandle; | |||
| 4496 | // entmode BB (ODA §20.4.1 / Open Design FE): | |||
| 4497 | // 0 = owner handle follows in the handle stream | |||
| 4498 | // 1 = paperspace entity without owner-relative handle | |||
| 4499 | // 2 = modelspace entity without owner-relative handle | |||
| 4500 | // Prefer owner when present; otherwise honor DRW_Entity::space. | |||
| 4501 | std::uint8_t entmode = 2; | |||
| 4502 | if (hasOwner) | |||
| 4503 | entmode = 0; | |||
| 4504 | else if (space == DRW::PaperSpace) | |||
| 4505 | entmode = 1; | |||
| 4506 | buf->put2Bits(entmode); | |||
| 4507 | ||||
| 4508 | // numReactors (BL per spec §20.4.1). 2a.2: emit the real count; empty | |||
| 4509 | // reactorHandles → 0 → byte-identical to legacy. | |||
| 4510 | #if LIBDXFRW_FULL_COMMON_HEADER1 | |||
| 4511 | buf->putBitLong(static_cast<std::int32_t>(reactorHandles.size())); | |||
| 4512 | #else | |||
| 4513 | buf->putBitLong(0); | |||
| 4514 | #endif | |||
| 4515 | ||||
| 4516 | // R2004/R2010 (AC1018, AC1024): reader reads xDictFlag bit (version > AC1015) | |||
| 4517 | // then forces haveNextLinks=1 (no bit in stream). We always emit | |||
| 4518 | // xDictFlag=0 (xdic-present) so the reader reads exactly one xdic handle | |||
| 4519 | // in the handle section — we emit the real handle when xDictHandle!=0 and | |||
| 4520 | // a null handle otherwise. This keeps the empty case byte-identical to the | |||
| 4521 | // legacy path (bit 0 + null handle) while round-tripping a real xdict. | |||
| 4522 | // R2000 (AC1015): no xDictFlag bit; reader's xDictFlag stays 0 so it ALWAYS | |||
| 4523 | // reads an xdic handle — same emit rule applies. | |||
| 4524 | // R2013+ (AC1027+): reader reads xDictFlag then reads haveNextLinks (bit restored). | |||
| 4525 | if (version == DRW::AC1015) { | |||
| 4526 | buf->putBit(1); // nolinks=1 (R2000: no prev/next chain) | |||
| 4527 | } else { | |||
| 4528 | buf->putBit(0); // xDictFlag=0 (xdic present; real-or-null handle follows) | |||
| 4529 | if (version > DRW::AC1024) { | |||
| 4530 | // libreDWG common_entity_data.spec — R2013+ has_ds_data (B). libdxfrw | |||
| 4531 | // never inlines an ACIS SAB datastore, so emit hasDsData (default 0). | |||
| 4532 | // The old code emitted literal 1 (mislabeled haveNextLinks), falsely | |||
| 4533 | // advertising an SAB blob and risking misparse in strict readers. | |||
| 4534 | buf->putBit(hasDsData); | |||
| 4535 | } | |||
| 4536 | } | |||
| 4537 | ||||
| 4538 | // ENC color. R2004+ retains the true-color, transparency, DBCOLOR, and | |||
| 4539 | // byte-oriented color/book-name side channels; AC1015 falls back to BS. | |||
| 4540 | UTF8STRINGstd::string encColorName = colorName; | |||
| 4541 | UTF8STRINGstd::string encBookName; | |||
| 4542 | const std::string::size_type separator = encColorName.find('$'); | |||
| 4543 | if (separator != std::string::npos) { | |||
| 4544 | encBookName = encColorName.substr(0, separator); | |||
| 4545 | encColorName.erase(0, separator + 1); | |||
| 4546 | } | |||
| 4547 | buf->putEnColor(version, static_cast<std::uint16_t>(color), color24, | |||
| 4548 | encColorName, encBookName, | |||
| 4549 | static_cast<std::uint32_t>(transparency), | |||
| 4550 | version >= DRW::AC1018 && hasAcDbColorH); | |||
| 4551 | ||||
| 4552 | // ltypeScale BD. | |||
| 4553 | buf->putBitDouble(ltypeScale); | |||
| 4554 | ||||
| 4555 | // ltFlags BB: 0=BYLAYER, 1=BYBLOCK, 2=CONTINUOUS, 3=lTypeH present. | |||
| 4556 | // Prefer an already-set ltFlags; otherwise derive from lineType / lTypeH. | |||
| 4557 | { | |||
| 4558 | auto upper = [](std::string s) { | |||
| 4559 | for (char& c : s) | |||
| 4560 | c = static_cast<char>(std::toupper(static_cast<unsigned char>(c))); | |||
| 4561 | return s; | |||
| 4562 | }; | |||
| 4563 | std::uint8_t flags = ltFlags; | |||
| 4564 | if (flags > 3) | |||
| 4565 | flags = 0; | |||
| 4566 | if (flags == 0 && lTypeH.ref != 0) | |||
| 4567 | flags = 3; | |||
| 4568 | if (flags == 0) { | |||
| 4569 | const std::string lt = upper(lineType); | |||
| 4570 | if (lt.empty() || lt == "BYLAYER") | |||
| 4571 | flags = 0; | |||
| 4572 | else if (lt == "BYBLOCK") | |||
| 4573 | flags = 1; | |||
| 4574 | else if (lt == "CONTINUOUS") | |||
| 4575 | flags = 2; | |||
| 4576 | else | |||
| 4577 | flags = 3; // named linetype — handle required | |||
| 4578 | } | |||
| 4579 | ltFlags = flags; | |||
| 4580 | } | |||
| 4581 | buf->put2Bits(ltFlags); | |||
| 4582 | // plotFlags BB: a nonzero plot-style handle requires the hard-pointer | |||
| 4583 | // handle in the common handle stream. Keep the default zero path | |||
| 4584 | // unchanged for entities without an override. | |||
| 4585 | plotFlags = plotStyle > 0 ? 3 : 0; | |||
| 4586 | buf->put2Bits(plotFlags); | |||
| 4587 | ||||
| 4588 | // R2010 (AC1024): materialFlag BB + shadowFlag RC (version > AC1018). | |||
| 4589 | if (version > DRW::AC1018) { | |||
| 4590 | materialFlag = material == DRW::MaterialByLayer ? 0 : 3; | |||
| 4591 | shadowFlag = static_cast<std::uint8_t>(shadow) & 0x3; | |||
| 4592 | buf->put2Bits(materialFlag); | |||
| 4593 | buf->putRawChar8(shadowFlag); | |||
| 4594 | } | |||
| 4595 | ||||
| 4596 | // R2010 (AC1024): three visual-style flag bits (version > AC1021). | |||
| 4597 | if (version > DRW::AC1021) { | |||
| 4598 | hasFullVisualStyle = fullVisualStyleHandle != 0; | |||
| 4599 | hasFaceVisualStyle = faceVisualStyleHandle != 0; | |||
| 4600 | hasEdgeVisualStyle = edgeVisualStyleHandle != 0; | |||
| 4601 | buf->putBit(hasFullVisualStyle); | |||
| 4602 | buf->putBit(hasFaceVisualStyle); | |||
| 4603 | buf->putBit(hasEdgeVisualStyle); | |||
| 4604 | } | |||
| 4605 | ||||
| 4606 | // invisibleFlag BS (DXF 60). 2a.1: emit from `visible` (bit 0 = invisible) | |||
| 4607 | // instead of a hardcoded 0. visible==true → 0 → byte-identical to legacy. | |||
| 4608 | #if LIBDXFRW_FULL_COMMON_HEADER1 | |||
| 4609 | buf->putBitShort(visible ? 0 : 1); | |||
| 4610 | #else | |||
| 4611 | buf->putBitShort(0); | |||
| 4612 | #endif | |||
| 4613 | ||||
| 4614 | // lWeight RC (0 = byLayer per DRW_LW_Conv). | |||
| 4615 | buf->putRawChar8(static_cast<std::uint8_t>(lWeight)); | |||
| 4616 | ||||
| 4617 | return buf->isGood(); | |||
| 4618 | } | |||
| 4619 | ||||
| 4620 | bool DRW_Entity::encodeDwgEntHandle(DRW::Version version, dwgBufferW *buf, | |||
| 4621 | dwgBufferW *handleBuf) { | |||
| 4622 | if (buf == nullptr || reactorHandles.size() > dwgSafety::MaxReactorCount || | |||
| 4623 | (version != DRW::AC1015 && version != DRW::AC1018 && | |||
| 4624 | version != DRW::AC1021 && | |||
| 4625 | version != DRW::AC1024 && version != DRW::AC1027 && | |||
| 4626 | version != DRW::AC1032)) return false; | |||
| 4627 | ||||
| 4628 | // For AC1024, handles are directed to handleBuf (the separate handle section); | |||
| 4629 | // for AC1015/AC1018, handles go into buf alongside the data. | |||
| 4630 | dwgBufferW *hb = (handleBuf != nullptr) ? handleBuf : buf; | |||
| 4631 | ||||
| 4632 | // Owner handle is present only when encodeDwgCommon emitted entmode=0. | |||
| 4633 | if (parentHandle != DRW::NoHandle) { | |||
| 4634 | dwgHandle owner; | |||
| 4635 | owner.code = 4; // soft pointer owner, read via getOffsetHandle() | |||
| 4636 | owner.ref = parentHandle; | |||
| 4637 | owner.size = 0; | |||
| 4638 | std::uint32_t t = parentHandle; | |||
| 4639 | while (t != 0) { t >>= 8; ++owner.size; } | |||
| 4640 | hb->putHandle(owner); | |||
| 4641 | } | |||
| 4642 | ||||
| 4643 | // Reactor handles (2a.2): emitted before xdic, one per numReactors written | |||
| 4644 | // in the DATA section, as ABSOLUTE handles (reader uses getHandle()). Empty | |||
| 4645 | // reactorHandles → nothing emitted → byte-identical to legacy. | |||
| 4646 | #if LIBDXFRW_FULL_COMMON_HEADER1 | |||
| 4647 | for (std::uint32_t ref : reactorHandles) { | |||
| 4648 | dwgHandle rh; | |||
| 4649 | rh.code = 4; // soft pointer | |||
| 4650 | rh.ref = ref; | |||
| 4651 | rh.size = 0; | |||
| 4652 | if (ref != 0) { std::uint32_t t = ref; while (t != 0) { t >>= 8; ++rh.size; } } | |||
| 4653 | hb->putHandle(rh); | |||
| 4654 | } | |||
| 4655 | #endif | |||
| 4656 | ||||
| 4657 | // XDic handle — xDictFlag=0 in the DATA section means the reader reads one | |||
| 4658 | // XDicObj handle here: emit the real handle when xDictHandle!=0, else the | |||
| 4659 | // null handle (matching the legacy byte-for-byte for the empty case). | |||
| 4660 | dwgHandle xDic; | |||
| 4661 | xDic.code = 3; | |||
| 4662 | #if LIBDXFRW_FULL_COMMON_HEADER1 | |||
| 4663 | xDic.ref = xDictHandle; | |||
| 4664 | xDic.size = 0; | |||
| 4665 | if (xDictHandle != 0) { | |||
| 4666 | std::uint32_t t = xDictHandle; while (t != 0) { t >>= 8; ++xDic.size; } | |||
| 4667 | } | |||
| 4668 | #else | |||
| 4669 | xDic.ref = 0; | |||
| 4670 | xDic.size = 0; | |||
| 4671 | #endif | |||
| 4672 | hb->putHandle(xDic); | |||
| 4673 | ||||
| 4674 | // R2004+ stores the optional AcDbColor reference after the common owner, | |||
| 4675 | // reactor, and xdictionary handles. Keep this order aligned with the | |||
| 4676 | // reader and the cross-project handle-stream contract. | |||
| 4677 | if (version > DRW::AC1015 && hasAcDbColorH) | |||
| 4678 | putHardPointerHandle(hb, acDbColorHandle); | |||
| 4679 | ||||
| 4680 | // Layer handle (R2000+ unconditional). Hard pointer. | |||
| 4681 | dwgHandle lH; | |||
| 4682 | lH.code = layerH.ref == 0 ? 0 : 5; // 5 = hard pointer for layer ref | |||
| 4683 | lH.ref = layerH.ref; | |||
| 4684 | lH.size = 0; | |||
| 4685 | if (lH.ref != 0) { | |||
| 4686 | std::uint32_t t = lH.ref; | |||
| 4687 | while (t != 0) { t >>= 8; ++lH.size; } | |||
| 4688 | } | |||
| 4689 | hb->putHandle(lH); | |||
| 4690 | ||||
| 4691 | // ltFlags=3 → lTypeH (hard pointer, code 5) present; else omit. | |||
| 4692 | if (ltFlags == 3) { | |||
| 4693 | dwgHandle ltH; | |||
| 4694 | ltH.code = lTypeH.ref == 0 ? 0 : 5; | |||
| 4695 | ltH.ref = lTypeH.ref; | |||
| 4696 | ltH.size = 0; | |||
| 4697 | if (ltH.ref != 0) { | |||
| 4698 | std::uint32_t t = ltH.ref; | |||
| 4699 | while (t != 0) { t >>= 8; ++ltH.size; } | |||
| 4700 | } | |||
| 4701 | hb->putHandle(ltH); | |||
| 4702 | } | |||
| 4703 | auto putHardPointer = [hb](std::uint32_t ref) { | |||
| 4704 | dwgHandle h; | |||
| 4705 | h.code = ref == 0 ? 0 : 5; | |||
| 4706 | h.ref = ref; | |||
| 4707 | h.size = 0; | |||
| 4708 | if (ref != 0) { | |||
| 4709 | std::uint32_t t = ref; | |||
| 4710 | while (t != 0) { | |||
| 4711 | t >>= 8; | |||
| 4712 | ++h.size; | |||
| 4713 | } | |||
| 4714 | } | |||
| 4715 | hb->putHandle(h); | |||
| 4716 | }; | |||
| 4717 | ||||
| 4718 | if (version > DRW::AC1018) { | |||
| 4719 | if (materialFlag == 3) | |||
| 4720 | putHardPointer(material); | |||
| 4721 | if (shadowFlag == 3) | |||
| 4722 | putHardPointer(shadowHandle); | |||
| 4723 | } | |||
| 4724 | if (plotFlags == 3) | |||
| 4725 | putHardPointer(static_cast<std::uint32_t>(plotStyle)); | |||
| 4726 | if (version > DRW::AC1021) { | |||
| 4727 | if (hasFullVisualStyle) | |||
| 4728 | putHardPointer(fullVisualStyleHandle); | |||
| 4729 | if (hasFaceVisualStyle) | |||
| 4730 | putHardPointer(faceVisualStyleHandle); | |||
| 4731 | if (hasEdgeVisualStyle) | |||
| 4732 | putHardPointer(edgeVisualStyleHandle); | |||
| 4733 | } | |||
| 4734 | ||||
| 4735 | return buf->isGood() && hb->isGood(); | |||
| 4736 | } | |||
| 4737 | ||||
| 4738 | bool DRW_Point::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 4739 | (void)bs; (void)strBuf; | |||
| 4740 | oType = 27; // POINT class id — see dwgreader.cpp:1111 dispatch | |||
| 4741 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 4742 | ||||
| 4743 | // Point body — mirror of DRW_Point::parseDwg below. | |||
| 4744 | buf->putBitDouble(basePoint.x); | |||
| 4745 | buf->putBitDouble(basePoint.y); | |||
| 4746 | buf->putBitDouble(basePoint.z); | |||
| 4747 | buf->putThickness(thickness, /*b_R2000_style=*/true); | |||
| 4748 | buf->putExtrusion(extPoint, /*b_R2000_style=*/true); | |||
| 4749 | buf->putBitDouble(xAxisAngle); // ODA §20.4.31 code 50 | |||
| 4750 | ||||
| 4751 | return encodeDwgEntHandle(version, buf, handleBuf); | |||
| 4752 | } | |||
| 4753 | ||||
| 4754 | void DRW_Point::resetDwgState() { | |||
| 4755 | DRW_Entity::reset(); | |||
| 4756 | basePoint = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 4757 | thickness = 0.0; | |||
| 4758 | extPoint = DRW_Coord{0.0, 0.0, 1.0}; | |||
| 4759 | xAxisAngle = 0.0; | |||
| 4760 | } | |||
| 4761 | ||||
| 4762 | bool DRW_Point::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){ | |||
| 4763 | resetDwgState(); | |||
| 4764 | dwgBuffer *sourceBuf = buf; | |||
| 4765 | auto fail = [this, sourceBuf]() { | |||
| 4766 | if (sourceBuf != nullptr) | |||
| 4767 | sourceBuf->invalidate(); | |||
| 4768 | resetDwgState(); | |||
| 4769 | return false; | |||
| 4770 | }; | |||
| 4771 | if (sourceBuf == nullptr) | |||
| 4772 | return fail(); | |||
| 4773 | ||||
| 4774 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 4775 | if (!DRW_Entity::parseDwgCommon(version, &bodyProbe, bs) | |||
| 4776 | || !bodyProbe.isGood()) | |||
| 4777 | return fail(); | |||
| 4778 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 4779 | DRW_Coord parsedBasePoint; | |||
| 4780 | DRW_Coord parsedExtrusion; | |||
| 4781 | double parsedThickness = 0.0; | |||
| 4782 | double parsedXAxisAngle = 0.0; | |||
| 4783 | if (!readBoundedBitCoord(bodyProbe, bodyEndBit, parsedBasePoint) | |||
| 4784 | || !readBoundedThickness(bodyProbe, bodyEndBit, | |||
| 4785 | version > DRW::AC1014, parsedThickness) | |||
| 4786 | || !readBoundedExtrusion(bodyProbe, bodyEndBit, | |||
| 4787 | version > DRW::AC1014, parsedExtrusion) | |||
| 4788 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, parsedXAxisAngle) | |||
| 4789 | || !std::isfinite(parsedBasePoint.x) | |||
| 4790 | || !std::isfinite(parsedBasePoint.y) | |||
| 4791 | || !std::isfinite(parsedBasePoint.z) | |||
| 4792 | || !std::isfinite(parsedThickness) | |||
| 4793 | || !std::isfinite(parsedExtrusion.x) | |||
| 4794 | || !std::isfinite(parsedExtrusion.y) | |||
| 4795 | || !std::isfinite(parsedExtrusion.z) | |||
| 4796 | || !std::isfinite(parsedXAxisAngle)) | |||
| 4797 | return fail(); | |||
| 4798 | ||||
| 4799 | std::uint64_t handleEndBit = 0; | |||
| 4800 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, | |||
| 4801 | handleEndBit)) | |||
| 4802 | return fail(); | |||
| 4803 | dwgBuffer handleProbe = bodyProbe.forkIndependent(); | |||
| 4804 | if (!DRW_Entity::parseDwgEntHandle(version, &handleProbe, true, | |||
| 4805 | handleEndBit) | |||
| 4806 | || !handleProbe.isGood()) | |||
| 4807 | return fail(); | |||
| 4808 | ||||
| 4809 | basePoint = parsedBasePoint; | |||
| 4810 | thickness = parsedThickness; | |||
| 4811 | extPoint = parsedExtrusion; | |||
| 4812 | xAxisAngle = parsedXAxisAngle; | |||
| 4813 | *sourceBuf = handleProbe; | |||
| 4814 | return true; | |||
| 4815 | } | |||
| 4816 | ||||
| 4817 | void DRW_Line::resetDwgState() { | |||
| 4818 | DRW_Point::resetDwgState(); | |||
| 4819 | secPoint = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 4820 | } | |||
| 4821 | ||||
| 4822 | bool DRW_Line::parseCode(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 4823 | switch (code) { | |||
| 4824 | case 11: | |||
| 4825 | secPoint.x = reader->getDouble(); | |||
| 4826 | break; | |||
| 4827 | case 21: | |||
| 4828 | secPoint.y = reader->getDouble(); | |||
| 4829 | break; | |||
| 4830 | case 31: | |||
| 4831 | secPoint.z = reader->getDouble(); | |||
| 4832 | break; | |||
| 4833 | default: | |||
| 4834 | return DRW_Point::parseCode(code, reader); | |||
| 4835 | } | |||
| 4836 | ||||
| 4837 | return true; | |||
| 4838 | } | |||
| 4839 | ||||
| 4840 | bool DRW_Line::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 4841 | (void)bs; (void)strBuf; | |||
| 4842 | oType = 19; // LINE class id — see dwgreader.cpp:1105 | |||
| 4843 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 4844 | ||||
| 4845 | // R2000+ Line body — zIsZero shortcut: if both z's are 0, omit the | |||
| 4846 | // z fields entirely. Reader reads `zIsZero` first, then RD x + | |||
| 4847 | // DD secX (default = x), RD y + DD secY (default = y), and | |||
| 4848 | // conditionally RD z + DD secZ. Our putDefaultDouble always emits | |||
| 4849 | // the full RD via code 0b11; reader's getDefaultDouble with code | |||
| 4850 | // 0b11 returns the raw double. | |||
| 4851 | bool zIsZero = (basePoint.z == 0.0 && secPoint.z == 0.0); | |||
| 4852 | buf->putBit(zIsZero ? 1 : 0); | |||
| 4853 | buf->putRawDouble(basePoint.x); | |||
| 4854 | buf->putDefaultDouble(basePoint.x, secPoint.x); | |||
| 4855 | buf->putRawDouble(basePoint.y); | |||
| 4856 | buf->putDefaultDouble(basePoint.y, secPoint.y); | |||
| 4857 | if (!zIsZero) { | |||
| 4858 | buf->putRawDouble(basePoint.z); | |||
| 4859 | buf->putDefaultDouble(basePoint.z, secPoint.z); | |||
| 4860 | } | |||
| 4861 | buf->putThickness(thickness, /*b_R2000_style=*/true); | |||
| 4862 | buf->putExtrusion(extPoint, /*b_R2000_style=*/true); | |||
| 4863 | ||||
| 4864 | return encodeDwgEntHandle(version, buf, handleBuf); | |||
| 4865 | } | |||
| 4866 | ||||
| 4867 | bool DRW_3DLine::parseDwg(DRW::Version version, dwgBuffer *buf, | |||
| 4868 | std::uint32_t bs) { | |||
| 4869 | resetDwgState(); | |||
| 4870 | dwgBuffer *sourceBuf = buf; | |||
| 4871 | auto fail = [this, sourceBuf]() { | |||
| 4872 | if (sourceBuf != nullptr) | |||
| 4873 | sourceBuf->invalidate(); | |||
| 4874 | resetDwgState(); | |||
| 4875 | return false; | |||
| 4876 | }; | |||
| 4877 | if (sourceBuf == nullptr) | |||
| 4878 | return fail(); | |||
| 4879 | ||||
| 4880 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 4881 | if (!DRW_Entity::parseDwgCommon(version, &bodyProbe, bs) | |||
| 4882 | || !bodyProbe.isGood()) | |||
| 4883 | return fail(); | |||
| 4884 | ||||
| 4885 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 4886 | double values[10]{}; | |||
| 4887 | for (double& value : values) { | |||
| 4888 | if (!readBoundedRawDouble(bodyProbe, bodyEndBit, value) | |||
| 4889 | || !std::isfinite(value)) | |||
| 4890 | return fail(); | |||
| 4891 | } | |||
| 4892 | ||||
| 4893 | std::uint64_t handleEndBit = 0; | |||
| 4894 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, | |||
| 4895 | handleEndBit)) | |||
| 4896 | return fail(); | |||
| 4897 | dwgBuffer handleProbe = bodyProbe.forkIndependent(); | |||
| 4898 | if (!DRW_Entity::parseDwgEntHandle(version, &handleProbe, true, | |||
| 4899 | handleEndBit) | |||
| 4900 | || !handleProbe.isGood()) | |||
| 4901 | return fail(); | |||
| 4902 | ||||
| 4903 | basePoint = DRW_Coord{values[0], values[1], values[2]}; | |||
| 4904 | secPoint = DRW_Coord{values[3], values[4], values[5]}; | |||
| 4905 | extPoint = DRW_Coord{values[6], values[7], values[8]}; | |||
| 4906 | thickness = values[9]; | |||
| 4907 | *sourceBuf = handleProbe; | |||
| 4908 | return true; | |||
| 4909 | } | |||
| 4910 | ||||
| 4911 | bool DRW_3DLine::encodeDwg(DRW::Version version, dwgBufferW *buf, | |||
| 4912 | std::uint32_t bs, dwgBufferW *strBuf, | |||
| 4913 | dwgBufferW *handleBuf) { | |||
| 4914 | (void)bs; | |||
| 4915 | if (version < DRW::AC1015 || buf == nullptr) | |||
| 4916 | return false; | |||
| 4917 | ||||
| 4918 | // 3DLINE is a modern custom class. Its class ordinal is writer-local, | |||
| 4919 | // while the body remains the fixed raw-double layout used by the reader. | |||
| 4920 | oType = kDwgClassNum; | |||
| 4921 | if (!encodeDwgCommon(version, buf, strBuf)) | |||
| 4922 | return false; | |||
| 4923 | ||||
| 4924 | for (const double coordinate : {basePoint.x, basePoint.y, basePoint.z, | |||
| 4925 | secPoint.x, secPoint.y, secPoint.z, | |||
| 4926 | extPoint.x, extPoint.y, extPoint.z, | |||
| 4927 | thickness}) { | |||
| 4928 | buf->putRawDouble(coordinate); | |||
| 4929 | } | |||
| 4930 | ||||
| 4931 | return encodeDwgEntHandle(version, buf, handleBuf); | |||
| 4932 | } | |||
| 4933 | ||||
| 4934 | bool DRW_Circle::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 4935 | (void)bs; (void)strBuf; | |||
| 4936 | oType = 18; // CIRCLE class id — see dwgreader.cpp:1099 | |||
| 4937 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 4938 | ||||
| 4939 | // Circle body — mirror of DRW_Circle::parseDwg. | |||
| 4940 | buf->putBitDouble(basePoint.x); | |||
| 4941 | buf->putBitDouble(basePoint.y); | |||
| 4942 | buf->putBitDouble(basePoint.z); | |||
| 4943 | buf->putBitDouble(radious); | |||
| 4944 | buf->putThickness(thickness, /*b_R2000_style=*/true); | |||
| 4945 | buf->putExtrusion(extPoint, /*b_R2000_style=*/true); | |||
| 4946 | ||||
| 4947 | return encodeDwgEntHandle(version, buf, handleBuf); | |||
| 4948 | } | |||
| 4949 | ||||
| 4950 | bool DRW_Ray::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 4951 | (void)bs; (void)strBuf; | |||
| 4952 | // Ray = 40, Xline = 41 — derive from runtime type so DRW_Xline can | |||
| 4953 | // share this encoder (it inherits from DRW_Ray). | |||
| 4954 | oType = (eType == DRW::XLINE) ? 41 : 40; | |||
| 4955 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 4956 | ||||
| 4957 | // 3 BD basePoint + 3 BD vector — same layout as parseDwg. | |||
| 4958 | buf->putBitDouble(basePoint.x); | |||
| 4959 | buf->putBitDouble(basePoint.y); | |||
| 4960 | buf->putBitDouble(basePoint.z); | |||
| 4961 | buf->putBitDouble(secPoint.x); | |||
| 4962 | buf->putBitDouble(secPoint.y); | |||
| 4963 | buf->putBitDouble(secPoint.z); | |||
| 4964 | ||||
| 4965 | return encodeDwgEntHandle(version, buf, handleBuf); | |||
| 4966 | } | |||
| 4967 | ||||
| 4968 | bool DRW_Trace::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 4969 | (void)bs; (void)strBuf; | |||
| 4970 | oType = 32; // TRACE = 32 — see dwgreader.cpp:1317 | |||
| 4971 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 4972 | ||||
| 4973 | // Trace body — mirror of parseDwg. Note the unusual layout: | |||
| 4974 | // thickness FIRST, then elevation (basePoint.z) as BD, then 4 | |||
| 4975 | // corners as 2RD (z values share basePoint.z). | |||
| 4976 | buf->putThickness(thickness, /*b_R2000_style=*/true); | |||
| 4977 | buf->putBitDouble(basePoint.z); | |||
| 4978 | buf->putRawDouble(basePoint.x); | |||
| 4979 | buf->putRawDouble(basePoint.y); | |||
| 4980 | buf->putRawDouble(secPoint.x); | |||
| 4981 | buf->putRawDouble(secPoint.y); | |||
| 4982 | buf->putRawDouble(thirdPoint.x); | |||
| 4983 | buf->putRawDouble(thirdPoint.y); | |||
| 4984 | buf->putRawDouble(fourPoint.x); | |||
| 4985 | buf->putRawDouble(fourPoint.y); | |||
| 4986 | buf->putExtrusion(extPoint, /*b_R2000_style=*/true); | |||
| 4987 | ||||
| 4988 | return encodeDwgEntHandle(version, buf, handleBuf); | |||
| 4989 | } | |||
| 4990 | ||||
| 4991 | bool DRW_Spline::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 4992 | (void)bs; (void)strBuf; | |||
| 4993 | if (buf == nullptr || !validatePayloadFields()) | |||
| 4994 | return false; | |||
| 4995 | oType = 36; // SPLINE class id — see dwgreader.cpp:1329 | |||
| 4996 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 4997 | encodeDwgSplineBody(version, buf); | |||
| 4998 | return encodeDwgEntHandle(version, buf, handleBuf); | |||
| 4999 | } | |||
| 5000 | ||||
| 5001 | // Spline body encode: the scenario/degree/knots/ctrl/fit section, WITHOUT the | |||
| 5002 | // leading encodeDwgCommon or the trailing encodeDwgEntHandle. Factored out so | |||
| 5003 | // DRW_Helix::encodeDwg can reuse the identical payload (Phase 8a-1). | |||
| 5004 | // Omits the DXF-only flag70/extrusion (210-230) which the DWG stream never | |||
| 5005 | // carries here. | |||
| 5006 | void DRW_Spline::encodeDwgSplineBody(DRW::Version version, dwgBufferW *buf) const { | |||
| 5007 | // Scenario: | |||
| 5008 | // 1 = control-point / rational / planar (uses knots + control + weights) | |||
| 5009 | // 2 = fit-point (uses fit points + tangents + tolerance) | |||
| 5010 | // When both lists are populated (e.g. DXF-sourced splines), prefer scenario 1 | |||
| 5011 | // (ctrl + knots) and drop the fit list from the DWG stream — scenario 1 has no | |||
| 5012 | // fit-point section, so writing both would corrupt all subsequent entities. | |||
| 5013 | const bool hasFit = !fitlist.empty(); | |||
| 5014 | const bool hasCtrl = !controllist.empty(); | |||
| 5015 | std::int32_t scenario = (hasFit && !hasCtrl) ? 2 : 1; | |||
| 5016 | if (m_scenario == 1 && hasCtrl) { | |||
| 5017 | scenario = 1; | |||
| 5018 | } else if (m_scenario == 2 && hasFit) { | |||
| 5019 | scenario = 2; | |||
| 5020 | } | |||
| 5021 | buf->putBitLong(scenario); | |||
| 5022 | if (version > DRW::AC1024) { | |||
| 5023 | // splFlag1 bit 0: method = fit points; bit 2: closed; | |||
| 5024 | // bit 3: knotParam participates in R2013+ scenario selection. | |||
| 5025 | std::int32_t splFlag1 = m_splineFlags1; | |||
| 5026 | splFlag1 &= ~(kSplineFlagMethodFitPoints | kSplineFlagUseKnotParameter | kSplineFlagClosed); | |||
| 5027 | if (scenario == 2) { | |||
| 5028 | splFlag1 |= kSplineFlagMethodFitPoints | kSplineFlagUseKnotParameter; | |||
| 5029 | if (flags & 0x01) splFlag1 |= kSplineFlagClosed; | |||
| 5030 | } else { | |||
| 5031 | if (flags & 0x01) splFlag1 |= kSplineFlagClosed; | |||
| 5032 | } | |||
| 5033 | buf->putBitLong(splFlag1); | |||
| 5034 | std::int32_t knotParam = m_knotParam; | |||
| 5035 | if (scenario == 1) { | |||
| 5036 | knotParam = kSplineKnotParamCustom; | |||
| 5037 | } else if (knotParam == kSplineKnotParamCustom) { | |||
| 5038 | knotParam = 0; | |||
| 5039 | } | |||
| 5040 | buf->putBitLong(knotParam); | |||
| 5041 | } | |||
| 5042 | buf->putBitLong(static_cast<std::int32_t>(degree)); | |||
| 5043 | ||||
| 5044 | if (scenario == 2) { | |||
| 5045 | buf->putBitDouble(tolfit); | |||
| 5046 | buf->put3BitDouble(tgStart); | |||
| 5047 | buf->put3BitDouble(tgEnd); | |||
| 5048 | const std::int32_t nFit = static_cast<std::int32_t>(fitlist.size()); | |||
| 5049 | buf->putBitLong(nFit); | |||
| 5050 | } else { | |||
| 5051 | // scenario == 1 | |||
| 5052 | // Reader at parseDwg reads three flag bits in this order: | |||
| 5053 | // rational bit (flags bit 2 → 0x04) | |||
| 5054 | // closed bit (flags bit 0 → 0x01) | |||
| 5055 | // periodic bit (flags bit 1 → 0x02) | |||
| 5056 | const bool hasNonDefaultWeights = std::any_of(weightlist.begin(), weightlist.end(), differsFromUnitWeight); | |||
| 5057 | buf->putBit(((flags & 0x4) || hasNonDefaultWeights) ? 1 : 0); // rational | |||
| 5058 | buf->putBit((flags & 0x1) ? 1 : 0); // closed | |||
| 5059 | buf->putBit((flags & 0x2) ? 1 : 0); // periodic | |||
| 5060 | buf->putBitDouble(tolknot); | |||
| 5061 | buf->putBitDouble(tolcontrol); | |||
| 5062 | const std::int32_t nKnots = static_cast<std::int32_t>(knotslist.size()); | |||
| 5063 | const std::int32_t nCtrl = static_cast<std::int32_t>(controllist.size()); | |||
| 5064 | buf->putBitLong(nKnots); | |||
| 5065 | buf->putBitLong(nCtrl); | |||
| 5066 | // weight bit: caller populates weightlist when each control point | |||
| 5067 | // has a non-default weight (NURBS conics). | |||
| 5068 | bool hasWeights = !weightlist.empty(); | |||
| 5069 | buf->putBit(hasWeights ? 1 : 0); | |||
| 5070 | } | |||
| 5071 | ||||
| 5072 | // Data sections are scenario-gated to avoid stream corruption: | |||
| 5073 | // parseDwg reads knots+ctrl only for scenario 1, fit only for scenario 2. | |||
| 5074 | if (scenario == 1) { | |||
| 5075 | for (double k : knotslist) buf->putBitDouble(k); | |||
| 5076 | for (size_t i = 0; i < controllist.size(); ++i) { | |||
| 5077 | buf->put3BitDouble(*controllist[i]); | |||
| 5078 | if (!weightlist.empty()) { | |||
| 5079 | double w = (i < weightlist.size()) ? weightlist[i] : 1.0; | |||
| 5080 | buf->putBitDouble(w); | |||
| 5081 | } | |||
| 5082 | } | |||
| 5083 | } else { | |||
| 5084 | for (const auto& fp : fitlist) buf->put3BitDouble(*fp); | |||
| 5085 | } | |||
| 5086 | } | |||
| 5087 | ||||
| 5088 | // DRW_Helix::encodeDwg — spline body (oType = HELIX class 503) + AcDbHelix | |||
| 5089 | // trailer, then the common entity handle data. Trailer field order MUST match | |||
| 5090 | // DRW_Helix::parseDwg (Phase 8a-1). | |||
| 5091 | bool DRW_Helix::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 5092 | (void)bs; (void)strBuf; | |||
| 5093 | const auto finite = [](const DRW_Coord& point) { | |||
| 5094 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 5095 | && std::isfinite(point.z); | |||
| 5096 | }; | |||
| 5097 | if (buf == nullptr || !validatePayloadFields() | |||
| 5098 | || !finite(axisBasePt) || !finite(startPt) || !finite(axisVector) | |||
| 5099 | || !std::isfinite(radius) || !std::isfinite(turns) | |||
| 5100 | || !std::isfinite(turnHeight)) | |||
| 5101 | return false; | |||
| 5102 | oType = kDwgClassNum; // HELIX custom class 503 | |||
| 5103 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 5104 | encodeDwgSplineBody(version, buf); | |||
| 5105 | ||||
| 5106 | // AcDbHelix trailer (same order as parseDwg): | |||
| 5107 | buf->putBitLong(m_majorVersion); | |||
| 5108 | buf->putBitLong(m_maintVersion); | |||
| 5109 | buf->put3BitDouble(axisBasePt); | |||
| 5110 | buf->put3BitDouble(startPt); | |||
| 5111 | buf->put3BitDouble(axisVector); | |||
| 5112 | buf->putBitDouble(radius); | |||
| 5113 | buf->putBitDouble(turns); | |||
| 5114 | buf->putBitDouble(turnHeight); | |||
| 5115 | buf->putBit(handedness ? 1 : 0); | |||
| 5116 | buf->putRawChar8(static_cast<std::uint8_t>(constraintType)); | |||
| 5117 | ||||
| 5118 | return encodeDwgEntHandle(version, buf, handleBuf); | |||
| 5119 | } | |||
| 5120 | ||||
| 5121 | bool DRW_MText::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 5122 | (void)bs; | |||
| 5123 | oType = 44; // MTEXT class id — see dwgreader.cpp:1215 | |||
| 5124 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 5125 | ||||
| 5126 | // R2000/R2004/R2010 MTEXT body — mirror of DRW_MText::parseDwg. | |||
| 5127 | buf->put3BitDouble(basePoint); // insertion | |||
| 5128 | buf->put3BitDouble(extPoint); // extrusion | |||
| 5129 | buf->put3BitDouble(secPoint); // X-axis dir | |||
| 5130 | buf->putBitDouble(widthscale); // rect width | |||
| 5131 | if (version > DRW::AC1018) { | |||
| 5132 | buf->putBitDouble(0.0); // rect height, R2007+ | |||
| 5133 | } | |||
| 5134 | buf->putBitDouble(height); // text height | |||
| 5135 | buf->putBitShort(static_cast<std::uint16_t>(textgen)); // attachment | |||
| 5136 | buf->putBitShort(static_cast<std::uint16_t>(alignH)); // drawing dir | |||
| 5137 | buf->putBitDouble(0.0); // ext_ht (extents height; undocumented) | |||
| 5138 | buf->putBitDouble(0.0); // ext_wid (extents width; undocumented) | |||
| 5139 | // For AC1024: text goes to string buffer; for AC1015/AC1018: inline. | |||
| 5140 | (strBuf ? strBuf : buf)->putVariableText(version, text); | |||
| 5141 | // R2000+ extras: | |||
| 5142 | buf->putBitShort(linespacingStyle); // linespacing style BS 73 | |||
| 5143 | buf->putBitDouble(interlin); // linespacing factor BD | |||
| 5144 | buf->putBit(0); // unknown bit | |||
| 5145 | if (version > DRW::AC1015) { // R2004+: background flags BL | |||
| 5146 | buf->putBitLong(m_backgroundFlags); | |||
| 5147 | if ((m_backgroundFlags & 0x01) || (version >= DRW::AC1032 && (m_backgroundFlags & 0x10))) { | |||
| 5148 | buf->putBitDouble(m_backgroundScale); // BitDouble (matches the read fix) | |||
| 5149 | buf->putCmColor(version, static_cast<std::uint16_t>(m_backgroundColor)); | |||
| 5150 | buf->putBitLong(m_backgroundTransparency); | |||
| 5151 | } | |||
| 5152 | } | |||
| 5153 | if (version >= DRW::AC1032) { | |||
| 5154 | buf->putBit(m_r2018IsNotAnnotative ? 1 : 0); | |||
| 5155 | if (m_r2018IsNotAnnotative) { | |||
| 5156 | buf->putBitShort(m_r2018Version); | |||
| 5157 | buf->putBit(m_r2018DefaultFlag ? 1 : 0); | |||
| 5158 | buf->putBitLong(m_r2018Attachment); | |||
| 5159 | buf->put3BitDouble(m_r2018XAxisDir); | |||
| 5160 | buf->put3BitDouble(m_r2018InsertionPoint); | |||
| 5161 | buf->putBitDouble(m_r2018RectWidth); | |||
| 5162 | buf->putBitDouble(m_r2018RectHeight); | |||
| 5163 | buf->putBitDouble(m_r2018ExtentsHeight); | |||
| 5164 | buf->putBitDouble(m_r2018ExtentsWidth); | |||
| 5165 | if (m_r2018ColumnType > 2 | |||
| 5166 | || m_r2018ColumnCount < 0 | |||
| 5167 | || m_r2018ColumnCount > kMaxMTextColumnHeights | |||
| 5168 | || m_r2018ColumnHeights.size() | |||
| 5169 | > static_cast<std::size_t>(kMaxMTextColumnHeights)) | |||
| 5170 | return false; | |||
| 5171 | buf->putBitShort(m_r2018ColumnType); | |||
| 5172 | if (m_r2018ColumnType != 0) { | |||
| 5173 | std::int32_t columnCount = m_r2018ColumnCount; | |||
| 5174 | if (!m_r2018ColumnAutoHeight && m_r2018ColumnType == 2 | |||
| 5175 | && !m_r2018ColumnHeights.empty()) { | |||
| 5176 | columnCount = static_cast<std::int32_t>(m_r2018ColumnHeights.size()); | |||
| 5177 | } | |||
| 5178 | if (!m_r2018ColumnAutoHeight && m_r2018ColumnType == 2 | |||
| 5179 | && static_cast<std::size_t>(columnCount) | |||
| 5180 | != m_r2018ColumnHeights.size()) | |||
| 5181 | return false; | |||
| 5182 | buf->putBitLong(columnCount); | |||
| 5183 | buf->putBitDouble(m_r2018ColumnWidth); | |||
| 5184 | buf->putBitDouble(m_r2018ColumnGutter); | |||
| 5185 | buf->putBit(m_r2018ColumnAutoHeight ? 1 : 0); | |||
| 5186 | buf->putBit(m_r2018ColumnFlowReversed ? 1 : 0); | |||
| 5187 | if (!m_r2018ColumnAutoHeight && m_r2018ColumnType == 2) { | |||
| 5188 | for (std::int32_t i = 0; i < columnCount; ++i) { | |||
| 5189 | const double columnHeight = static_cast<size_t>(i) < m_r2018ColumnHeights.size() | |||
| 5190 | ? m_r2018ColumnHeights[static_cast<size_t>(i)] | |||
| 5191 | : 0.0; | |||
| 5192 | buf->putBitDouble(columnHeight); | |||
| 5193 | } | |||
| 5194 | } | |||
| 5195 | } | |||
| 5196 | } | |||
| 5197 | } | |||
| 5198 | ||||
| 5199 | if (!encodeDwgEntHandle(version, buf, handleBuf)) return false; | |||
| 5200 | ||||
| 5201 | // styleH — hard pointer to STYLE table record (default STANDARD). | |||
| 5202 | dwgBufferW *hb = handleBuf ? handleBuf : buf; | |||
| 5203 | putHardPointerHandle(hb, (styleH.ref == 0) ? 0x13 : styleH.ref); | |||
| 5204 | if (version >= DRW::AC1032 && m_r2018IsNotAnnotative) | |||
| 5205 | putHardPointerHandle(hb, (m_r2018AppIdHandle == 0) ? 0x14 : m_r2018AppIdHandle); | |||
| 5206 | return buf->isGood() && hb->isGood(); | |||
| 5207 | } | |||
| 5208 | ||||
| 5209 | bool DRW_Insert::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 5210 | (void)bs; (void)strBuf; | |||
| 5211 | if (buf == nullptr) | |||
| 5212 | return false; | |||
| 5213 | const bool hasAttrib = !attribHandles.empty(); | |||
| 5214 | if (!hasAttrib) { | |||
| 5215 | if (seqendH.ref != DRW::NoHandle) | |||
| 5216 | return false; | |||
| 5217 | } else { | |||
| 5218 | if (seqendH.ref == DRW::NoHandle) | |||
| 5219 | return false; | |||
| 5220 | if (version < DRW::AC1018) { | |||
| 5221 | if (attribHandles.size() != 2 || | |||
| 5222 | (attribHandles.front().ref == DRW::NoHandle) != | |||
| 5223 | (attribHandles.back().ref == DRW::NoHandle)) { | |||
| 5224 | return false; | |||
| 5225 | } | |||
| 5226 | } else if (std::any_of(attribHandles.cbegin(), attribHandles.cend(), | |||
| 5227 | [](const dwgHandle& handle) { | |||
| 5228 | return handle.ref == DRW::NoHandle; | |||
| 5229 | })) { | |||
| 5230 | return false; | |||
| 5231 | } | |||
| 5232 | } | |||
| 5233 | if (attribHandles.size() > static_cast<std::size_t>(std::numeric_limits<std::int32_t>::max())) | |||
| 5234 | return false; | |||
| 5235 | ||||
| 5236 | // 2b.6: emit MINSERT (oType 8) when a column/row grid is present; | |||
| 5237 | // otherwise a plain INSERT (oType 7). The reader keys the grid block off | |||
| 5238 | // oType==8 (parseDwg :3189). | |||
| 5239 | oType = isMInsert() ? 8 : 7; | |||
| 5240 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 5241 | ||||
| 5242 | // INSERT body — mirror of DRW_Insert::parseDwg for R2000. | |||
| 5243 | buf->putBitDouble(basePoint.x); | |||
| 5244 | buf->putBitDouble(basePoint.y); | |||
| 5245 | buf->putBitDouble(basePoint.z); | |||
| 5246 | ||||
| 5247 | // dataFlags: pick the most compact form based on actual scales. | |||
| 5248 | // 3 → all scales default to 1.0 (no emit) | |||
| 5249 | // 2 → uniform scale (xscale RD only; yscale=zscale=xscale) | |||
| 5250 | // 1 → xscale defaults to 1, yscale/zscale as DD against xscale | |||
| 5251 | // 0 → xscale RD; yscale/zscale as DD against xscale | |||
| 5252 | if (sameStoredDouble(xscale, 1.0) && sameStoredDouble(yscale, 1.0) | |||
| 5253 | && sameStoredDouble(zscale, 1.0)) { | |||
| 5254 | buf->put2Bits(3); | |||
| 5255 | } else if (sameStoredDouble(xscale, yscale) && sameStoredDouble(yscale, zscale)) { | |||
| 5256 | buf->put2Bits(2); | |||
| 5257 | buf->putRawDouble(xscale); | |||
| 5258 | } else if (sameStoredDouble(xscale, 1.0)) { | |||
| 5259 | // xscale is exactly 1.0 (parseDwg leaves it at its 1.0 default and | |||
| 5260 | // never reads it in this branch), so it can be omitted; y and z are | |||
| 5261 | // independent and go through the same DD-against-1.0 path parseDwg | |||
| 5262 | // reads them with. | |||
| 5263 | buf->put2Bits(1); | |||
| 5264 | buf->putDefaultDouble(1.0, yscale); | |||
| 5265 | buf->putDefaultDouble(1.0, zscale); | |||
| 5266 | } else { | |||
| 5267 | // Use dataFlags=0 (general case): RD x + DD y + DD z. | |||
| 5268 | buf->put2Bits(0); | |||
| 5269 | buf->putRawDouble(xscale); | |||
| 5270 | buf->putDefaultDouble(xscale, yscale); | |||
| 5271 | buf->putDefaultDouble(xscale, zscale); | |||
| 5272 | } | |||
| 5273 | ||||
| 5274 | buf->putBitDouble(angle); // radians | |||
| 5275 | buf->putExtrusion(extPoint, /*b_R2000_style=*/false); | |||
| 5276 | buf->putBit(hasAttrib ? 1 : 0); | |||
| 5277 | if (hasAttrib && version > DRW::AC1015) | |||
| 5278 | buf->putBitLong(static_cast<std::int32_t>(attribHandles.size())); | |||
| 5279 | // hasAttrib==0 ⇒ the SINCE-R2004 num_owned BL is absent (parse :3184), so | |||
| 5280 | // the MINSERT grid (oType==8) follows the hasAttrib bit directly. Field | |||
| 5281 | // order mirrors parseDwg :3190-3193 (colcount BS, rowcount BS, colspace BD, | |||
| 5282 | // rowspace BD) and libreDWG dwg.spec num_cols/num_rows/col_spacing/row_spacing. | |||
| 5283 | if (oType == 8) { // MINSERT grid | |||
| 5284 | buf->putBitShort(static_cast<std::uint16_t>(colcount)); | |||
| 5285 | buf->putBitShort(static_cast<std::uint16_t>(rowcount)); | |||
| 5286 | buf->putBitDouble(colspace); | |||
| 5287 | buf->putBitDouble(rowspace); | |||
| 5288 | } | |||
| 5289 | ||||
| 5290 | if (!encodeDwgEntHandle(version, buf, handleBuf)) return false; | |||
| 5291 | ||||
| 5292 | // BLOCK_RECORD hard pointer. | |||
| 5293 | dwgHandle bhH; | |||
| 5294 | bhH.code = (blockRecH.ref == 0) ? 0 : 5; | |||
| 5295 | bhH.ref = blockRecH.ref; | |||
| 5296 | bhH.size = 0; | |||
| 5297 | if (bhH.ref != 0) { | |||
| 5298 | std::uint32_t t = bhH.ref; | |||
| 5299 | while (t != 0) { t >>= 8; ++bhH.size; } | |||
| 5300 | } | |||
| 5301 | (handleBuf ? handleBuf : buf)->putHandle(bhH); | |||
| 5302 | ||||
| 5303 | if (hasAttrib) { | |||
| 5304 | dwgBufferW *hb = handleBuf ? handleBuf : buf; | |||
| 5305 | if (version < DRW::AC1018) { | |||
| 5306 | for (const dwgHandle& attribHandle : attribHandles) | |||
| 5307 | putDwgReference(hb, DRW::DwgSoftPointer, attribHandle.ref); | |||
| 5308 | } else { | |||
| 5309 | const std::uint8_t attributeCode = | |||
| 5310 | oType == 8 ? DRW::DwgSoftPointer : DRW::DwgHardOwnership; | |||
| 5311 | for (const dwgHandle& attribHandle : attribHandles) | |||
| 5312 | putDwgReference(hb, attributeCode, attribHandle.ref); | |||
| 5313 | } | |||
| 5314 | putDwgReference(hb, DRW::DwgHardOwnership, seqendH.ref); | |||
| 5315 | } | |||
| 5316 | return buf->isGood() && (handleBuf == nullptr || handleBuf->isGood()); | |||
| 5317 | } | |||
| 5318 | ||||
| 5319 | bool DRW_3Dface::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 5320 | (void)bs; (void)strBuf; | |||
| 5321 | oType = 28; // 3DFACE class id — see dwgreader.cpp:1237 | |||
| 5322 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 5323 | ||||
| 5324 | // R2000+ 3DFACE body — mirror of parseDwg's z_is_zero / has_no_flag | |||
| 5325 | // optimization. Reader checks `invisibleflag != NoEdge`; if NoEdge, | |||
| 5326 | // emit has_no_flag=1 to suppress the BS read. | |||
| 5327 | bool hasNoFlag = (invisibleflag == /*NoEdge*/0); | |||
| 5328 | bool zIsZero = (basePoint.z == 0.0); | |||
| 5329 | buf->putBit(hasNoFlag ? 1 : 0); | |||
| 5330 | buf->putBit(zIsZero ? 1 : 0); | |||
| 5331 | buf->putRawDouble(basePoint.x); | |||
| 5332 | buf->putRawDouble(basePoint.y); | |||
| 5333 | if (!zIsZero) buf->putRawDouble(basePoint.z); | |||
| 5334 | buf->putDefaultDouble(basePoint.x, secPoint.x); | |||
| 5335 | buf->putDefaultDouble(basePoint.y, secPoint.y); | |||
| 5336 | buf->putDefaultDouble(basePoint.z, secPoint.z); | |||
| 5337 | buf->putDefaultDouble(secPoint.x, thirdPoint.x); | |||
| 5338 | buf->putDefaultDouble(secPoint.y, thirdPoint.y); | |||
| 5339 | buf->putDefaultDouble(secPoint.z, thirdPoint.z); | |||
| 5340 | buf->putDefaultDouble(thirdPoint.x, fourPoint.x); | |||
| 5341 | buf->putDefaultDouble(thirdPoint.y, fourPoint.y); | |||
| 5342 | buf->putDefaultDouble(thirdPoint.z, fourPoint.z); | |||
| 5343 | if (!hasNoFlag) buf->putBitShort(static_cast<std::uint16_t>(invisibleflag)); | |||
| 5344 | ||||
| 5345 | return encodeDwgEntHandle(version, buf, handleBuf); | |||
| 5346 | } | |||
| 5347 | ||||
| 5348 | bool DRW_Solid::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 5349 | (void)bs; (void)strBuf; | |||
| 5350 | oType = 31; // SOLID class id — see dwgreader.cpp:1305 | |||
| 5351 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 5352 | ||||
| 5353 | // Same body layout as TRACE (4 corners + extrusion). Duplicated | |||
| 5354 | // here rather than delegating to DRW_Trace::encodeDwg because that | |||
| 5355 | // hardcodes oType=32. | |||
| 5356 | buf->putThickness(thickness, /*b_R2000_style=*/true); | |||
| 5357 | buf->putBitDouble(basePoint.z); | |||
| 5358 | buf->putRawDouble(basePoint.x); | |||
| 5359 | buf->putRawDouble(basePoint.y); | |||
| 5360 | buf->putRawDouble(secPoint.x); | |||
| 5361 | buf->putRawDouble(secPoint.y); | |||
| 5362 | buf->putRawDouble(thirdPoint.x); | |||
| 5363 | buf->putRawDouble(thirdPoint.y); | |||
| 5364 | buf->putRawDouble(fourPoint.x); | |||
| 5365 | buf->putRawDouble(fourPoint.y); | |||
| 5366 | buf->putExtrusion(extPoint, /*b_R2000_style=*/true); | |||
| 5367 | ||||
| 5368 | return encodeDwgEntHandle(version, buf, handleBuf); | |||
| 5369 | } | |||
| 5370 | ||||
| 5371 | bool DRW_LWPolyline::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 5372 | (void)bs; (void)strBuf; | |||
| 5373 | if (buf == nullptr || !validatePayloadFields()) | |||
| 5374 | return false; | |||
| 5375 | oType = 77; // LWPOLYLINE class id — see dwgreader.cpp:1202 | |||
| 5376 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 5377 | ||||
| 5378 | // DRW_LWPolyline::flags carries DXF-side bits (1=closed, 128=plinegen). | |||
| 5379 | // DWG-side flags are different: they signal which optional fields are | |||
| 5380 | // present. Per parseDwg, bit 9 (0x200) = closed, bit 8 (0x100) = | |||
| 5381 | // plinegen. Build the DWG flags from the DXF flags plus the data. | |||
| 5382 | std::uint16_t dwgFlags = 0; | |||
| 5383 | if (flags & 1) dwgFlags |= 0x200; // closed | |||
| 5384 | if (flags & 128) dwgFlags |= 0x100; // plinegen | |||
| 5385 | if (thickness != 0.0) dwgFlags |= 0x2; | |||
| 5386 | if (width != 0.0) dwgFlags |= 0x4; | |||
| 5387 | if (elevation != 0.0) dwgFlags |= 0x8; | |||
| 5388 | bool defaultExt = (extPoint.x == 0.0 && extPoint.y == 0.0 && extPoint.z == 1.0); | |||
| 5389 | if (!defaultExt) dwgFlags |= 0x1; | |||
| 5390 | // Detect per-vertex bulge / width data. | |||
| 5391 | bool anyBulge = false; | |||
| 5392 | bool anyWidth = false; | |||
| 5393 | bool anyVertexId = false; | |||
| 5394 | for (const auto& v : vertlist) { | |||
| 5395 | if (v && v->bulge != 0.0) anyBulge = true; | |||
| 5396 | if (v && (v->stawidth != 0.0 || v->endwidth != 0.0)) anyWidth = true; | |||
| 5397 | if (v && v->identifier != 0) anyVertexId = true; | |||
| 5398 | } | |||
| 5399 | if (anyBulge) dwgFlags |= 0x10; | |||
| 5400 | if (anyWidth) dwgFlags |= 0x20; | |||
| 5401 | if (version > DRW::AC1021 && anyVertexId) dwgFlags |= 0x400; | |||
| 5402 | ||||
| 5403 | buf->putBitShort(dwgFlags); | |||
| 5404 | if (dwgFlags & 0x4) buf->putBitDouble(width); | |||
| 5405 | if (dwgFlags & 0x8) buf->putBitDouble(elevation); | |||
| 5406 | if (dwgFlags & 0x2) buf->putBitDouble(thickness); | |||
| 5407 | if (dwgFlags & 0x1) buf->putExtrusion(extPoint, /*b_R2000_style=*/false); | |||
| 5408 | ||||
| 5409 | const std::int32_t numVerts = static_cast<std::int32_t>(vertlist.size()); | |||
| 5410 | buf->putBitLong(numVerts); | |||
| 5411 | if (dwgFlags & 0x10) buf->putBitLong(numVerts); // bulgesnum | |||
| 5412 | if (version > DRW::AC1021 && (dwgFlags & 0x400)) { | |||
| 5413 | buf->putBitLong(numVerts); // vertexIdCount | |||
| 5414 | } | |||
| 5415 | if (dwgFlags & 0x20) buf->putBitLong(numVerts); // widthsnum | |||
| 5416 | ||||
| 5417 | if (numVerts > 0) { | |||
| 5418 | // First vertex as 2RD. Subsequent vertices as 2DD relative to | |||
| 5419 | // the previous, with putDefaultDouble always emitting code 0b11 | |||
| 5420 | // (full RD); the reader's getDefaultDouble returns the raw value. | |||
| 5421 | buf->putRawDouble(vertlist[0]->x); | |||
| 5422 | buf->putRawDouble(vertlist[0]->y); | |||
| 5423 | for (size_t i = 1; i < vertlist.size(); ++i) { | |||
| 5424 | buf->putDefaultDouble(vertlist[i-1]->x, vertlist[i]->x); | |||
| 5425 | buf->putDefaultDouble(vertlist[i-1]->y, vertlist[i]->y); | |||
| 5426 | } | |||
| 5427 | if (dwgFlags & 0x10) { | |||
| 5428 | for (const auto& v : vertlist) | |||
| 5429 | buf->putBitDouble(v->bulge); | |||
| 5430 | } | |||
| 5431 | if (version > DRW::AC1021 && (dwgFlags & 0x400)) { | |||
| 5432 | for (const auto& v : vertlist) | |||
| 5433 | buf->putBitLong(static_cast<std::int32_t>(v->identifier)); | |||
| 5434 | } | |||
| 5435 | if (dwgFlags & 0x20) { | |||
| 5436 | for (const auto& v : vertlist) { | |||
| 5437 | buf->putBitDouble(v->stawidth); | |||
| 5438 | buf->putBitDouble(v->endwidth); | |||
| 5439 | } | |||
| 5440 | } | |||
| 5441 | } | |||
| 5442 | ||||
| 5443 | return encodeDwgEntHandle(version, buf, handleBuf); | |||
| 5444 | } | |||
| 5445 | ||||
| 5446 | bool DRW_Block::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 5447 | (void)bs; | |||
| 5448 | // BLOCK = 4, ENDBLK = 5 per DWG spec. isEnd controls which. | |||
| 5449 | oType = isEnd ? 5 : 4; | |||
| 5450 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 5451 | if (!isEnd) { | |||
| 5452 | (strBuf ? strBuf : buf)->putVariableText(version, name); | |||
| 5453 | } | |||
| 5454 | if (version > DRW::AC1018) { | |||
| 5455 | buf->putBit(0); // unknown bit (R2007+: always 0 for our output) | |||
| 5456 | } | |||
| 5457 | return encodeDwgEntHandle(version, buf, handleBuf); | |||
| 5458 | } | |||
| 5459 | ||||
| 5460 | bool DRW_Text::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 5461 | (void)bs; | |||
| 5462 | oType = 1; // TEXT class id — see dwgreader.cpp:1208 | |||
| 5463 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 5464 | ||||
| 5465 | // R2000+ TEXT body — mirror of DRW_Text::parseDwg. We emit | |||
| 5466 | // data_flags=0 so the reader sees every optional field rather than | |||
| 5467 | // substituting defaults — keeps the encoder simple, costs ~30 bytes | |||
| 5468 | // per TEXT versus the most compressed form. | |||
| 5469 | buf->putRawChar8(0); // data_flags=0 | |||
| 5470 | buf->putRawDouble(basePoint.z); // elevation RD | |||
| 5471 | buf->putRawDouble(basePoint.x); // insertion 2RD | |||
| 5472 | buf->putRawDouble(basePoint.y); | |||
| 5473 | buf->putDefaultDouble(basePoint.x, secPoint.x); // alignment 2DD | |||
| 5474 | buf->putDefaultDouble(basePoint.y, secPoint.y); | |||
| 5475 | buf->putExtrusion(extPoint, /*b_R2000_style=*/true); | |||
| 5476 | buf->putThickness(thickness, /*b_R2000_style=*/true); | |||
| 5477 | buf->putRawDouble(oblique); // oblique angle | |||
| 5478 | // Angle: struct holds degrees; on-disk format is radians. Reader | |||
| 5479 | // does `angle *= ARAD` (180/π) after read. Inverse: divide here. | |||
| 5480 | buf->putRawDouble(angle / ARAD57.29577951308232); | |||
| 5481 | buf->putRawDouble(height); // text height | |||
| 5482 | buf->putRawDouble(widthscale); // width factor | |||
| 5483 | (strBuf ? strBuf : buf)->putVariableText(version, text); // text string | |||
| 5484 | buf->putBitShort(static_cast<std::uint16_t>(textgen)); | |||
| 5485 | buf->putBitShort(static_cast<std::uint16_t>(alignH)); | |||
| 5486 | buf->putBitShort(static_cast<std::uint16_t>(alignV)); | |||
| 5487 | ||||
| 5488 | if (!encodeDwgEntHandle(version, buf, handleBuf)) return false; | |||
| 5489 | ||||
| 5490 | // styleH — hard pointer to STYLE table record. Default points at | |||
| 5491 | // the STANDARD textstyle (handle 0x13) if caller hasn't set one. | |||
| 5492 | dwgHandle sH; | |||
| 5493 | std::uint32_t sref = (styleH.ref == 0) ? 0x13 : styleH.ref; | |||
| 5494 | sH.code = 5; // hard pointer | |||
| 5495 | sH.ref = sref; | |||
| 5496 | sH.size = 0; | |||
| 5497 | if (sref != 0) { | |||
| 5498 | std::uint32_t t = sref; | |||
| 5499 | while (t != 0) { t >>= 8; ++sH.size; } | |||
| 5500 | } | |||
| 5501 | (handleBuf ? handleBuf : buf)->putHandle(sH); | |||
| 5502 | return true; | |||
| 5503 | } | |||
| 5504 | ||||
| 5505 | bool DRW_Ellipse::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 5506 | (void)bs; (void)strBuf; | |||
| 5507 | oType = 35; // ELLIPSE class id — see dwgreader.cpp:1117 | |||
| 5508 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 5509 | ||||
| 5510 | // Ellipse body — mirror of DRW_Ellipse::parseDwg. | |||
| 5511 | buf->put3BitDouble(basePoint); // center | |||
| 5512 | buf->put3BitDouble(secPoint); // major axis vector | |||
| 5513 | buf->put3BitDouble(extPoint); // extrusion | |||
| 5514 | buf->putBitDouble(ratio); // minor/major ratio | |||
| 5515 | buf->putBitDouble(staparam); // start parameter | |||
| 5516 | buf->putBitDouble(endparam); // end parameter | |||
| 5517 | ||||
| 5518 | return encodeDwgEntHandle(version, buf, handleBuf); | |||
| 5519 | } | |||
| 5520 | ||||
| 5521 | bool DRW_Arc::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 5522 | (void)bs; (void)strBuf; | |||
| 5523 | oType = 17; // ARC class id — see dwgreader.cpp:1093 | |||
| 5524 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 5525 | ||||
| 5526 | // Arc body — Circle body + 2 BD angles. | |||
| 5527 | buf->putBitDouble(basePoint.x); | |||
| 5528 | buf->putBitDouble(basePoint.y); | |||
| 5529 | buf->putBitDouble(basePoint.z); | |||
| 5530 | buf->putBitDouble(radious); | |||
| 5531 | buf->putThickness(thickness, /*b_R2000_style=*/true); | |||
| 5532 | buf->putExtrusion(extPoint, /*b_R2000_style=*/true); | |||
| 5533 | buf->putBitDouble(staangle); | |||
| 5534 | buf->putBitDouble(endangle); | |||
| 5535 | ||||
| 5536 | return encodeDwgEntHandle(version, buf, handleBuf); | |||
| 5537 | } | |||
| 5538 | ||||
| 5539 | bool DRW_Line::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){ | |||
| 5540 | resetDwgState(); | |||
| 5541 | dwgBuffer *sourceBuf = buf; | |||
| 5542 | auto fail = [this, sourceBuf]() { | |||
| 5543 | if (sourceBuf != nullptr) | |||
| 5544 | sourceBuf->invalidate(); | |||
| 5545 | resetDwgState(); | |||
| 5546 | return false; | |||
| 5547 | }; | |||
| 5548 | if (sourceBuf == nullptr) | |||
| 5549 | return fail(); | |||
| 5550 | ||||
| 5551 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 5552 | if (!DRW_Entity::parseDwgCommon(version, &bodyProbe, bs) | |||
| 5553 | || !bodyProbe.isGood()) | |||
| 5554 | return fail(); | |||
| 5555 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 5556 | DRW_Coord parsedBasePoint; | |||
| 5557 | DRW_Coord parsedSecPoint; | |||
| 5558 | DRW_Coord parsedExtrusion; | |||
| 5559 | double parsedThickness = 0.0; | |||
| 5560 | if (version < DRW::AC1015) { | |||
| 5561 | if (!readBoundedBitCoord(bodyProbe, bodyEndBit, parsedBasePoint) | |||
| 5562 | || !readBoundedBitCoord(bodyProbe, bodyEndBit, parsedSecPoint)) | |||
| 5563 | return fail(); | |||
| 5564 | } else { | |||
| 5565 | if (!proxyEntityHasBits(bodyProbe, bodyEndBit, 1)) | |||
| 5566 | return fail(); | |||
| 5567 | const bool zIsZero = bodyProbe.getBit() != 0; | |||
| 5568 | if (!bodyProbe.isGood() | |||
| 5569 | || !readBoundedRawDouble(bodyProbe, bodyEndBit, | |||
| 5570 | parsedBasePoint.x) | |||
| 5571 | || !readBoundedDefaultDouble(bodyProbe, bodyEndBit, | |||
| 5572 | parsedBasePoint.x, | |||
| 5573 | parsedSecPoint.x) | |||
| 5574 | || !readBoundedRawDouble(bodyProbe, bodyEndBit, | |||
| 5575 | parsedBasePoint.y) | |||
| 5576 | || !readBoundedDefaultDouble(bodyProbe, bodyEndBit, | |||
| 5577 | parsedBasePoint.y, | |||
| 5578 | parsedSecPoint.y)) | |||
| 5579 | return fail(); | |||
| 5580 | if (zIsZero) { | |||
| 5581 | parsedBasePoint.z = 0.0; | |||
| 5582 | parsedSecPoint.z = 0.0; | |||
| 5583 | } else if (!readBoundedRawDouble(bodyProbe, bodyEndBit, | |||
| 5584 | parsedBasePoint.z) | |||
| 5585 | || !readBoundedDefaultDouble(bodyProbe, bodyEndBit, | |||
| 5586 | parsedBasePoint.z, | |||
| 5587 | parsedSecPoint.z)) | |||
| 5588 | return fail(); | |||
| 5589 | } | |||
| 5590 | if (!readBoundedThickness(bodyProbe, bodyEndBit, | |||
| 5591 | version > DRW::AC1014, parsedThickness) | |||
| 5592 | || !readBoundedExtrusion(bodyProbe, bodyEndBit, | |||
| 5593 | version > DRW::AC1014, parsedExtrusion) | |||
| 5594 | || !std::isfinite(parsedBasePoint.x) | |||
| 5595 | || !std::isfinite(parsedBasePoint.y) | |||
| 5596 | || !std::isfinite(parsedBasePoint.z) | |||
| 5597 | || !std::isfinite(parsedSecPoint.x) | |||
| 5598 | || !std::isfinite(parsedSecPoint.y) | |||
| 5599 | || !std::isfinite(parsedSecPoint.z) | |||
| 5600 | || !std::isfinite(parsedThickness) | |||
| 5601 | || !std::isfinite(parsedExtrusion.x) | |||
| 5602 | || !std::isfinite(parsedExtrusion.y) | |||
| 5603 | || !std::isfinite(parsedExtrusion.z)) | |||
| 5604 | return fail(); | |||
| 5605 | ||||
| 5606 | std::uint64_t handleEndBit = 0; | |||
| 5607 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, | |||
| 5608 | handleEndBit)) | |||
| 5609 | return fail(); | |||
| 5610 | dwgBuffer handleProbe = bodyProbe.forkIndependent(); | |||
| 5611 | if (!DRW_Entity::parseDwgEntHandle(version, &handleProbe, true, | |||
| 5612 | handleEndBit) | |||
| 5613 | || !handleProbe.isGood()) | |||
| 5614 | return fail(); | |||
| 5615 | ||||
| 5616 | basePoint = parsedBasePoint; | |||
| 5617 | secPoint = parsedSecPoint; | |||
| 5618 | thickness = parsedThickness; | |||
| 5619 | extPoint = parsedExtrusion; | |||
| 5620 | *sourceBuf = handleProbe; | |||
| 5621 | return true; | |||
| 5622 | } | |||
| 5623 | ||||
| 5624 | bool DRW_Ray::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){ | |||
| 5625 | resetDwgState(); | |||
| 5626 | dwgBuffer *sourceBuf = buf; | |||
| 5627 | auto fail = [this, sourceBuf]() { | |||
| 5628 | if (sourceBuf != nullptr) | |||
| 5629 | sourceBuf->invalidate(); | |||
| 5630 | resetDwgState(); | |||
| 5631 | return false; | |||
| 5632 | }; | |||
| 5633 | if (sourceBuf == nullptr) | |||
| 5634 | return fail(); | |||
| 5635 | ||||
| 5636 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 5637 | if (!DRW_Entity::parseDwgCommon(version, &bodyProbe, bs) | |||
| 5638 | || !bodyProbe.isGood()) | |||
| 5639 | return fail(); | |||
| 5640 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 5641 | DRW_Coord parsedBasePoint; | |||
| 5642 | DRW_Coord parsedDirection; | |||
| 5643 | if (!readBoundedBitCoord(bodyProbe, bodyEndBit, parsedBasePoint) | |||
| 5644 | || !readBoundedBitCoord(bodyProbe, bodyEndBit, parsedDirection) | |||
| 5645 | || !std::isfinite(parsedBasePoint.x) | |||
| 5646 | || !std::isfinite(parsedBasePoint.y) | |||
| 5647 | || !std::isfinite(parsedBasePoint.z) | |||
| 5648 | || !std::isfinite(parsedDirection.x) | |||
| 5649 | || !std::isfinite(parsedDirection.y) | |||
| 5650 | || !std::isfinite(parsedDirection.z)) | |||
| 5651 | return fail(); | |||
| 5652 | ||||
| 5653 | std::uint64_t handleEndBit = 0; | |||
| 5654 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, | |||
| 5655 | handleEndBit)) | |||
| 5656 | return fail(); | |||
| 5657 | dwgBuffer handleProbe = bodyProbe.forkIndependent(); | |||
| 5658 | if (!DRW_Entity::parseDwgEntHandle(version, &handleProbe, true, | |||
| 5659 | handleEndBit) | |||
| 5660 | || !handleProbe.isGood()) | |||
| 5661 | return fail(); | |||
| 5662 | ||||
| 5663 | basePoint = parsedBasePoint; | |||
| 5664 | secPoint = parsedDirection; | |||
| 5665 | *sourceBuf = handleProbe; | |||
| 5666 | return true; | |||
| 5667 | } | |||
| 5668 | ||||
| 5669 | void DRW_Circle::applyExtrusion(){ | |||
| 5670 | if (haveExtrusion) { | |||
| 5671 | //NOTE: Commenting these out causes the the arcs being tested to be located | |||
| 5672 | //on the other side of the y axis (all x dimensions are negated). | |||
| 5673 | calculateAxis(extPoint); | |||
| 5674 | extrudePoint(extPoint, &basePoint); | |||
| 5675 | } | |||
| 5676 | } | |||
| 5677 | ||||
| 5678 | bool DRW_Circle::parseCode(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 5679 | switch (code) { | |||
| 5680 | case 40: | |||
| 5681 | radious = reader->getDouble(); | |||
| 5682 | break; | |||
| 5683 | default: | |||
| 5684 | return DRW_Point::parseCode(code, reader); | |||
| 5685 | } | |||
| 5686 | ||||
| 5687 | return true; | |||
| 5688 | } | |||
| 5689 | ||||
| 5690 | void DRW_Circle::resetDwgState() { | |||
| 5691 | DRW_Point::resetDwgState(); | |||
| 5692 | radious = 0.0; | |||
| 5693 | } | |||
| 5694 | ||||
| 5695 | bool DRW_Circle::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){ | |||
| 5696 | resetDwgState(); | |||
| 5697 | radious = 0.0; | |||
| 5698 | dwgBuffer *sourceBuf = buf; | |||
| 5699 | auto fail = [this, sourceBuf]() { | |||
| 5700 | if (sourceBuf != nullptr) | |||
| 5701 | sourceBuf->invalidate(); | |||
| 5702 | resetDwgState(); | |||
| 5703 | return false; | |||
| 5704 | }; | |||
| 5705 | if (sourceBuf == nullptr) | |||
| 5706 | return fail(); | |||
| 5707 | ||||
| 5708 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 5709 | if (!DRW_Entity::parseDwgCommon(version, &bodyProbe, bs) | |||
| 5710 | || !bodyProbe.isGood()) | |||
| 5711 | return fail(); | |||
| 5712 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 5713 | DRW_Coord parsedCenter; | |||
| 5714 | DRW_Coord parsedExtrusion; | |||
| 5715 | double parsedRadius = 0.0; | |||
| 5716 | double parsedThickness = 0.0; | |||
| 5717 | if (!readBoundedBitCoord(bodyProbe, bodyEndBit, parsedCenter) | |||
| 5718 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, parsedRadius) | |||
| 5719 | || !readBoundedThickness(bodyProbe, bodyEndBit, | |||
| 5720 | version > DRW::AC1014, parsedThickness) | |||
| 5721 | || !readBoundedExtrusion(bodyProbe, bodyEndBit, | |||
| 5722 | version > DRW::AC1014, parsedExtrusion) | |||
| 5723 | || !std::isfinite(parsedCenter.x) | |||
| 5724 | || !std::isfinite(parsedCenter.y) | |||
| 5725 | || !std::isfinite(parsedCenter.z) | |||
| 5726 | || !std::isfinite(parsedRadius) | |||
| 5727 | || !std::isfinite(parsedThickness) | |||
| 5728 | || !std::isfinite(parsedExtrusion.x) | |||
| 5729 | || !std::isfinite(parsedExtrusion.y) | |||
| 5730 | || !std::isfinite(parsedExtrusion.z)) | |||
| 5731 | return fail(); | |||
| 5732 | ||||
| 5733 | std::uint64_t handleEndBit = 0; | |||
| 5734 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, | |||
| 5735 | handleEndBit)) | |||
| 5736 | return fail(); | |||
| 5737 | dwgBuffer handleProbe = bodyProbe.forkIndependent(); | |||
| 5738 | if (!DRW_Entity::parseDwgEntHandle(version, &handleProbe, true, | |||
| 5739 | handleEndBit) | |||
| 5740 | || !handleProbe.isGood()) | |||
| 5741 | return fail(); | |||
| 5742 | ||||
| 5743 | basePoint = parsedCenter; | |||
| 5744 | radious = parsedRadius; | |||
| 5745 | thickness = parsedThickness; | |||
| 5746 | extPoint = parsedExtrusion; | |||
| 5747 | *sourceBuf = handleProbe; | |||
| 5748 | return true; | |||
| 5749 | } | |||
| 5750 | ||||
| 5751 | void DRW_Arc::applyExtrusion(){ | |||
| 5752 | DRW_Circle::applyExtrusion(); | |||
| 5753 | ||||
| 5754 | if(haveExtrusion){ | |||
| 5755 | // If the extrusion vector has a z value less than 0, the angles for the arc | |||
| 5756 | // have to be mirrored since DXF files use the right hand rule. | |||
| 5757 | // Note that the following code only handles the special case where there is a 2D | |||
| 5758 | // drawing with the z axis heading into the paper (or rather screen). An arbitrary | |||
| 5759 | // extrusion axis (with x and y values greater than 1/64) may still have issues. | |||
| 5760 | if (fabs(extPoint.x) < 0.015625 && fabs(extPoint.y) < 0.015625 && extPoint.z < 0.0) { | |||
| 5761 | staangle=M_PI3.14159265358979323846-staangle; | |||
| 5762 | endangle=M_PI3.14159265358979323846-endangle; | |||
| 5763 | ||||
| 5764 | double temp = staangle; | |||
| 5765 | staangle=endangle; | |||
| 5766 | endangle=temp; | |||
| 5767 | } | |||
| 5768 | } | |||
| 5769 | } | |||
| 5770 | ||||
| 5771 | bool DRW_Arc::parseCode(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 5772 | switch (code) { | |||
| 5773 | case 50: | |||
| 5774 | staangle = reader->getDouble()/ ARAD57.29577951308232; | |||
| 5775 | break; | |||
| 5776 | case 51: | |||
| 5777 | endangle = reader->getDouble()/ ARAD57.29577951308232; | |||
| 5778 | break; | |||
| 5779 | default: | |||
| 5780 | return DRW_Circle::parseCode(code, reader); | |||
| 5781 | } | |||
| 5782 | ||||
| 5783 | return true; | |||
| 5784 | } | |||
| 5785 | ||||
| 5786 | bool DRW_Arc::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){ | |||
| 5787 | DRW_Circle::resetDwgState(); | |||
| 5788 | radious = 0.0; | |||
| 5789 | staangle = 0.0; | |||
| 5790 | endangle = 0.0; | |||
| 5791 | isccw = 1; | |||
| 5792 | dwgBuffer *sourceBuf = buf; | |||
| 5793 | auto fail = [this, sourceBuf]() { | |||
| 5794 | if (sourceBuf != nullptr) | |||
| 5795 | sourceBuf->invalidate(); | |||
| 5796 | DRW_Circle::resetDwgState(); | |||
| 5797 | staangle = 0.0; | |||
| 5798 | endangle = 0.0; | |||
| 5799 | isccw = 1; | |||
| 5800 | return false; | |||
| 5801 | }; | |||
| 5802 | if (sourceBuf == nullptr) | |||
| 5803 | return fail(); | |||
| 5804 | ||||
| 5805 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 5806 | if (!DRW_Entity::parseDwgCommon(version, &bodyProbe, bs) | |||
| 5807 | || !bodyProbe.isGood()) | |||
| 5808 | return fail(); | |||
| 5809 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 5810 | DRW_Coord parsedCenter; | |||
| 5811 | DRW_Coord parsedExtrusion; | |||
| 5812 | double parsedRadius = 0.0; | |||
| 5813 | double parsedThickness = 0.0; | |||
| 5814 | double parsedStartAngle = 0.0; | |||
| 5815 | double parsedEndAngle = 0.0; | |||
| 5816 | if (!readBoundedBitCoord(bodyProbe, bodyEndBit, parsedCenter) | |||
| 5817 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, parsedRadius) | |||
| 5818 | || !readBoundedThickness(bodyProbe, bodyEndBit, | |||
| 5819 | version > DRW::AC1014, parsedThickness) | |||
| 5820 | || !readBoundedExtrusion(bodyProbe, bodyEndBit, | |||
| 5821 | version > DRW::AC1014, parsedExtrusion) | |||
| 5822 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, parsedStartAngle) | |||
| 5823 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, parsedEndAngle) | |||
| 5824 | || !std::isfinite(parsedCenter.x) | |||
| 5825 | || !std::isfinite(parsedCenter.y) | |||
| 5826 | || !std::isfinite(parsedCenter.z) | |||
| 5827 | || !std::isfinite(parsedRadius) | |||
| 5828 | || !std::isfinite(parsedThickness) | |||
| 5829 | || !std::isfinite(parsedExtrusion.x) | |||
| 5830 | || !std::isfinite(parsedExtrusion.y) | |||
| 5831 | || !std::isfinite(parsedExtrusion.z) | |||
| 5832 | || !std::isfinite(parsedStartAngle) | |||
| 5833 | || !std::isfinite(parsedEndAngle)) | |||
| 5834 | return fail(); | |||
| 5835 | ||||
| 5836 | std::uint64_t handleEndBit = 0; | |||
| 5837 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, | |||
| 5838 | handleEndBit)) | |||
| 5839 | return fail(); | |||
| 5840 | dwgBuffer handleProbe = bodyProbe.forkIndependent(); | |||
| 5841 | if (!DRW_Entity::parseDwgEntHandle(version, &handleProbe, true, | |||
| 5842 | handleEndBit) | |||
| 5843 | || !handleProbe.isGood()) | |||
| 5844 | return fail(); | |||
| 5845 | ||||
| 5846 | basePoint = parsedCenter; | |||
| 5847 | radious = parsedRadius; | |||
| 5848 | thickness = parsedThickness; | |||
| 5849 | extPoint = parsedExtrusion; | |||
| 5850 | staangle = parsedStartAngle; | |||
| 5851 | endangle = parsedEndAngle; | |||
| 5852 | *sourceBuf = handleProbe; | |||
| 5853 | return true; | |||
| 5854 | } | |||
| 5855 | ||||
| 5856 | bool DRW_Ellipse::parseCode(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 5857 | switch (code) { | |||
| 5858 | case 40: | |||
| 5859 | ratio = reader->getDouble(); | |||
| 5860 | break; | |||
| 5861 | case 41: | |||
| 5862 | staparam = reader->getDouble(); | |||
| 5863 | break; | |||
| 5864 | case 42: | |||
| 5865 | endparam = reader->getDouble(); | |||
| 5866 | break; | |||
| 5867 | default: | |||
| 5868 | return DRW_Line::parseCode(code, reader); | |||
| 5869 | } | |||
| 5870 | ||||
| 5871 | return true; | |||
| 5872 | } | |||
| 5873 | ||||
| 5874 | void DRW_Ellipse::applyExtrusion(){ | |||
| 5875 | if (haveExtrusion) { | |||
| 5876 | calculateAxis(extPoint); | |||
| 5877 | extrudePoint(extPoint, &basePoint); | |||
| 5878 | extrudePoint(extPoint, &secPoint); | |||
| 5879 | double intialparam = staparam; | |||
| 5880 | if (extPoint.z < 0.){ | |||
| 5881 | staparam = M_PIx26.283185307179586 - endparam; | |||
| 5882 | endparam = M_PIx26.283185307179586 - intialparam; | |||
| 5883 | } | |||
| 5884 | } | |||
| 5885 | } | |||
| 5886 | ||||
| 5887 | //if ratio > 1 minor axis are greather than major axis, correct it | |||
| 5888 | void DRW_Ellipse::correctAxis(){ | |||
| 5889 | bool complete = false; | |||
| 5890 | if (staparam == endparam) { | |||
| 5891 | staparam = 0.0; | |||
| 5892 | endparam = M_PIx26.283185307179586; //2*M_PI; | |||
| 5893 | complete = true; | |||
| 5894 | } | |||
| 5895 | if (ratio > 1){ | |||
| 5896 | if ( fabs(endparam - staparam - M_PIx26.283185307179586) < 1.0e-10) | |||
| 5897 | complete = true; | |||
| 5898 | double incX = secPoint.x; | |||
| 5899 | secPoint.x = -(secPoint.y * ratio); | |||
| 5900 | secPoint.y = incX*ratio; | |||
| 5901 | ratio = 1/ratio; | |||
| 5902 | if (!complete){ | |||
| 5903 | if (staparam < M_PI_21.57079632679489661923) | |||
| 5904 | staparam += M_PI3.14159265358979323846 *2; | |||
| 5905 | if (endparam < M_PI_21.57079632679489661923) | |||
| 5906 | endparam += M_PI3.14159265358979323846 *2; | |||
| 5907 | endparam -= M_PI_21.57079632679489661923; | |||
| 5908 | staparam -= M_PI_21.57079632679489661923; | |||
| 5909 | } | |||
| 5910 | } | |||
| 5911 | } | |||
| 5912 | ||||
| 5913 | bool DRW_Ellipse::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){ | |||
| 5914 | resetDwgState(); | |||
| 5915 | ratio = 1.0; | |||
| 5916 | staparam = 0.0; | |||
| 5917 | endparam = 0.0; | |||
| 5918 | isccw = 1; | |||
| 5919 | dwgBuffer *sourceBuf = buf; | |||
| 5920 | auto fail = [this, sourceBuf]() { | |||
| 5921 | if (sourceBuf != nullptr) | |||
| 5922 | sourceBuf->invalidate(); | |||
| 5923 | resetDwgState(); | |||
| 5924 | ratio = 1.0; | |||
| 5925 | staparam = 0.0; | |||
| 5926 | endparam = 0.0; | |||
| 5927 | isccw = 1; | |||
| 5928 | return false; | |||
| 5929 | }; | |||
| 5930 | if (sourceBuf == nullptr) | |||
| 5931 | return fail(); | |||
| 5932 | ||||
| 5933 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 5934 | if (!DRW_Entity::parseDwgCommon(version, &bodyProbe, bs) | |||
| 5935 | || !bodyProbe.isGood()) | |||
| 5936 | return fail(); | |||
| 5937 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 5938 | DRW_Coord parsedCenter; | |||
| 5939 | DRW_Coord parsedAxis; | |||
| 5940 | DRW_Coord parsedExtrusion; | |||
| 5941 | double parsedRatio = 1.0; | |||
| 5942 | double parsedStart = 0.0; | |||
| 5943 | double parsedEnd = 0.0; | |||
| 5944 | if (!readBoundedBitCoord(bodyProbe, bodyEndBit, parsedCenter) | |||
| 5945 | || !readBoundedBitCoord(bodyProbe, bodyEndBit, parsedAxis) | |||
| 5946 | || !readBoundedBitCoord(bodyProbe, bodyEndBit, parsedExtrusion) | |||
| 5947 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, parsedRatio) | |||
| 5948 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, parsedStart) | |||
| 5949 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, parsedEnd) | |||
| 5950 | || !std::isfinite(parsedCenter.x) | |||
| 5951 | || !std::isfinite(parsedCenter.y) | |||
| 5952 | || !std::isfinite(parsedCenter.z) | |||
| 5953 | || !std::isfinite(parsedAxis.x) | |||
| 5954 | || !std::isfinite(parsedAxis.y) | |||
| 5955 | || !std::isfinite(parsedAxis.z) | |||
| 5956 | || !std::isfinite(parsedExtrusion.x) | |||
| 5957 | || !std::isfinite(parsedExtrusion.y) | |||
| 5958 | || !std::isfinite(parsedExtrusion.z) | |||
| 5959 | || !std::isfinite(parsedRatio) | |||
| 5960 | || !std::isfinite(parsedStart) | |||
| 5961 | || !std::isfinite(parsedEnd)) | |||
| 5962 | return fail(); | |||
| 5963 | ||||
| 5964 | std::uint64_t handleEndBit = 0; | |||
| 5965 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, | |||
| 5966 | handleEndBit)) | |||
| 5967 | return fail(); | |||
| 5968 | dwgBuffer handleProbe = bodyProbe.forkIndependent(); | |||
| 5969 | if (!DRW_Entity::parseDwgEntHandle(version, &handleProbe, true, | |||
| 5970 | handleEndBit) | |||
| 5971 | || !handleProbe.isGood()) | |||
| 5972 | return fail(); | |||
| 5973 | ||||
| 5974 | basePoint = parsedCenter; | |||
| 5975 | secPoint = parsedAxis; | |||
| 5976 | extPoint = parsedExtrusion; | |||
| 5977 | ratio = parsedRatio; | |||
| 5978 | staparam = parsedStart; | |||
| 5979 | endparam = parsedEnd; | |||
| 5980 | *sourceBuf = handleProbe; | |||
| 5981 | return true; | |||
| 5982 | } | |||
| 5983 | ||||
| 5984 | //parts are the number of vertex to split polyline, default 128 | |||
| 5985 | void DRW_Ellipse::toPolyline(DRW_Polyline *pol, int parts){ | |||
| 5986 | double radMajor, radMinor, cosRot, sinRot, incAngle, curAngle; | |||
| 5987 | double cosCurr, sinCurr; | |||
| 5988 | radMajor = hypot(secPoint.x, secPoint.y); | |||
| 5989 | radMinor = radMajor*ratio; | |||
| 5990 | //calculate sin & cos of included angle | |||
| 5991 | incAngle = atan2(secPoint.y, secPoint.x); | |||
| 5992 | cosRot = cos(incAngle); | |||
| 5993 | sinRot = sin(incAngle); | |||
| 5994 | incAngle = M_PIx26.283185307179586 / parts; | |||
| 5995 | curAngle = staparam; | |||
| 5996 | int i = static_cast<int>(curAngle / incAngle); | |||
| 5997 | do { | |||
| 5998 | if (curAngle > endparam) { | |||
| 5999 | curAngle = endparam; | |||
| 6000 | i = parts+2; | |||
| 6001 | } | |||
| 6002 | cosCurr = cos(curAngle); | |||
| 6003 | sinCurr = sin(curAngle); | |||
| 6004 | double x = basePoint.x + (cosCurr*cosRot*radMajor) - (sinCurr*sinRot*radMinor); | |||
| 6005 | double y = basePoint.y + (cosCurr*sinRot*radMajor) + (sinCurr*cosRot*radMinor); | |||
| 6006 | pol->addVertex( DRW_Vertex(x, y, 0.0, 0.0)); | |||
| 6007 | curAngle = (++i)*incAngle; | |||
| 6008 | } while (i<parts); | |||
| 6009 | if ( fabs(endparam - staparam - M_PIx26.283185307179586) < 1.0e-10){ | |||
| 6010 | pol->flags = 1; | |||
| 6011 | } | |||
| 6012 | pol->layer = this->layer; | |||
| 6013 | pol->lineType = this->lineType; | |||
| 6014 | pol->color = this->color; | |||
| 6015 | pol->lWeight = this->lWeight; | |||
| 6016 | pol->extPoint = this->extPoint; | |||
| 6017 | } | |||
| 6018 | ||||
| 6019 | void DRW_Trace::applyExtrusion(){ | |||
| 6020 | if (haveExtrusion) { | |||
| 6021 | calculateAxis(extPoint); | |||
| 6022 | extrudePoint(extPoint, &basePoint); | |||
| 6023 | extrudePoint(extPoint, &secPoint); | |||
| 6024 | extrudePoint(extPoint, &thirdPoint); | |||
| 6025 | extrudePoint(extPoint, &fourPoint); | |||
| 6026 | } | |||
| 6027 | } | |||
| 6028 | ||||
| 6029 | bool DRW_Trace::parseCode(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 6030 | switch (code) { | |||
| 6031 | case 12: | |||
| 6032 | thirdPoint.x = reader->getDouble(); | |||
| 6033 | break; | |||
| 6034 | case 22: | |||
| 6035 | thirdPoint.y = reader->getDouble(); | |||
| 6036 | break; | |||
| 6037 | case 32: | |||
| 6038 | thirdPoint.z = reader->getDouble(); | |||
| 6039 | break; | |||
| 6040 | case 13: | |||
| 6041 | fourPoint.x = reader->getDouble(); | |||
| 6042 | break; | |||
| 6043 | case 23: | |||
| 6044 | fourPoint.y = reader->getDouble(); | |||
| 6045 | break; | |||
| 6046 | case 33: | |||
| 6047 | fourPoint.z = reader->getDouble(); | |||
| 6048 | break; | |||
| 6049 | default: | |||
| 6050 | return DRW_Line::parseCode(code, reader); | |||
| 6051 | } | |||
| 6052 | ||||
| 6053 | return true; | |||
| 6054 | } | |||
| 6055 | ||||
| 6056 | void DRW_Trace::resetDwgState() { | |||
| 6057 | DRW_Line::resetDwgState(); | |||
| 6058 | thirdPoint = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 6059 | fourPoint = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 6060 | } | |||
| 6061 | ||||
| 6062 | bool DRW_Trace::parseDwg(DRW::Version version, dwgBuffer *buf, | |||
| 6063 | std::uint32_t bs) { | |||
| 6064 | resetDwgState(); | |||
| 6065 | dwgBuffer *sourceBuf = buf; | |||
| 6066 | auto fail = [this, sourceBuf]() { | |||
| 6067 | if (sourceBuf != nullptr) | |||
| 6068 | sourceBuf->invalidate(); | |||
| 6069 | resetDwgState(); | |||
| 6070 | return false; | |||
| 6071 | }; | |||
| 6072 | if (sourceBuf == nullptr) | |||
| 6073 | return fail(); | |||
| 6074 | ||||
| 6075 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 6076 | if (!DRW_Entity::parseDwgCommon(version, &bodyProbe, bs) | |||
| 6077 | || !bodyProbe.isGood()) | |||
| 6078 | return fail(); | |||
| 6079 | ||||
| 6080 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 6081 | double parsedThickness = 0.0; | |||
| 6082 | double parsedElevation = 0.0; | |||
| 6083 | std::array<double, 8> coordinates{}; | |||
| 6084 | DRW_Coord parsedExtrusion{0.0, 0.0, 1.0}; | |||
| 6085 | if (!readBoundedThickness(bodyProbe, bodyEndBit, | |||
| 6086 | version > DRW::AC1014, parsedThickness) | |||
| 6087 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, parsedElevation)) | |||
| 6088 | return fail(); | |||
| 6089 | for (double& coordinate : coordinates) { | |||
| 6090 | if (!readBoundedRawDouble(bodyProbe, bodyEndBit, coordinate) | |||
| 6091 | || !std::isfinite(coordinate)) | |||
| 6092 | return fail(); | |||
| 6093 | } | |||
| 6094 | if (!std::isfinite(parsedThickness) | |||
| 6095 | || !std::isfinite(parsedElevation) | |||
| 6096 | || !readBoundedExtrusion(bodyProbe, bodyEndBit, | |||
| 6097 | version > DRW::AC1014, parsedExtrusion) | |||
| 6098 | || !std::isfinite(parsedExtrusion.x) | |||
| 6099 | || !std::isfinite(parsedExtrusion.y) | |||
| 6100 | || !std::isfinite(parsedExtrusion.z)) | |||
| 6101 | return fail(); | |||
| 6102 | ||||
| 6103 | std::uint64_t handleEndBit = 0; | |||
| 6104 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, | |||
| 6105 | handleEndBit)) | |||
| 6106 | return fail(); | |||
| 6107 | dwgBuffer handleProbe = bodyProbe.forkIndependent(); | |||
| 6108 | if (!DRW_Entity::parseDwgEntHandle(version, &handleProbe, true, | |||
| 6109 | handleEndBit) | |||
| 6110 | || !handleProbe.isGood()) | |||
| 6111 | return fail(); | |||
| 6112 | ||||
| 6113 | thickness = parsedThickness; | |||
| 6114 | basePoint = DRW_Coord{coordinates[0], coordinates[1], parsedElevation}; | |||
| 6115 | secPoint = DRW_Coord{coordinates[2], coordinates[3], parsedElevation}; | |||
| 6116 | thirdPoint = DRW_Coord{coordinates[4], coordinates[5], parsedElevation}; | |||
| 6117 | fourPoint = DRW_Coord{coordinates[6], coordinates[7], parsedElevation}; | |||
| 6118 | extPoint = parsedExtrusion; | |||
| 6119 | *sourceBuf = handleProbe; | |||
| 6120 | return true; | |||
| 6121 | } | |||
| 6122 | ||||
| 6123 | bool DRW_Solid::parseDwg(DRW::Version v, dwgBuffer *buf, std::uint32_t bs){ | |||
| 6124 | DRW_DBG("\n***************************** parsing Solid *********************************************\n")DRW_dbg::dbg("\n***************************** parsing Solid *********************************************\n" ); | |||
| 6125 | return DRW_Trace::parseDwg(v, buf, bs); | |||
| 6126 | } | |||
| 6127 | ||||
| 6128 | bool DRW_3Dface::parseCode(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 6129 | switch (code) { | |||
| 6130 | case 70: | |||
| 6131 | invisibleflag = reader->getInt32(); | |||
| 6132 | break; | |||
| 6133 | default: | |||
| 6134 | return DRW_Trace::parseCode(code, reader); | |||
| 6135 | } | |||
| 6136 | ||||
| 6137 | return true; | |||
| 6138 | } | |||
| 6139 | ||||
| 6140 | bool DRW_3Dface::parseDwg(DRW::Version v, dwgBuffer *buf, | |||
| 6141 | std::uint32_t bs) { | |||
| 6142 | DRW_Trace::resetDwgState(); | |||
| 6143 | invisibleflag = 0; | |||
| 6144 | dwgBuffer *sourceBuf = buf; | |||
| 6145 | auto fail = [this, sourceBuf]() { | |||
| 6146 | if (sourceBuf != nullptr) | |||
| 6147 | sourceBuf->invalidate(); | |||
| 6148 | DRW_Trace::resetDwgState(); | |||
| 6149 | invisibleflag = 0; | |||
| 6150 | return false; | |||
| 6151 | }; | |||
| 6152 | if (sourceBuf == nullptr) | |||
| 6153 | return fail(); | |||
| 6154 | ||||
| 6155 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 6156 | if (!DRW_Entity::parseDwgCommon(v, &bodyProbe, bs) | |||
| 6157 | || !bodyProbe.isGood()) | |||
| 6158 | return fail(); | |||
| 6159 | ||||
| 6160 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 6161 | std::array<DRW_Coord, 4> points{}; | |||
| 6162 | std::uint16_t parsedInvisibleFlag = 0; | |||
| 6163 | if (v < DRW::AC1015) { | |||
| 6164 | for (DRW_Coord& point : points) { | |||
| 6165 | if (!readBoundedBitDouble(bodyProbe, bodyEndBit, point.x) | |||
| 6166 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, point.y) | |||
| 6167 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, point.z)) | |||
| 6168 | return fail(); | |||
| 6169 | } | |||
| 6170 | if (!readBoundedBitShort(bodyProbe, bodyEndBit, | |||
| 6171 | parsedInvisibleFlag)) | |||
| 6172 | return fail(); | |||
| 6173 | } else { | |||
| 6174 | if (!proxyEntityHasBits(bodyProbe, bodyEndBit, 2)) | |||
| 6175 | return fail(); | |||
| 6176 | const bool hasNoFlag = bodyProbe.getBit() != 0; | |||
| 6177 | const bool zIsZero = bodyProbe.getBit() != 0; | |||
| 6178 | if (!bodyProbe.isGood() | |||
| 6179 | || !readBoundedRawDouble(bodyProbe, bodyEndBit, points[0].x) | |||
| 6180 | || !readBoundedRawDouble(bodyProbe, bodyEndBit, points[0].y)) | |||
| 6181 | return fail(); | |||
| 6182 | if (zIsZero) { | |||
| 6183 | points[0].z = 0.0; | |||
| 6184 | } else if (!readBoundedRawDouble(bodyProbe, bodyEndBit, | |||
| 6185 | points[0].z)) { | |||
| 6186 | return fail(); | |||
| 6187 | } | |||
| 6188 | ||||
| 6189 | if (!readBoundedDefaultDouble(bodyProbe, bodyEndBit, points[0].x, | |||
| 6190 | points[1].x) | |||
| 6191 | || !readBoundedDefaultDouble(bodyProbe, bodyEndBit, points[0].y, | |||
| 6192 | points[1].y) | |||
| 6193 | || !readBoundedDefaultDouble(bodyProbe, bodyEndBit, points[0].z, | |||
| 6194 | points[1].z) | |||
| 6195 | || !readBoundedDefaultDouble(bodyProbe, bodyEndBit, points[1].x, | |||
| 6196 | points[2].x) | |||
| 6197 | || !readBoundedDefaultDouble(bodyProbe, bodyEndBit, points[1].y, | |||
| 6198 | points[2].y) | |||
| 6199 | || !readBoundedDefaultDouble(bodyProbe, bodyEndBit, points[1].z, | |||
| 6200 | points[2].z) | |||
| 6201 | || !readBoundedDefaultDouble(bodyProbe, bodyEndBit, points[2].x, | |||
| 6202 | points[3].x) | |||
| 6203 | || !readBoundedDefaultDouble(bodyProbe, bodyEndBit, points[2].y, | |||
| 6204 | points[3].y) | |||
| 6205 | || !readBoundedDefaultDouble(bodyProbe, bodyEndBit, points[2].z, | |||
| 6206 | points[3].z)) | |||
| 6207 | return fail(); | |||
| 6208 | if (hasNoFlag) { | |||
| 6209 | parsedInvisibleFlag = NoEdge; | |||
| 6210 | } else if (!readBoundedBitShort(bodyProbe, bodyEndBit, | |||
| 6211 | parsedInvisibleFlag)) { | |||
| 6212 | return fail(); | |||
| 6213 | } | |||
| 6214 | } | |||
| 6215 | ||||
| 6216 | for (const DRW_Coord& point : points) { | |||
| 6217 | if (!std::isfinite(point.x) || !std::isfinite(point.y) | |||
| 6218 | || !std::isfinite(point.z)) | |||
| 6219 | return fail(); | |||
| 6220 | } | |||
| 6221 | if (parsedInvisibleFlag > AllEdges) | |||
| 6222 | return fail(); | |||
| 6223 | ||||
| 6224 | std::uint64_t handleEndBit = 0; | |||
| 6225 | if (!dwgHandleStreamEndBit(*sourceBuf, v, objSize, bs, handleEndBit)) | |||
| 6226 | return fail(); | |||
| 6227 | dwgBuffer handleProbe = bodyProbe.forkIndependent(); | |||
| 6228 | if (!DRW_Entity::parseDwgEntHandle(v, &handleProbe, true, handleEndBit) | |||
| 6229 | || !handleProbe.isGood()) | |||
| 6230 | return fail(); | |||
| 6231 | ||||
| 6232 | basePoint = points[0]; | |||
| 6233 | secPoint = points[1]; | |||
| 6234 | thirdPoint = points[2]; | |||
| 6235 | fourPoint = points[3]; | |||
| 6236 | invisibleflag = static_cast<int>(parsedInvisibleFlag); | |||
| 6237 | *sourceBuf = handleProbe; | |||
| 6238 | return true; | |||
| 6239 | } | |||
| 6240 | ||||
| 6241 | void DRW_ModelerGeometry::resetDwgState() { | |||
| 6242 | DRW_Entity::reset(); | |||
| 6243 | m_modelerVersion = 0; | |||
| 6244 | m_bodyBitSize = 0; | |||
| 6245 | m_objectSize = 0; | |||
| 6246 | m_isEmpty = false; | |||
| 6247 | m_hasModelerData = false; | |||
| 6248 | m_modelerDataUnknownBit = false; | |||
| 6249 | m_hasWireframe = false; | |||
| 6250 | m_historyHandle = 0; | |||
| 6251 | m_rawBytes.clear(); | |||
| 6252 | m_payloadRanges.clear(); | |||
| 6253 | m_wireframe = DRW_AcisBrep(); | |||
| 6254 | m_wireframeDecoded = false; | |||
| 6255 | } | |||
| 6256 | ||||
| 6257 | bool DRW_ModelerGeometry::parseDwg(DRW::Version v, dwgBuffer *buf, std::uint32_t bs){ | |||
| 6258 | resetDwgState(); | |||
| 6259 | dwgBuffer *sourceBuf = buf; | |||
| 6260 | auto fail = [this, sourceBuf]() { | |||
| 6261 | if (sourceBuf != nullptr) | |||
| 6262 | sourceBuf->invalidate(); | |||
| 6263 | resetDwgState(); | |||
| 6264 | return false; | |||
| 6265 | }; | |||
| 6266 | if (sourceBuf == nullptr) | |||
| 6267 | return fail(); | |||
| 6268 | ||||
| 6269 | dwgBuffer probe = sourceBuf->forkIndependent(); | |||
| 6270 | dwgBuffer stringProbe = sourceBuf->forkIndependent(); | |||
| 6271 | dwgBuffer *stringStream = v > DRW::AC1018 ? &stringProbe : nullptr; | |||
| 6272 | bool ret = DRW_Entity::parseDwg(v, &probe, stringStream, bs); | |||
| 6273 | if (!ret) | |||
| 6274 | return fail(); | |||
| 6275 | DRW_DBG("\n***************************** parsing modeler geometry ******************\n")DRW_dbg::dbg("\n***************************** parsing modeler geometry ******************\n" ); | |||
| 6276 | ||||
| 6277 | std::uint64_t bodyEndBit = 0; | |||
| 6278 | if (!entityBodyDataEndBit( | |||
| 6279 | stringStream != nullptr ? *stringStream : probe, | |||
| 6280 | v, objSize, bodyEndBit)) | |||
| 6281 | return fail(); | |||
| 6282 | const std::uint64_t sourceEndBit = proxyEntityEndBit(*sourceBuf, 0); | |||
| 6283 | if ((v >= DRW::AC1015 && objSize == 0) || bodyEndBit > sourceEndBit | |||
| 6284 | || currentDwgBit(&probe) > bodyEndBit) | |||
| 6285 | return fail(); | |||
| 6286 | bool parsedIsEmpty = false; | |||
| 6287 | bool parsedUnknownBit = false; | |||
| 6288 | std::uint16_t parsedModelerVersion = 0; | |||
| 6289 | if (!readBoundedBit(probe, bodyEndBit, parsedIsEmpty) | |||
| 6290 | || !readBoundedBit(probe, bodyEndBit, parsedUnknownBit)) | |||
| 6291 | return fail(); | |||
| 6292 | const bool parsedHasModelerData = !parsedIsEmpty; | |||
| 6293 | if (parsedHasModelerData | |||
| 6294 | && !readBoundedBitShort(probe, bodyEndBit, parsedModelerVersion)) | |||
| 6295 | return fail(); | |||
| 6296 | if (!probe.isGood() || (stringStream != nullptr && !stringStream->isGood())) | |||
| 6297 | return fail(); | |||
| 6298 | ||||
| 6299 | std::uint64_t handleEndBit = 0; | |||
| 6300 | if (!dwgHandleStreamEndBit(*sourceBuf, v, objSize, bs, handleEndBit)) | |||
| 6301 | return fail(); | |||
| 6302 | // R13-R2004 modeler bodies contain opaque ACIS/SAT data between this | |||
| 6303 | // header and the common handles. Do not interpret that payload: jump to | |||
| 6304 | // the bounded object-data end exactly as the surface/proxy readers do. | |||
| 6305 | dwgBuffer handleProbe = sourceBuf->forkIndependent(); | |||
| 6306 | if (v <= DRW::AC1018) { | |||
| 6307 | if (!handleProbe.setPosition(bodyEndBit >> 3)) | |||
| 6308 | return fail(); | |||
| 6309 | handleProbe.setBitPos(static_cast<std::uint8_t>(bodyEndBit & 7u)); | |||
| 6310 | if (!handleProbe.isGood()) | |||
| 6311 | return fail(); | |||
| 6312 | } | |||
| 6313 | ret = DRW_Entity::parseDwgEntHandle(v, &handleProbe, true, handleEndBit); | |||
| 6314 | if (!ret || !handleProbe.isGood()) | |||
| 6315 | return fail(); | |||
| 6316 | std::uint32_t parsedHistoryHandle = 0; | |||
| 6317 | if (eType == DRW::E3DSOLID && v > DRW::AC1018 | |||
| 6318 | && proxyEntityHasBits(handleProbe, handleEndBit, 8)) { | |||
| 6319 | dwgHandle historyH; | |||
| 6320 | if (!readBoundedDwgHandle(handleProbe, handleEndBit, 0, false, | |||
| 6321 | historyH)) | |||
| 6322 | return fail(); | |||
| 6323 | parsedHistoryHandle = historyH.ref; | |||
| 6324 | DRW_DBG(" 3DSOLID history Handle: ")DRW_dbg::dbg(" 3DSOLID history Handle: "); | |||
| 6325 | DRW_DBGHL(historyH.code, historyH.size, historyH.ref)DRW_dbg::dbgHL(historyH.code, historyH.size, historyH.ref); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 6326 | } | |||
| 6327 | ||||
| 6328 | if (handleProbe.size() > std::numeric_limits<std::uint32_t>::max()) | |||
| 6329 | return fail(); | |||
| 6330 | m_bodyBitSize = bs; | |||
| 6331 | m_objectSize = static_cast<std::uint32_t>(probe.size()); | |||
| 6332 | m_isEmpty = parsedIsEmpty; | |||
| 6333 | m_hasModelerData = parsedHasModelerData; | |||
| 6334 | m_modelerDataUnknownBit = parsedUnknownBit; | |||
| 6335 | m_modelerVersion = parsedModelerVersion; | |||
| 6336 | m_historyHandle = parsedHistoryHandle; | |||
| 6337 | *sourceBuf = handleProbe; | |||
| 6338 | return true; | |||
| 6339 | } | |||
| 6340 | ||||
| 6341 | bool DRW_ModelerGeometry::parseCode(int code, const std::unique_ptr<dxfReader>& reader) { | |||
| 6342 | switch (code) { | |||
| 6343 | case 1: | |||
| 6344 | case 3: | |||
| 6345 | if (!appendTextBytesChecked(m_rawBytes, reader->getString(), | |||
| 6346 | dwgSafety::MaxBufferSize)) | |||
| 6347 | return false; | |||
| 6348 | break; | |||
| 6349 | case 70: { | |||
| 6350 | const int value = reader->getInt32(); | |||
| 6351 | if (value < 0 || value > std::numeric_limits<std::uint16_t>::max()) | |||
| 6352 | return false; | |||
| 6353 | m_modelerVersion = static_cast<std::uint16_t>(value); | |||
| 6354 | break; | |||
| 6355 | } | |||
| 6356 | case 350: | |||
| 6357 | case 360: | |||
| 6358 | m_historyHandle = static_cast<std::uint32_t>(reader->getHandleString()); | |||
| 6359 | break; | |||
| 6360 | case 310: | |||
| 6361 | { | |||
| 6362 | std::vector<std::uint8_t> decoded; | |||
| 6363 | if (!decodeHexBytes(reader->getString(), decoded)) | |||
| 6364 | return false; | |||
| 6365 | if (!appendBytesChecked(m_rawBytes, decoded, | |||
| 6366 | dwgSafety::MaxBufferSize)) | |||
| 6367 | return false; | |||
| 6368 | } | |||
| 6369 | break; | |||
| 6370 | default: | |||
| 6371 | return DRW_Entity::parseCode(code, reader); | |||
| 6372 | } | |||
| 6373 | return true; | |||
| 6374 | } | |||
| 6375 | ||||
| 6376 | void DRW_Mesh::resetDwgState() { | |||
| 6377 | DRW_Entity::reset(); | |||
| 6378 | version = 2; | |||
| 6379 | blendCrease = false; | |||
| 6380 | subdivisionLevel = 0; | |||
| 6381 | subdivVertices.clear(); | |||
| 6382 | vertices.clear(); | |||
| 6383 | faces.clear(); | |||
| 6384 | edges.clear(); | |||
| 6385 | creases.clear(); | |||
| 6386 | unknown = 0; | |||
| 6387 | propertyOverrides.clear(); | |||
| 6388 | m_dxfMeshSubclassSeen = false; | |||
| 6389 | m_dxfState = 0; | |||
| 6390 | m_dxfVertexCount = -1; | |||
| 6391 | m_dxfFaceItemsRemaining = -1; | |||
| 6392 | m_dxfEdgeValuesRemaining = -1; | |||
| 6393 | m_dxfCreaseValuesRemaining = -1; | |||
| 6394 | m_dxfPending = 0; | |||
| 6395 | m_dxfEdgeFrom = -1; | |||
| 6396 | m_dxfOverrideEntityCount = -1; | |||
| 6397 | m_dxfOverridePropertyCount = -1; | |||
| 6398 | } | |||
| 6399 | ||||
| 6400 | // DRW_Mesh::parseDwg — AcDbSubDMesh, field order shared by ACadSharp and | |||
| 6401 | // dwgTs. DWG group 91 is the subdivision level, not a refined-vertex count; | |||
| 6402 | // the following BL is the level-0 vertex count. | |||
| 6403 | bool DRW_Mesh::parseDwg(DRW::Version v, dwgBuffer *buf, std::uint32_t bs){ | |||
| 6404 | resetDwgState(); | |||
| 6405 | dwgBuffer *sourceBuf = buf; | |||
| 6406 | auto fail = [this, sourceBuf]() { | |||
| 6407 | if (sourceBuf != nullptr) | |||
| 6408 | sourceBuf->invalidate(); | |||
| 6409 | resetDwgState(); | |||
| 6410 | return false; | |||
| 6411 | }; | |||
| 6412 | if (sourceBuf == nullptr) | |||
| 6413 | return fail(); | |||
| 6414 | ||||
| 6415 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 6416 | dwgBuffer stringProbe = sourceBuf->forkIndependent(); | |||
| 6417 | dwgBuffer *stringStream = v > DRW::AC1018 ? &stringProbe : nullptr; | |||
| 6418 | if (!DRW_Entity::parseDwg(v, &bodyProbe, stringStream, bs)) | |||
| 6419 | return fail(); | |||
| 6420 | buf = &bodyProbe; | |||
| 6421 | DRW_DBG("\n***************************** parsing MESH (AcDbSubDMesh) *****************\n")DRW_dbg::dbg("\n***************************** parsing MESH (AcDbSubDMesh) *****************\n" ); | |||
| 6422 | std::uint64_t bodyEndBit = 0; | |||
| 6423 | if (!entityBodyDataEndBit( | |||
| 6424 | stringStream != nullptr ? *stringStream : bodyProbe, | |||
| 6425 | v, objSize, bodyEndBit)) | |||
| 6426 | return fail(); | |||
| 6427 | ||||
| 6428 | auto readCount = [&](std::uint32_t minimumBitsPerItem, | |||
| 6429 | std::uint32_t& count) { | |||
| 6430 | return readTableBodyCount( | |||
| 6431 | v, buf, static_cast<std::uint32_t>(bodyEndBit), | |||
| 6432 | DRW_Mesh::kMaxMeshItems, minimumBitsPerItem, count); | |||
| 6433 | }; | |||
| 6434 | ||||
| 6435 | std::uint16_t parsedVersion = 0; | |||
| 6436 | bool parsedBlendCrease = false; | |||
| 6437 | std::int32_t parsedSubdivisionLevel = 0; | |||
| 6438 | if (!readBoundedBitShort(*buf, bodyEndBit, parsedVersion) | |||
| 6439 | || !readBoundedBit(*buf, bodyEndBit, parsedBlendCrease) | |||
| 6440 | || !readBoundedBitLong(*buf, bodyEndBit, parsedSubdivisionLevel) | |||
| 6441 | || parsedSubdivisionLevel < 0) { | |||
| 6442 | return fail(); | |||
| 6443 | } | |||
| 6444 | ||||
| 6445 | std::uint32_t nVert = 0; // BL vertex count (92) | |||
| 6446 | if (!readCount(6, nVert)) return fail(); // minimum 3BD width | |||
| 6447 | std::vector<DRW_Coord> parsedVertices; | |||
| 6448 | if (!DRW::reserve(parsedVertices, static_cast<int>(nVert))) | |||
| 6449 | return fail(); | |||
| 6450 | std::vector<std::vector<std::int32_t>> parsedFaces; | |||
| 6451 | std::vector<std::pair<std::int32_t, std::int32_t>> parsedEdges; | |||
| 6452 | std::vector<double> parsedCreases; | |||
| 6453 | for (std::uint32_t i = 0; i < nVert; ++i) { | |||
| 6454 | DRW_Coord point; | |||
| 6455 | if (!readBoundedBitCoord(*buf, bodyEndBit, point)) | |||
| 6456 | return fail(); | |||
| 6457 | parsedVertices.push_back(point); | |||
| 6458 | } | |||
| 6459 | const auto finite = [](const DRW_Coord& point) { | |||
| 6460 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 6461 | && std::isfinite(point.z); | |||
| 6462 | }; | |||
| 6463 | if (!buf->isGood() | |||
| 6464 | || (stringStream != nullptr && !stringStream->isGood()) | |||
| 6465 | || !std::all_of(parsedVertices.begin(), parsedVertices.end(), finite)) | |||
| 6466 | return fail(); | |||
| 6467 | ||||
| 6468 | // faces (93) is a FLAT BL stream of length num_faces; each face is | |||
| 6469 | // [count, idx0, idx1, ...]. num_faces is the stream length, not the polygon | |||
| 6470 | // count — group on the fly. | |||
| 6471 | std::uint32_t faceItems = 0; // BL face-list size (93) | |||
| 6472 | if (!readCount(2, faceItems)) return fail(); | |||
| 6473 | std::int32_t remaining = static_cast<std::int32_t>(faceItems); | |||
| 6474 | while (remaining > 0 && buf->isGood()) { | |||
| 6475 | std::int32_t cnt = 0; | |||
| 6476 | if (!readBoundedBitLong(*buf, bodyEndBit, cnt)) | |||
| 6477 | return fail(); | |||
| 6478 | --remaining; | |||
| 6479 | if (cnt < 0 || cnt > remaining) | |||
| 6480 | return fail(); | |||
| 6481 | std::vector<std::int32_t> face; | |||
| 6482 | if (!DRW::reserve(face, cnt)) | |||
| 6483 | return fail(); | |||
| 6484 | for (std::int32_t j = 0; j < cnt; ++j) { | |||
| 6485 | std::int32_t index = 0; | |||
| 6486 | if (!readBoundedBitLong(*buf, bodyEndBit, index)) | |||
| 6487 | return fail(); | |||
| 6488 | if (index < 0 || static_cast<std::uint32_t>(index) >= nVert) | |||
| 6489 | return fail(); | |||
| 6490 | face.push_back(index); | |||
| 6491 | --remaining; | |||
| 6492 | } | |||
| 6493 | if (!buf->isGood()) return fail(); | |||
| 6494 | parsedFaces.push_back(std::move(face)); | |||
| 6495 | } | |||
| 6496 | if (remaining != 0 || !buf->isGood()) return fail(); | |||
| 6497 | ||||
| 6498 | std::uint32_t nEdges = 0; // BL edge count (94) | |||
| 6499 | if (!readCount(4, nEdges)) return fail(); // two minimum-width BL values | |||
| 6500 | if (!DRW::reserve(parsedEdges, static_cast<int>(nEdges))) | |||
| 6501 | return fail(); | |||
| 6502 | for (std::uint32_t i = 0; i < nEdges; ++i) { | |||
| 6503 | std::int32_t from = 0; | |||
| 6504 | std::int32_t to = 0; | |||
| 6505 | if (!readBoundedBitLong(*buf, bodyEndBit, from) | |||
| 6506 | || !readBoundedBitLong(*buf, bodyEndBit, to)) | |||
| 6507 | return fail(); | |||
| 6508 | if (from < 0 || to < 0 | |||
| 6509 | || static_cast<std::uint32_t>(from) >= nVert | |||
| 6510 | || static_cast<std::uint32_t>(to) >= nVert) | |||
| 6511 | return fail(); | |||
| 6512 | parsedEdges.emplace_back(from, to); | |||
| 6513 | } | |||
| 6514 | if (!buf->isGood()) return fail(); | |||
| 6515 | ||||
| 6516 | std::uint32_t nCrease = 0; // BL crease count (95) | |||
| 6517 | if (!readCount(2, nCrease)) return fail(); // minimum-width BD value | |||
| 6518 | if (!DRW::reserve(parsedCreases, static_cast<int>(nCrease))) | |||
| 6519 | return fail(); | |||
| 6520 | for (std::uint32_t i = 0; i < nCrease; ++i) { | |||
| 6521 | double crease = 0.0; | |||
| 6522 | if (!readBoundedBitDouble(*buf, bodyEndBit, crease)) | |||
| 6523 | return fail(); | |||
| 6524 | parsedCreases.push_back(crease); | |||
| 6525 | } | |||
| 6526 | if (!buf->isGood() | |||
| 6527 | || !std::all_of(parsedCreases.begin(), parsedCreases.end(), | |||
| 6528 | [](double value) { return std::isfinite(value); })) | |||
| 6529 | return fail(); | |||
| 6530 | ||||
| 6531 | std::int32_t parsedUnknown = 0; | |||
| 6532 | if (!readBoundedBitLong(*buf, bodyEndBit, parsedUnknown)) | |||
| 6533 | return fail(); // trailing unknown (BL) | |||
| 6534 | ||||
| 6535 | std::uint64_t handleEndBit = 0; | |||
| 6536 | if (!dwgHandleStreamEndBit(*sourceBuf, v, objSize, bs, handleEndBit)) | |||
| 6537 | return fail(); | |||
| 6538 | dwgBuffer handleProbe = bodyProbe.forkIndependent(); | |||
| 6539 | if (!DRW_Entity::parseDwgEntHandle(v, &handleProbe, true, handleEndBit) | |||
| 6540 | || !handleProbe.isGood()) | |||
| 6541 | return fail(); | |||
| 6542 | vertices = std::move(parsedVertices); | |||
| 6543 | faces = std::move(parsedFaces); | |||
| 6544 | edges = std::move(parsedEdges); | |||
| 6545 | creases = std::move(parsedCreases); | |||
| 6546 | version = parsedVersion; | |||
| 6547 | blendCrease = parsedBlendCrease; | |||
| 6548 | subdivisionLevel = parsedSubdivisionLevel; | |||
| 6549 | unknown = parsedUnknown; | |||
| 6550 | *sourceBuf = handleProbe; | |||
| 6551 | return true; | |||
| 6552 | } | |||
| 6553 | ||||
| 6554 | // DRW_Mesh::parseCode — DXF read (codes 71/72/91/92/10·20·30/93/90/94/95/140). | |||
| 6555 | // The 90 stream is shared by faces (after 93) and edges (after 94); m_dxfState | |||
| 6556 | // sequences which one is being filled (mirrors DRW_Image::parseCode's stateful | |||
| 6557 | // 91/14/24 WIPEOUT-vertex accumulation). After the crease stream, group 90 | |||
| 6558 | // starts the bounded property-override records described by AcDbSubDMesh. | |||
| 6559 | bool DRW_Mesh::parseCode(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 6560 | try { | |||
| 6561 | switch (code) { | |||
| 6562 | case 71: { | |||
| 6563 | const std::int32_t value = reader->getInt32(); | |||
| 6564 | if (value < 0 || value > std::numeric_limits<std::int16_t>::max()) | |||
| 6565 | return false; | |||
| 6566 | version = static_cast<std::uint16_t>(value); | |||
| 6567 | return true; | |||
| 6568 | } | |||
| 6569 | case 72: { | |||
| 6570 | const std::int32_t value = reader->getInt32(); | |||
| 6571 | if (value != 0 && value != 1) | |||
| 6572 | return false; | |||
| 6573 | blendCrease = value != 0; | |||
| 6574 | return true; | |||
| 6575 | } | |||
| 6576 | case 91: { | |||
| 6577 | const std::int32_t value = reader->getInt32(); | |||
| 6578 | if (m_dxfOverrideEntityCount >= 0) { | |||
| 6579 | if (m_dxfState != 96 | |||
| 6580 | || (!propertyOverrides.empty() && m_dxfOverridePropertyCount != 0) | |||
| 6581 | || propertyOverrides.size() >= static_cast<std::size_t>(m_dxfOverrideEntityCount)) | |||
| 6582 | return false; | |||
| 6583 | propertyOverrides.push_back({value, {}}); | |||
| 6584 | m_dxfOverridePropertyCount = -1; | |||
| 6585 | return true; | |||
| 6586 | } | |||
| 6587 | if (value < 0) | |||
| 6588 | return false; | |||
| 6589 | subdivisionLevel = value; | |||
| 6590 | return true; | |||
| 6591 | } | |||
| 6592 | case 100: | |||
| 6593 | if (reader->getString() == "AcDbSubDMesh") | |||
| 6594 | m_dxfMeshSubclassSeen = true; | |||
| 6595 | return true; | |||
| 6596 | case 92: { // base-vertex count; later 92 values belong to overrides | |||
| 6597 | if (!m_dxfMeshSubclassSeen) | |||
| 6598 | return DRW_Entity::parseCode(code, reader); | |||
| 6599 | if (m_dxfVertexCount >= 0) { | |||
| 6600 | if (m_dxfOverrideEntityCount < 0 || m_dxfState != 96 | |||
| 6601 | || propertyOverrides.empty() || m_dxfOverridePropertyCount >= 0) | |||
| 6602 | return false; | |||
| 6603 | const std::int32_t count = reader->getInt32(); | |||
| 6604 | if (!isValidCount(count, 4)) | |||
| 6605 | return false; | |||
| 6606 | if (!DRW::reserve(propertyOverrides.back().propertyTypes, count)) | |||
| 6607 | return false; | |||
| 6608 | m_dxfOverridePropertyCount = count; | |||
| 6609 | return true; | |||
| 6610 | } | |||
| 6611 | const std::int32_t count = reader->getInt32(); | |||
| 6612 | if (!isValidCount(count, DRW_Mesh::kMaxMeshItems)) | |||
| 6613 | return false; | |||
| 6614 | if (!DRW::reserve(vertices, count)) | |||
| 6615 | return false; | |||
| 6616 | m_dxfVertexCount = count; | |||
| 6617 | m_dxfState = 92; | |||
| 6618 | return true; | |||
| 6619 | } | |||
| 6620 | case 10: | |||
| 6621 | if (m_dxfState != 92 || m_dxfVertexCount < 0 | |||
| 6622 | || vertices.size() >= static_cast<std::size_t>(m_dxfVertexCount)) | |||
| 6623 | return false; | |||
| 6624 | { | |||
| 6625 | const double value = reader->getDouble(); | |||
| 6626 | if (!std::isfinite(value)) | |||
| 6627 | return false; | |||
| 6628 | vertices.emplace_back(); | |||
| 6629 | vertices.back().x = value; | |||
| 6630 | } | |||
| 6631 | return true; | |||
| 6632 | case 20: | |||
| 6633 | if (m_dxfState != 92 || vertices.empty()) | |||
| 6634 | return false; | |||
| 6635 | { | |||
| 6636 | const double value = reader->getDouble(); | |||
| 6637 | if (!std::isfinite(value)) | |||
| 6638 | return false; | |||
| 6639 | vertices.back().y = value; | |||
| 6640 | } | |||
| 6641 | return true; | |||
| 6642 | case 30: | |||
| 6643 | if (m_dxfState != 92 || vertices.empty()) | |||
| 6644 | return false; | |||
| 6645 | { | |||
| 6646 | const double value = reader->getDouble(); | |||
| 6647 | if (!std::isfinite(value)) | |||
| 6648 | return false; | |||
| 6649 | vertices.back().z = value; | |||
| 6650 | } | |||
| 6651 | return true; | |||
| 6652 | case 93: { // face-list item count | |||
| 6653 | if (m_dxfVertexCount < 0 | |||
| 6654 | || vertices.size() != static_cast<std::size_t>(m_dxfVertexCount)) | |||
| 6655 | return false; | |||
| 6656 | const std::int32_t count = reader->getInt32(); | |||
| 6657 | if (!isValidCount(count, DRW_Mesh::kMaxMeshItems)) | |||
| 6658 | return false; | |||
| 6659 | m_dxfState = 93; | |||
| 6660 | m_dxfFaceItemsRemaining = count; | |||
| 6661 | m_dxfPending = 0; | |||
| 6662 | return true; | |||
| 6663 | } | |||
| 6664 | case 94: { // edge count; each edge consumes two code-90 values | |||
| 6665 | if (m_dxfFaceItemsRemaining != 0 || m_dxfPending != 0) | |||
| 6666 | return false; | |||
| 6667 | const std::int32_t count = reader->getInt32(); | |||
| 6668 | if (!isValidCount(count, DRW_Mesh::kMaxMeshItems)) | |||
| 6669 | return false; | |||
| 6670 | m_dxfState = 94; | |||
| 6671 | m_dxfEdgeValuesRemaining = count * 2; | |||
| 6672 | m_dxfEdgeFrom = -1; | |||
| 6673 | if (!DRW::reserve(edges, count)) | |||
| 6674 | return false; | |||
| 6675 | return true; | |||
| 6676 | } | |||
| 6677 | case 90: { | |||
| 6678 | const std::int32_t val = reader->getInt32(); | |||
| 6679 | if (m_dxfState == 95) { | |||
| 6680 | if (m_dxfCreaseValuesRemaining != 0) | |||
| 6681 | return false; | |||
| 6682 | if (m_dxfOverrideEntityCount >= 0) | |||
| 6683 | return false; | |||
| 6684 | if (!isValidCount(val, DRW_Mesh::kMaxMeshItems)) | |||
| 6685 | return false; | |||
| 6686 | m_dxfOverrideEntityCount = val; | |||
| 6687 | m_dxfOverridePropertyCount = val == 0 ? 0 : -1; | |||
| 6688 | m_dxfState = 96; | |||
| 6689 | } else if (m_dxfState == 96) { | |||
| 6690 | if (m_dxfOverrideEntityCount < 0 || propertyOverrides.empty() | |||
| 6691 | || m_dxfOverridePropertyCount <= 0 || val < 0 || val > 3) | |||
| 6692 | return false; | |||
| 6693 | propertyOverrides.back().propertyTypes.push_back(val); | |||
| 6694 | --m_dxfOverridePropertyCount; | |||
| 6695 | } else if (m_dxfState == 93) { | |||
| 6696 | if (m_dxfFaceItemsRemaining <= 0) | |||
| 6697 | return false; | |||
| 6698 | if (m_dxfPending == 0) { | |||
| 6699 | if (val < 3 || val > m_dxfFaceItemsRemaining - 1) | |||
| 6700 | return false; | |||
| 6701 | faces.emplace_back(); | |||
| 6702 | m_dxfPending = val; | |||
| 6703 | --m_dxfFaceItemsRemaining; | |||
| 6704 | } else { | |||
| 6705 | if (val < 0 || val >= m_dxfVertexCount) | |||
| 6706 | return false; | |||
| 6707 | if (!faces.empty()) | |||
| 6708 | faces.back().push_back(val); | |||
| 6709 | --m_dxfFaceItemsRemaining; | |||
| 6710 | --m_dxfPending; | |||
| 6711 | } | |||
| 6712 | } else if (m_dxfState == 94) { | |||
| 6713 | if (m_dxfEdgeValuesRemaining <= 0 || val < 0 || val >= m_dxfVertexCount) | |||
| 6714 | return false; | |||
| 6715 | --m_dxfEdgeValuesRemaining; | |||
| 6716 | if (m_dxfEdgeFrom < 0) | |||
| 6717 | m_dxfEdgeFrom = val; | |||
| 6718 | else { | |||
| 6719 | edges.emplace_back(m_dxfEdgeFrom, val); | |||
| 6720 | m_dxfEdgeFrom = -1; | |||
| 6721 | } | |||
| 6722 | } else { | |||
| 6723 | return false; | |||
| 6724 | } | |||
| 6725 | return true; | |||
| 6726 | } | |||
| 6727 | case 95: { // edge crease count | |||
| 6728 | if (m_dxfEdgeValuesRemaining != 0 || m_dxfEdgeFrom != -1) | |||
| 6729 | return false; | |||
| 6730 | const std::int32_t count = reader->getInt32(); | |||
| 6731 | if (!isValidCount(count, DRW_Mesh::kMaxMeshItems)) | |||
| 6732 | return false; | |||
| 6733 | m_dxfState = 95; | |||
| 6734 | m_dxfCreaseValuesRemaining = count; | |||
| 6735 | if (!DRW::reserve(creases, count)) | |||
| 6736 | return false; | |||
| 6737 | return true; | |||
| 6738 | } | |||
| 6739 | case 140: | |||
| 6740 | if (m_dxfState != 95 || m_dxfCreaseValuesRemaining <= 0) | |||
| 6741 | return false; | |||
| 6742 | { | |||
| 6743 | const double value = reader->getDouble(); | |||
| 6744 | if (!std::isfinite(value)) | |||
| 6745 | return false; | |||
| 6746 | creases.push_back(value); | |||
| 6747 | } | |||
| 6748 | --m_dxfCreaseValuesRemaining; | |||
| 6749 | return true; | |||
| 6750 | default: | |||
| 6751 | return DRW_Entity::parseCode(code, reader); | |||
| 6752 | } | |||
| 6753 | } catch (...) { | |||
| 6754 | return false; | |||
| 6755 | } | |||
| 6756 | } | |||
| 6757 | ||||
| 6758 | bool DRW_Mesh::validateGeometry() const { | |||
| 6759 | if (subdivisionLevel < 0 | |||
| 6760 | || vertices.size() > static_cast<std::size_t>(kMaxMeshItems) | |||
| 6761 | || edges.size() > static_cast<std::size_t>(kMaxMeshItems) | |||
| 6762 | || faces.size() > static_cast<std::size_t>(kMaxMeshItems) | |||
| 6763 | || creases.size() > static_cast<std::size_t>(kMaxMeshItems)) | |||
| 6764 | return false; | |||
| 6765 | ||||
| 6766 | const auto finite = [](const DRW_Coord& point) { | |||
| 6767 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 6768 | && std::isfinite(point.z); | |||
| 6769 | }; | |||
| 6770 | if (!std::all_of(vertices.cbegin(), vertices.cend(), finite) | |||
| 6771 | || !std::all_of(creases.cbegin(), creases.cend(), | |||
| 6772 | [](double value) { return std::isfinite(value); })) | |||
| 6773 | return false; | |||
| 6774 | std::int32_t faceStreamCount = 0; | |||
| 6775 | for (const auto& face : faces) { | |||
| 6776 | if (face.size() < 3 | |||
| 6777 | || face.size() > static_cast<std::size_t>(kMaxMeshItems - 1) | |||
| 6778 | || faceStreamCount > kMaxMeshItems | |||
| 6779 | - static_cast<std::int32_t>(face.size() + 1)) | |||
| 6780 | return false; | |||
| 6781 | for (std::int32_t index : face) { | |||
| 6782 | if (index < 0 | |||
| 6783 | || static_cast<std::size_t>(index) >= vertices.size()) | |||
| 6784 | return false; | |||
| 6785 | } | |||
| 6786 | faceStreamCount += static_cast<std::int32_t>(face.size() + 1); | |||
| 6787 | } | |||
| 6788 | for (const auto& edge : edges) { | |||
| 6789 | if (edge.first < 0 || edge.second < 0 | |||
| 6790 | || static_cast<std::size_t>(edge.first) >= vertices.size() | |||
| 6791 | || static_cast<std::size_t>(edge.second) >= vertices.size()) | |||
| 6792 | return false; | |||
| 6793 | } | |||
| 6794 | return true; | |||
| 6795 | } | |||
| 6796 | ||||
| 6797 | bool DRW_Mesh::validateDxf() const { | |||
| 6798 | if (!m_dxfMeshSubclassSeen | |||
| 6799 | || m_dxfVertexCount < 0 | |||
| 6800 | || vertices.size() != static_cast<std::size_t>(m_dxfVertexCount) | |||
| 6801 | || m_dxfFaceItemsRemaining != 0 | |||
| 6802 | || m_dxfPending != 0 | |||
| 6803 | || m_dxfEdgeValuesRemaining != 0 | |||
| 6804 | || m_dxfEdgeFrom != -1 | |||
| 6805 | || m_dxfCreaseValuesRemaining != 0 | |||
| 6806 | || (m_dxfOverrideEntityCount >= 0 | |||
| 6807 | && (m_dxfOverridePropertyCount < 0 | |||
| 6808 | || m_dxfOverridePropertyCount != 0 | |||
| 6809 | || propertyOverrides.size() != static_cast<std::size_t>(m_dxfOverrideEntityCount)))) | |||
| 6810 | return false; | |||
| 6811 | for (const auto& overrideData : propertyOverrides) { | |||
| 6812 | if (overrideData.subEntityMarker < 0 | |||
| 6813 | || overrideData.propertyTypes.size() > 4u) | |||
| 6814 | return false; | |||
| 6815 | if (!std::all_of(overrideData.propertyTypes.cbegin(), | |||
| 6816 | overrideData.propertyTypes.cend(), | |||
| 6817 | [](std::int32_t type) { return type >= 0 && type <= 3; })) | |||
| 6818 | return false; | |||
| 6819 | } | |||
| 6820 | return validateGeometry(); | |||
| 6821 | } | |||
| 6822 | ||||
| 6823 | bool DRW_Mesh::validateDxfOutput() const { | |||
| 6824 | if (version > static_cast<std::uint16_t>(std::numeric_limits<std::int16_t>::max()) | |||
| 6825 | || propertyOverrides.size() > static_cast<std::size_t>(kMaxMeshItems)) | |||
| 6826 | return false; | |||
| 6827 | for (const auto& overrideData : propertyOverrides) { | |||
| 6828 | if (overrideData.subEntityMarker < 0 | |||
| 6829 | || overrideData.propertyTypes.size() > 4u | |||
| 6830 | || !std::all_of(overrideData.propertyTypes.cbegin(), | |||
| 6831 | overrideData.propertyTypes.cend(), | |||
| 6832 | [](std::int32_t type) { return type >= 0 && type <= 3; })) | |||
| 6833 | return false; | |||
| 6834 | } | |||
| 6835 | return validateGeometry(); | |||
| 6836 | } | |||
| 6837 | ||||
| 6838 | bool DRW_Mesh::encodeDwg(DRW::Version dwgVersion, dwgBufferW *buf, std::uint32_t bs, | |||
| 6839 | dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 6840 | (void)bs; (void)strBuf; | |||
| 6841 | if (!validateGeometry()) | |||
| 6842 | return false; | |||
| 6843 | ||||
| 6844 | std::int32_t faceStreamCount = 0; | |||
| 6845 | for (const auto& face : faces) | |||
| 6846 | faceStreamCount += static_cast<std::int32_t>(face.size() + 1); | |||
| 6847 | ||||
| 6848 | oType = kDwgClassNum; | |||
| 6849 | if (!encodeDwgCommon(dwgVersion, buf)) return false; | |||
| 6850 | ||||
| 6851 | buf->putBitShort(version); | |||
| 6852 | buf->putBit(blendCrease ? 1 : 0); | |||
| 6853 | ||||
| 6854 | buf->putBitLong(subdivisionLevel); | |||
| 6855 | ||||
| 6856 | buf->putBitLong(static_cast<std::int32_t>(vertices.size())); | |||
| 6857 | for (const DRW_Coord& vertex : vertices) | |||
| 6858 | buf->put3BitDouble(vertex); | |||
| 6859 | ||||
| 6860 | buf->putBitLong(faceStreamCount); | |||
| 6861 | for (const auto& face : faces) { | |||
| 6862 | buf->putBitLong(static_cast<std::int32_t>(face.size())); | |||
| 6863 | for (std::int32_t index : face) | |||
| 6864 | buf->putBitLong(index); | |||
| 6865 | } | |||
| 6866 | ||||
| 6867 | buf->putBitLong(static_cast<std::int32_t>(edges.size())); | |||
| 6868 | for (const auto& edge : edges) { | |||
| 6869 | buf->putBitLong(edge.first); | |||
| 6870 | buf->putBitLong(edge.second); | |||
| 6871 | } | |||
| 6872 | ||||
| 6873 | buf->putBitLong(static_cast<std::int32_t>(creases.size())); | |||
| 6874 | for (double crease : creases) | |||
| 6875 | buf->putBitDouble(crease); | |||
| 6876 | ||||
| 6877 | buf->putBitLong(unknown); | |||
| 6878 | ||||
| 6879 | return encodeDwgEntHandle(dwgVersion, buf, handleBuf); | |||
| 6880 | } | |||
| 6881 | ||||
| 6882 | bool DRW_Shape::parseCode(int code, const std::unique_ptr<dxfReader>& reader) { | |||
| 6883 | switch (code) { | |||
| 6884 | case 2: | |||
| 6885 | m_styleName = reader->getUtf8String(); | |||
| 6886 | break; | |||
| 6887 | case 10: | |||
| 6888 | m_insertionPoint.x = reader->getDouble(); | |||
| 6889 | break; | |||
| 6890 | case 20: | |||
| 6891 | m_insertionPoint.y = reader->getDouble(); | |||
| 6892 | break; | |||
| 6893 | case 30: | |||
| 6894 | m_insertionPoint.z = reader->getDouble(); | |||
| 6895 | break; | |||
| 6896 | case 39: | |||
| 6897 | m_thickness = reader->getDouble(); | |||
| 6898 | break; | |||
| 6899 | case 40: | |||
| 6900 | m_scale = reader->getDouble(); | |||
| 6901 | break; | |||
| 6902 | case 41: | |||
| 6903 | m_widthFactor = reader->getDouble(); | |||
| 6904 | break; | |||
| 6905 | case 50: | |||
| 6906 | m_rotation = reader->getDouble() / ARAD57.29577951308232; | |||
| 6907 | break; | |||
| 6908 | case 51: | |||
| 6909 | m_oblique = reader->getDouble() / ARAD57.29577951308232; | |||
| 6910 | break; | |||
| 6911 | case 210: | |||
| 6912 | m_extrusion.x = reader->getDouble(); | |||
| 6913 | break; | |||
| 6914 | case 220: | |||
| 6915 | m_extrusion.y = reader->getDouble(); | |||
| 6916 | break; | |||
| 6917 | case 230: | |||
| 6918 | m_extrusion.z = reader->getDouble(); | |||
| 6919 | break; | |||
| 6920 | default: | |||
| 6921 | return DRW_Entity::parseCode(code, reader); | |||
| 6922 | } | |||
| 6923 | return true; | |||
| 6924 | } | |||
| 6925 | ||||
| 6926 | void DRW_Shape::resetDwgState() { | |||
| 6927 | DRW_Entity::reset(); | |||
| 6928 | m_insertionPoint = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 6929 | m_scale = 1.0; | |||
| 6930 | m_rotation = 0.0; | |||
| 6931 | m_widthFactor = 1.0; | |||
| 6932 | m_oblique = 0.0; | |||
| 6933 | m_thickness = 0.0; | |||
| 6934 | m_shapeIndex = 0; | |||
| 6935 | m_extrusion = DRW_Coord{0.0, 0.0, 1.0}; | |||
| 6936 | m_shapeFileHandle = 0; | |||
| 6937 | m_objectSize = 0; | |||
| 6938 | m_bodyBitSize = 0; | |||
| 6939 | m_rawBytes.clear(); | |||
| 6940 | } | |||
| 6941 | ||||
| 6942 | bool DRW_Shape::parseDwg(DRW::Version v, dwgBuffer *buf, std::uint32_t bs){ | |||
| 6943 | resetDwgState(); | |||
| 6944 | dwgBuffer *sourceBuf = buf; | |||
| 6945 | auto fail = [this, sourceBuf]() { | |||
| 6946 | if (sourceBuf != nullptr) | |||
| 6947 | sourceBuf->invalidate(); | |||
| 6948 | resetDwgState(); | |||
| 6949 | return false; | |||
| 6950 | }; | |||
| 6951 | if (sourceBuf == nullptr) | |||
| 6952 | return fail(); | |||
| 6953 | ||||
| 6954 | m_bodyBitSize = bs; | |||
| 6955 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 6956 | if (!DRW_Entity::parseDwgCommon(v, &bodyProbe, bs)) | |||
| 6957 | return fail(); | |||
| 6958 | DRW_DBG("\n***************************** parsing SHAPE *****************************\n")DRW_dbg::dbg("\n***************************** parsing SHAPE *****************************\n" ); | |||
| 6959 | ||||
| 6960 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 6961 | DRW_Coord insertionPoint; | |||
| 6962 | DRW_Coord extrusion; | |||
| 6963 | double scale = 0.0; | |||
| 6964 | double rotation = 0.0; | |||
| 6965 | double widthFactor = 0.0; | |||
| 6966 | double oblique = 0.0; | |||
| 6967 | double thickness = 0.0; | |||
| 6968 | std::uint16_t shapeIndex = 0; | |||
| 6969 | if (!readBounded3BitDouble(bodyProbe, bodyEndBit, insertionPoint) | |||
| 6970 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, scale) | |||
| 6971 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, rotation) | |||
| 6972 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, widthFactor) | |||
| 6973 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, oblique) | |||
| 6974 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, thickness) | |||
| 6975 | || !readBoundedBitShort(bodyProbe, bodyEndBit, shapeIndex) | |||
| 6976 | || !readBounded3BitDouble(bodyProbe, bodyEndBit, extrusion)) | |||
| 6977 | return fail(); | |||
| 6978 | const auto finite = [](const DRW_Coord& point) { | |||
| 6979 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 6980 | && std::isfinite(point.z); | |||
| 6981 | }; | |||
| 6982 | if (!bodyProbe.isGood() || !finite(insertionPoint) || !finite(extrusion) | |||
| 6983 | || !std::isfinite(scale) || !std::isfinite(rotation) | |||
| 6984 | || !std::isfinite(widthFactor) || !std::isfinite(oblique) | |||
| 6985 | || !std::isfinite(thickness)) | |||
| 6986 | return fail(); | |||
| 6987 | ||||
| 6988 | std::uint64_t handleEndBit = 0; | |||
| 6989 | if (!dwgHandleStreamEndBit(*sourceBuf, v, objSize, bs, handleEndBit)) | |||
| 6990 | return fail(); | |||
| 6991 | dwgBuffer handleProbe = bodyProbe.forkIndependent(); | |||
| 6992 | if (!DRW_Entity::parseDwgEntHandle(v, &handleProbe, true, handleEndBit) | |||
| 6993 | || !handleProbe.isGood()) | |||
| 6994 | return fail(); | |||
| 6995 | ||||
| 6996 | // DwgObjectFrame removes the CRC trailer before exposing the body. The | |||
| 6997 | // SHAPEFILE hard pointer is therefore mandatory and must be parsed even | |||
| 6998 | // when only its exact handle bytes remain. | |||
| 6999 | dwgHandle shapeFileH; | |||
| 7000 | if (!readBoundedDwgHandle(handleProbe, handleEndBit, 0, false, | |||
| 7001 | shapeFileH) | |||
| 7002 | || shapeFileH.ref == 0) | |||
| 7003 | return fail(); | |||
| 7004 | ||||
| 7005 | m_insertionPoint = insertionPoint; | |||
| 7006 | m_scale = scale; | |||
| 7007 | m_rotation = rotation; | |||
| 7008 | m_widthFactor = widthFactor; | |||
| 7009 | m_oblique = oblique; | |||
| 7010 | m_thickness = thickness; | |||
| 7011 | m_shapeIndex = shapeIndex; | |||
| 7012 | m_extrusion = extrusion; | |||
| 7013 | m_shapeFileHandle = shapeFileH.ref; | |||
| 7014 | DRW_DBG(" SHAPEFILE Handle: ")DRW_dbg::dbg(" SHAPEFILE Handle: "); | |||
| 7015 | DRW_DBGHL(shapeFileH.code, shapeFileH.size, shapeFileH.ref)DRW_dbg::dbgHL(shapeFileH.code, shapeFileH.size, shapeFileH.ref ); | |||
| 7016 | DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 7017 | *sourceBuf = handleProbe; | |||
| 7018 | return true; | |||
| 7019 | } | |||
| 7020 | ||||
| 7021 | // Phase 6.1: SHAPE encoder (fixed oType 33). Exact inverse of parseDwg above. | |||
| 7022 | // Without this override a SHAPE would encode as a LINE (default DRW_Entity). | |||
| 7023 | bool DRW_Shape::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, | |||
| 7024 | dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 7025 | (void)bs; (void)strBuf; | |||
| 7026 | const auto finite = [](const DRW_Coord& point) { | |||
| 7027 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 7028 | && std::isfinite(point.z); | |||
| 7029 | }; | |||
| 7030 | if (!finite(m_insertionPoint) || !finite(m_extrusion) | |||
| 7031 | || !std::isfinite(m_scale) || !std::isfinite(m_rotation) | |||
| 7032 | || !std::isfinite(m_widthFactor) || !std::isfinite(m_oblique) | |||
| 7033 | || !std::isfinite(m_thickness) || m_shapeFileHandle == 0) { | |||
| 7034 | return false; | |||
| 7035 | } | |||
| 7036 | oType = 33; // SHAPE class id — see dwgreader.cpp case 33 | |||
| 7037 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 7038 | ||||
| 7039 | buf->put3BitDouble(m_insertionPoint); | |||
| 7040 | buf->putBitDouble(m_scale); | |||
| 7041 | buf->putBitDouble(m_rotation); | |||
| 7042 | buf->putBitDouble(m_widthFactor); | |||
| 7043 | buf->putBitDouble(m_oblique); | |||
| 7044 | buf->putBitDouble(m_thickness); | |||
| 7045 | buf->putBitShort(m_shapeIndex); | |||
| 7046 | buf->put3BitDouble(m_extrusion); | |||
| 7047 | ||||
| 7048 | if (!encodeDwgEntHandle(version, buf, handleBuf)) return false; | |||
| 7049 | ||||
| 7050 | // Trailing SHAPEFILE style hard pointer (code 5), byte-count-sized. | |||
| 7051 | dwgHandle sH; | |||
| 7052 | sH.code = 5; | |||
| 7053 | sH.ref = m_shapeFileHandle; | |||
| 7054 | sH.size = 0; | |||
| 7055 | if (m_shapeFileHandle != 0) { | |||
| 7056 | std::uint32_t t = m_shapeFileHandle; | |||
| 7057 | while (t != 0) { t >>= 8; ++sH.size; } | |||
| 7058 | } else { | |||
| 7059 | sH.code = 0; // null handle | |||
| 7060 | } | |||
| 7061 | (handleBuf ? handleBuf : buf)->putHandle(sH); | |||
| 7062 | return true; | |||
| 7063 | } | |||
| 7064 | ||||
| 7065 | bool DRW_Ole2Frame::parseCode(int code, const std::unique_ptr<dxfReader>& reader) { | |||
| 7066 | const auto readUnsigned = [&](std::uint32_t maximum, | |||
| 7067 | std::uint32_t& target) { | |||
| 7068 | const int value = reader->getInt32(); | |||
| 7069 | if (value < 0 || static_cast<std::uint32_t>(value) > maximum) | |||
| 7070 | return false; | |||
| 7071 | target = static_cast<std::uint32_t>(value); | |||
| 7072 | return true; | |||
| 7073 | }; | |||
| 7074 | ||||
| 7075 | switch (code) { | |||
| 7076 | case 3: | |||
| 7077 | m_oleClient = reader->getUtf8String(); | |||
| 7078 | break; | |||
| 7079 | case 10: | |||
| 7080 | m_pt1.x = reader->getDouble(); | |||
| 7081 | break; | |||
| 7082 | case 20: | |||
| 7083 | m_pt1.y = reader->getDouble(); | |||
| 7084 | break; | |||
| 7085 | case 30: | |||
| 7086 | m_pt1.z = reader->getDouble(); | |||
| 7087 | break; | |||
| 7088 | case 11: | |||
| 7089 | m_pt2.x = reader->getDouble(); | |||
| 7090 | break; | |||
| 7091 | case 21: | |||
| 7092 | m_pt2.y = reader->getDouble(); | |||
| 7093 | break; | |||
| 7094 | case 31: | |||
| 7095 | m_pt2.z = reader->getDouble(); | |||
| 7096 | break; | |||
| 7097 | case 70: { | |||
| 7098 | std::uint32_t value = 0; | |||
| 7099 | if (!readUnsigned(std::numeric_limits<std::uint16_t>::max(), value)) | |||
| 7100 | return false; | |||
| 7101 | m_oleVersion = static_cast<std::uint16_t>(value); | |||
| 7102 | break; | |||
| 7103 | } | |||
| 7104 | case 71: { | |||
| 7105 | std::uint32_t value = 0; | |||
| 7106 | if (!readUnsigned(std::numeric_limits<std::uint16_t>::max(), value)) | |||
| 7107 | return false; | |||
| 7108 | m_flags = static_cast<std::uint16_t>(value); | |||
| 7109 | break; | |||
| 7110 | } | |||
| 7111 | case 72: { | |||
| 7112 | std::uint32_t value = 0; | |||
| 7113 | if (!readUnsigned(std::numeric_limits<std::uint16_t>::max(), value)) | |||
| 7114 | return false; | |||
| 7115 | m_mode = static_cast<std::uint16_t>(value); | |||
| 7116 | break; | |||
| 7117 | } | |||
| 7118 | case 73: { | |||
| 7119 | std::uint32_t value = 0; | |||
| 7120 | if (!readUnsigned(std::numeric_limits<std::uint8_t>::max(), value)) | |||
| 7121 | return false; | |||
| 7122 | m_lockAspect = static_cast<std::uint8_t>(value); | |||
| 7123 | break; | |||
| 7124 | } | |||
| 7125 | case 90: { | |||
| 7126 | std::uint32_t value = 0; | |||
| 7127 | if (!readUnsigned(kMaxOlePayloadBytes, value)) | |||
| 7128 | return false; | |||
| 7129 | m_declaredPayloadLength = value; | |||
| 7130 | m_dxfPayloadLengthSpecified = true; | |||
| 7131 | m_payloadPresent = value != 0; | |||
| 7132 | break; | |||
| 7133 | } | |||
| 7134 | case 310: { | |||
| 7135 | std::vector<std::uint8_t> bytes; | |||
| 7136 | if (!decodeHexBytes(reader->getString(), bytes)) | |||
| 7137 | return false; | |||
| 7138 | if (!appendBytesChecked(m_payloadBytes, bytes, | |||
| 7139 | kMaxOlePayloadBytes)) { | |||
| 7140 | m_payloadTooLarge = m_payloadBytes.size() > kMaxOlePayloadBytes | |||
| 7141 | || bytes.size() > kMaxOlePayloadBytes - | |||
| 7142 | std::min(m_payloadBytes.size(), | |||
| 7143 | static_cast<std::size_t>( | |||
| 7144 | kMaxOlePayloadBytes)); | |||
| 7145 | return false; | |||
| 7146 | } | |||
| 7147 | m_payloadPresent = true; | |||
| 7148 | break; | |||
| 7149 | } | |||
| 7150 | default: | |||
| 7151 | return DRW_Entity::parseCode(code, reader); | |||
| 7152 | } | |||
| 7153 | return true; | |||
| 7154 | } | |||
| 7155 | ||||
| 7156 | void DRW_Ole2Frame::resetDwgState() { | |||
| 7157 | DRW_Entity::reset(); | |||
| 7158 | m_flags = 0; | |||
| 7159 | m_mode = 0; | |||
| 7160 | m_declaredPayloadLength = 0; | |||
| 7161 | m_payloadByteCount = 0; | |||
| 7162 | m_payloadStartBit = 0; | |||
| 7163 | m_payloadPresent = false; | |||
| 7164 | m_payloadTruncated = false; | |||
| 7165 | m_payloadTooLarge = false; | |||
| 7166 | m_hasR2000TrailingByte = false; | |||
| 7167 | m_r2000TrailingByte = 0; | |||
| 7168 | m_objectSize = 0; | |||
| 7169 | m_bodyBitSize = 0; | |||
| 7170 | m_payloadBytes.clear(); | |||
| 7171 | m_pt1 = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 7172 | m_pt2 = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 7173 | m_lockAspect = 3; | |||
| 7174 | m_dxfPayloadLengthSpecified = false; | |||
| 7175 | m_oleVersion = 2; | |||
| 7176 | m_oleClient = "OLE"; | |||
| 7177 | m_rawBytes.clear(); | |||
| 7178 | } | |||
| 7179 | ||||
| 7180 | bool DRW_Ole2Frame::parseDwg(DRW::Version v, dwgBuffer *buf, std::uint32_t bs){ | |||
| 7181 | resetDwgState(); | |||
| 7182 | dwgBuffer *sourceBuf = buf; | |||
| 7183 | auto fail = [this, sourceBuf]() { | |||
| 7184 | if (sourceBuf != nullptr) | |||
| 7185 | sourceBuf->invalidate(); | |||
| 7186 | resetDwgState(); | |||
| 7187 | return false; | |||
| 7188 | }; | |||
| 7189 | if (sourceBuf == nullptr) | |||
| 7190 | return fail(); | |||
| 7191 | ||||
| 7192 | m_bodyBitSize = bs; | |||
| 7193 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 7194 | if (!DRW_Entity::parseDwgCommon(v, &bodyProbe, bs)) | |||
| 7195 | return fail(); | |||
| 7196 | DRW_DBG("\n***************************** parsing OLE2FRAME ************************\n")DRW_dbg::dbg("\n***************************** parsing OLE2FRAME ************************\n" ); | |||
| 7197 | ||||
| 7198 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 7199 | std::uint16_t parsedFlags = 0; | |||
| 7200 | std::uint16_t parsedMode = 0; | |||
| 7201 | std::int32_t declaredLength = 0; | |||
| 7202 | if (!readBoundedBitShort(bodyProbe, bodyEndBit, parsedFlags) | |||
| 7203 | || (v > DRW::AC1014 | |||
| 7204 | && !readBoundedBitShort(bodyProbe, bodyEndBit, parsedMode)) | |||
| 7205 | || !readBoundedBitLong(bodyProbe, bodyEndBit, declaredLength) | |||
| 7206 | || declaredLength < 0 | |||
| 7207 | || static_cast<std::uint32_t>(declaredLength) > kMaxOlePayloadBytes) | |||
| 7208 | return fail(); | |||
| 7209 | ||||
| 7210 | const std::uint64_t payloadStartBit = currentDwgBit(&bodyProbe); | |||
| 7211 | const auto bodyRemainingBits = [&](const dwgBuffer& cursor, | |||
| 7212 | std::uint64_t& remaining) { | |||
| 7213 | const std::uint64_t currentBit = currentDwgBit(&cursor); | |||
| 7214 | if (v > DRW::AC1014 && objSize != 0) { | |||
| 7215 | if (currentBit > bodyEndBit) | |||
| 7216 | return false; | |||
| 7217 | remaining = bodyEndBit - currentBit; | |||
| 7218 | return true; | |||
| 7219 | } | |||
| 7220 | const int bytes = cursor.numRemainingBytes(); | |||
| 7221 | if (bytes < 0) | |||
| 7222 | return false; | |||
| 7223 | remaining = static_cast<std::uint64_t>(bytes) * 8u; | |||
| 7224 | return true; | |||
| 7225 | }; | |||
| 7226 | ||||
| 7227 | std::uint64_t remainingBits = 0; | |||
| 7228 | if (!bodyRemainingBits(bodyProbe, remainingBits)) | |||
| 7229 | return fail(); | |||
| 7230 | const std::uint64_t trailingBits = v > DRW::AC1014 ? 8u : 0u; | |||
| 7231 | if (remainingBits < trailingBits | |||
| 7232 | || static_cast<std::uint64_t>(declaredLength) | |||
| 7233 | > (remainingBits - trailingBits) / 8u) | |||
| 7234 | return fail(); | |||
| 7235 | ||||
| 7236 | std::vector<std::uint8_t> payload; | |||
| 7237 | if (!DRW::resize(payload, declaredLength)) | |||
| 7238 | return fail(); | |||
| 7239 | if (!readBoundedBytes(bodyProbe, bodyEndBit, payload.data(), | |||
| 7240 | payload.size())) | |||
| 7241 | return fail(); | |||
| 7242 | ||||
| 7243 | std::uint8_t trailingByte = 0; | |||
| 7244 | bool hasTrailingByte = false; | |||
| 7245 | if (v > DRW::AC1014) { | |||
| 7246 | if (!bodyRemainingBits(bodyProbe, remainingBits) | |||
| 7247 | || (remainingBits != 0 && remainingBits < 8)) | |||
| 7248 | return fail(); | |||
| 7249 | if (remainingBits >= 8) { | |||
| 7250 | if (!readBoundedRawChar8(bodyProbe, bodyEndBit, trailingByte)) | |||
| 7251 | return fail(); | |||
| 7252 | hasTrailingByte = true; | |||
| 7253 | } | |||
| 7254 | } | |||
| 7255 | ||||
| 7256 | // Decode the frame rectangle (DXF 10/11) from the OLE header. AutoCAD/ODA do | |||
| 7257 | // NOT store pt1/pt2 as DWG fields; they live in the first ~0x80 bytes of the | |||
| 7258 | // payload as raw little-endian doubles. Guarded so a non-finite/short | |||
| 7259 | // payload simply leaves both points at the origin. | |||
| 7260 | DRW_Coord point1; | |||
| 7261 | DRW_Coord point2; | |||
| 7262 | if (payload.size() >= 0x4a && payload[0] == 0x80) { | |||
| 7263 | auto rd = [&](std::size_t off) { | |||
| 7264 | double value = 0.0; | |||
| 7265 | std::memcpy(&value, payload.data() + off, sizeof(double)); | |||
| 7266 | return value; | |||
| 7267 | }; | |||
| 7268 | const DRW_Coord upperLeft(rd(0x02), rd(0x0a), rd(0x12)); | |||
| 7269 | const DRW_Coord lowerRight(rd(0x32), rd(0x3a), rd(0x42)); | |||
| 7270 | if (std::isfinite(upperLeft.x) && std::isfinite(upperLeft.y) | |||
| 7271 | && std::isfinite(upperLeft.z) && std::isfinite(lowerRight.x) | |||
| 7272 | && std::isfinite(lowerRight.y) && std::isfinite(lowerRight.z)) { | |||
| 7273 | point1 = upperLeft; | |||
| 7274 | point2 = lowerRight; | |||
| 7275 | } | |||
| 7276 | } | |||
| 7277 | ||||
| 7278 | std::uint64_t handleEndBit = 0; | |||
| 7279 | if (!dwgHandleStreamEndBit(*sourceBuf, v, objSize, bs, handleEndBit)) | |||
| 7280 | return fail(); | |||
| 7281 | dwgBuffer handleProbe = bodyProbe.forkIndependent(); | |||
| 7282 | if (!DRW_Entity::parseDwgEntHandle(v, &handleProbe, true, handleEndBit) | |||
| 7283 | || !handleProbe.isGood()) | |||
| 7284 | return fail(); | |||
| 7285 | ||||
| 7286 | m_flags = parsedFlags; | |||
| 7287 | m_mode = parsedMode; | |||
| 7288 | m_declaredPayloadLength = static_cast<std::uint32_t>(declaredLength); | |||
| 7289 | m_payloadStartBit = payloadStartBit; | |||
| 7290 | m_payloadPresent = declaredLength > 0; | |||
| 7291 | m_payloadByteCount = static_cast<std::uint32_t>(declaredLength); | |||
| 7292 | m_payloadBytes = std::move(payload); | |||
| 7293 | m_hasR2000TrailingByte = hasTrailingByte; | |||
| 7294 | m_r2000TrailingByte = trailingByte; | |||
| 7295 | m_pt1 = point1; | |||
| 7296 | m_pt2 = point2; | |||
| 7297 | *sourceBuf = handleProbe; | |||
| 7298 | return true; | |||
| 7299 | } | |||
| 7300 | ||||
| 7301 | // Phase 6.2: OLE2FRAME encoder (fixed oType 74). Inverse of parseDwg, emitting | |||
| 7302 | // the captured opaque payload byte-for-byte. Without this override an OLE2FRAME | |||
| 7303 | // would encode as a LINE. | |||
| 7304 | bool DRW_Ole2Frame::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, | |||
| 7305 | dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 7306 | (void)bs; (void)strBuf; | |||
| 7307 | if (m_payloadTooLarge || m_payloadTruncated | |||
| 7308 | || m_payloadBytes.size() > kMaxOlePayloadBytes | |||
| 7309 | || (m_payloadPresent | |||
| 7310 | && m_declaredPayloadLength != m_payloadBytes.size())) { | |||
| 7311 | return false; | |||
| 7312 | } | |||
| 7313 | oType = 74; // OLE2FRAME class id — see dwgreader.cpp case 74 | |||
| 7314 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 7315 | ||||
| 7316 | buf->putBitShort(m_flags); | |||
| 7317 | if (version > DRW::AC1014) | |||
| 7318 | buf->putBitShort(m_mode); | |||
| 7319 | // Emit the actual captured length so the reader's data_size matches the | |||
| 7320 | // bytes that follow (avoids a declared-vs-actual mismatch on re-read). | |||
| 7321 | const std::uint32_t payloadLen = static_cast<std::uint32_t>(m_payloadBytes.size()); | |||
| 7322 | buf->putBitLong(static_cast<std::int32_t>(payloadLen)); | |||
| 7323 | if (payloadLen > 0) | |||
| 7324 | buf->putBytes(m_payloadBytes.data(), m_payloadBytes.size()); | |||
| 7325 | // R2000+ Unknown RC (ODA §20.4.88): emitted UNCONDITIONALLY for version > | |||
| 7326 | // AC1014. parseDwg reads it whenever bytes remain before the handle stream | |||
| 7327 | // (which is always — handle data always follows), so gating the write on | |||
| 7328 | // m_hasR2000TrailingByte desynced a directly-constructed OLE2FRAME (the | |||
| 7329 | // default false): the parser consumed the first handle byte as this RC and | |||
| 7330 | // shifted the entity handle stream. Default m_r2000TrailingByte is 0, so | |||
| 7331 | // constructed entities align and round-tripped ones keep the captured byte. | |||
| 7332 | if (version > DRW::AC1014) | |||
| 7333 | buf->putRawChar8(m_r2000TrailingByte); | |||
| 7334 | ||||
| 7335 | return encodeDwgEntHandle(version, buf, handleBuf); | |||
| 7336 | } | |||
| 7337 | ||||
| 7338 | bool DRW_OleFrame::parseCode(int code, const std::unique_ptr<dxfReader>& reader) { | |||
| 7339 | switch (code) { | |||
| 7340 | case 70: { | |||
| 7341 | const int value = reader->getInt32(); | |||
| 7342 | if (value < 0 || value > std::numeric_limits<std::uint16_t>::max()) | |||
| 7343 | return false; | |||
| 7344 | m_flags = static_cast<std::uint16_t>(value); | |||
| 7345 | break; | |||
| 7346 | } | |||
| 7347 | case 90: { | |||
| 7348 | const int value = reader->getInt32(); | |||
| 7349 | if (value < 0 | |||
| 7350 | || static_cast<std::uint32_t>(value) > kMaxOlePayloadBytes) { | |||
| 7351 | m_payloadTooLarge = value >= 0; | |||
| 7352 | return false; | |||
| 7353 | } | |||
| 7354 | m_declaredPayloadLength = static_cast<std::uint32_t>(value); | |||
| 7355 | m_dxfPayloadLengthSpecified = true; | |||
| 7356 | m_payloadPresent = value != 0; | |||
| 7357 | break; | |||
| 7358 | } | |||
| 7359 | case 310: { | |||
| 7360 | std::vector<std::uint8_t> bytes; | |||
| 7361 | if (!decodeHexBytes(reader->getString(), bytes)) | |||
| 7362 | return false; | |||
| 7363 | if (!appendBytesChecked(m_payloadBytes, bytes, | |||
| 7364 | kMaxOlePayloadBytes)) { | |||
| 7365 | m_payloadTooLarge = m_payloadBytes.size() > kMaxOlePayloadBytes | |||
| 7366 | || bytes.size() > kMaxOlePayloadBytes - | |||
| 7367 | std::min(m_payloadBytes.size(), | |||
| 7368 | static_cast<std::size_t>( | |||
| 7369 | kMaxOlePayloadBytes)); | |||
| 7370 | return false; | |||
| 7371 | } | |||
| 7372 | m_payloadPresent = true; | |||
| 7373 | break; | |||
| 7374 | } | |||
| 7375 | default: | |||
| 7376 | return DRW_Entity::parseCode(code, reader); | |||
| 7377 | } | |||
| 7378 | return true; | |||
| 7379 | } | |||
| 7380 | ||||
| 7381 | void DRW_OleFrame::resetDwgState() { | |||
| 7382 | DRW_Entity::reset(); | |||
| 7383 | m_flags = 0; | |||
| 7384 | m_mode = 0; | |||
| 7385 | m_declaredPayloadLength = 0; | |||
| 7386 | m_payloadByteCount = 0; | |||
| 7387 | m_payloadPresent = false; | |||
| 7388 | m_payloadTruncated = false; | |||
| 7389 | m_payloadTooLarge = false; | |||
| 7390 | m_objectSize = 0; | |||
| 7391 | m_bodyBitSize = 0; | |||
| 7392 | m_payloadBytes.clear(); | |||
| 7393 | m_dxfPayloadLengthSpecified = false; | |||
| 7394 | m_rawBytes.clear(); | |||
| 7395 | } | |||
| 7396 | ||||
| 7397 | bool DRW_OleFrame::parseDwg(DRW::Version version, dwgBuffer *buf, | |||
| 7398 | std::uint32_t bs) { | |||
| 7399 | resetDwgState(); | |||
| 7400 | dwgBuffer *sourceBuf = buf; | |||
| 7401 | auto fail = [this, sourceBuf]() { | |||
| 7402 | if (sourceBuf != nullptr) | |||
| 7403 | sourceBuf->invalidate(); | |||
| 7404 | resetDwgState(); | |||
| 7405 | return false; | |||
| 7406 | }; | |||
| 7407 | if (sourceBuf == nullptr) | |||
| 7408 | return fail(); | |||
| 7409 | ||||
| 7410 | m_bodyBitSize = bs; | |||
| 7411 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 7412 | if (!DRW_Entity::parseDwgCommon(version, &bodyProbe, bs)) | |||
| 7413 | return fail(); | |||
| 7414 | ||||
| 7415 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 7416 | std::uint16_t parsedFlags = 0; | |||
| 7417 | std::uint16_t parsedMode = 0; | |||
| 7418 | std::int32_t declaredLength = 0; | |||
| 7419 | if (!readBoundedBitShort(bodyProbe, bodyEndBit, parsedFlags) | |||
| 7420 | || (version > DRW::AC1014 | |||
| 7421 | && !readBoundedBitShort(bodyProbe, bodyEndBit, parsedMode)) | |||
| 7422 | || !readBoundedBitLong(bodyProbe, bodyEndBit, declaredLength) | |||
| 7423 | || declaredLength < 0 | |||
| 7424 | || static_cast<std::uint32_t>(declaredLength) > kMaxOlePayloadBytes) | |||
| 7425 | return fail(); | |||
| 7426 | ||||
| 7427 | std::uint64_t bodyRemainingBits = 0; | |||
| 7428 | const std::uint64_t currentBit = currentDwgBit(&bodyProbe); | |||
| 7429 | if (version > DRW::AC1014 && objSize != 0) { | |||
| 7430 | if (currentBit > bodyEndBit) | |||
| 7431 | return fail(); | |||
| 7432 | bodyRemainingBits = bodyEndBit - currentBit; | |||
| 7433 | } else { | |||
| 7434 | const int remainingBytes = bodyProbe.numRemainingBytes(); | |||
| 7435 | if (remainingBytes < 0) | |||
| 7436 | return fail(); | |||
| 7437 | bodyRemainingBits = static_cast<std::uint64_t>(remainingBytes) * 8u; | |||
| 7438 | } | |||
| 7439 | ||||
| 7440 | if (static_cast<std::uint64_t>(declaredLength) > bodyRemainingBits / 8u) | |||
| 7441 | return fail(); | |||
| 7442 | std::vector<std::uint8_t> payload; | |||
| 7443 | if (!DRW::resize(payload, declaredLength)) | |||
| 7444 | return fail(); | |||
| 7445 | if (!readBoundedBytes(bodyProbe, bodyEndBit, payload.data(), | |||
| 7446 | payload.size())) | |||
| 7447 | return fail(); | |||
| 7448 | ||||
| 7449 | std::uint64_t handleEndBit = 0; | |||
| 7450 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, | |||
| 7451 | handleEndBit)) | |||
| 7452 | return fail(); | |||
| 7453 | dwgBuffer handleProbe = bodyProbe.forkIndependent(); | |||
| 7454 | if (!DRW_Entity::parseDwgEntHandle(version, &handleProbe, true, | |||
| 7455 | handleEndBit) | |||
| 7456 | || !handleProbe.isGood()) | |||
| 7457 | return fail(); | |||
| 7458 | ||||
| 7459 | m_flags = parsedFlags; | |||
| 7460 | m_mode = parsedMode; | |||
| 7461 | m_declaredPayloadLength = static_cast<std::uint32_t>(declaredLength); | |||
| 7462 | m_payloadPresent = declaredLength != 0; | |||
| 7463 | m_payloadByteCount = static_cast<std::uint32_t>(declaredLength); | |||
| 7464 | m_payloadBytes = std::move(payload); | |||
| 7465 | *sourceBuf = handleProbe; | |||
| 7466 | return true; | |||
| 7467 | ||||
| 7468 | } | |||
| 7469 | ||||
| 7470 | bool DRW_OleFrame::encodeDwg(DRW::Version version, dwgBufferW *buf, | |||
| 7471 | std::uint32_t bs, dwgBufferW *strBuf, | |||
| 7472 | dwgBufferW *handleBuf) { | |||
| 7473 | (void)bs; | |||
| 7474 | (void)strBuf; | |||
| 7475 | if (buf == nullptr || m_payloadTooLarge || m_payloadTruncated | |||
| 7476 | || m_payloadBytes.size() > kMaxOlePayloadBytes | |||
| 7477 | || (m_payloadPresent | |||
| 7478 | && m_declaredPayloadLength != m_payloadBytes.size())) { | |||
| 7479 | return false; | |||
| 7480 | } | |||
| 7481 | ||||
| 7482 | oType = 43; | |||
| 7483 | if (!encodeDwgCommon(version, buf)) | |||
| 7484 | return false; | |||
| 7485 | buf->putBitShort(m_flags); | |||
| 7486 | if (version > DRW::AC1014) | |||
| 7487 | buf->putBitShort(m_mode); | |||
| 7488 | const std::uint32_t payloadLength = | |||
| 7489 | static_cast<std::uint32_t>(m_payloadBytes.size()); | |||
| 7490 | buf->putBitLong(static_cast<std::int32_t>(payloadLength)); | |||
| 7491 | if (payloadLength != 0) | |||
| 7492 | buf->putBytes(m_payloadBytes.data(), m_payloadBytes.size()); | |||
| 7493 | return encodeDwgEntHandle(version, buf, handleBuf); | |||
| 7494 | } | |||
| 7495 | ||||
| 7496 | void DRW_Light::resetDwgState() { | |||
| 7497 | DRW_Entity::reset(); | |||
| 7498 | m_classVersion = 0; | |||
| 7499 | m_name.clear(); | |||
| 7500 | m_type = 0; | |||
| 7501 | m_status = false; | |||
| 7502 | m_color = 0; | |||
| 7503 | m_plotGlyph = false; | |||
| 7504 | m_intensity = 0.0; | |||
| 7505 | m_position = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 7506 | m_target = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 7507 | m_attenuationType = 0; | |||
| 7508 | m_useAttenuationLimits = false; | |||
| 7509 | m_attenuationStartLimit = 0.0; | |||
| 7510 | m_attenuationEndLimit = 0.0; | |||
| 7511 | m_hotspotAngle = 0.0; | |||
| 7512 | m_falloffAngle = 0.0; | |||
| 7513 | m_castShadows = false; | |||
| 7514 | m_shadowType = 0; | |||
| 7515 | m_shadowMapSize = 0; | |||
| 7516 | m_shadowMapSoftness = 0; | |||
| 7517 | m_hasPhotometricData = false; | |||
| 7518 | m_hasWebFile = false; | |||
| 7519 | m_webFile.clear(); | |||
| 7520 | m_physicalIntensityMethod = 0; | |||
| 7521 | m_physicalIntensity = 0.0; | |||
| 7522 | m_illuminanceDistance = 0.0; | |||
| 7523 | m_lampColorType = 0; | |||
| 7524 | m_lampColorTemperature = 0.0; | |||
| 7525 | m_lampColorPreset = 0; | |||
| 7526 | m_webRotation = {1.0, 0.0, 0.0}; | |||
| 7527 | m_extendedLightShape = 0; | |||
| 7528 | m_extendedLightLength = 0.0; | |||
| 7529 | m_extendedLightWidth = 0.0; | |||
| 7530 | m_extendedLightRadius = 0.0; | |||
| 7531 | } | |||
| 7532 | ||||
| 7533 | bool DRW_Light::parseDwg(DRW::Version v, dwgBuffer *buf, std::uint32_t bs){ | |||
| 7534 | resetDwgState(); | |||
| 7535 | dwgBuffer *sourceBuf = buf; | |||
| 7536 | auto fail = [this, sourceBuf]() { | |||
| 7537 | if (sourceBuf != nullptr) | |||
| 7538 | sourceBuf->invalidate(); | |||
| 7539 | resetDwgState(); | |||
| 7540 | return false; | |||
| 7541 | }; | |||
| 7542 | if (sourceBuf == nullptr) | |||
| 7543 | return fail(); | |||
| 7544 | ||||
| 7545 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 7546 | dwgBuffer stringProbe = sourceBuf->forkIndependent(); | |||
| 7547 | dwgBuffer *stringStream = v > DRW::AC1018 ? &stringProbe : nullptr; | |||
| 7548 | if (!DRW_Entity::parseDwg(v, &bodyProbe, stringStream, bs) | |||
| 7549 | || !bodyProbe.isGood() || !stringProbe.isGood()) | |||
| 7550 | return fail(); | |||
| 7551 | DRW_DBG("\n***************************** parsing LIGHT *****************************\n")DRW_dbg::dbg("\n***************************** parsing LIGHT *****************************\n" ); | |||
| 7552 | ||||
| 7553 | const std::uint64_t bodyDataEndBit = dwgDataEndBit; | |||
| 7554 | std::uint64_t stringEndBit = bodyDataEndBit; | |||
| 7555 | if (stringStream != nullptr && v > DRW::AC1021) { | |||
| 7556 | std::uint64_t ignoredBodyEndBit = 0; | |||
| 7557 | if (!entityBodyDataEndBit(*stringStream, v, objSize, | |||
| 7558 | ignoredBodyEndBit, &stringEndBit)) | |||
| 7559 | return fail(); | |||
| 7560 | } | |||
| 7561 | ||||
| 7562 | std::int32_t parsedClassVersion = 0; | |||
| 7563 | UTF8STRINGstd::string parsedName; | |||
| 7564 | std::int32_t parsedType = 0; | |||
| 7565 | bool parsedStatus = false; | |||
| 7566 | std::uint32_t parsedColor = 0; | |||
| 7567 | bool parsedPlotGlyph = false; | |||
| 7568 | double parsedIntensity = 0.0; | |||
| 7569 | DRW_Coord parsedPosition; | |||
| 7570 | DRW_Coord parsedTarget; | |||
| 7571 | std::int32_t parsedAttenuationType = 0; | |||
| 7572 | bool parsedUseAttenuationLimits = false; | |||
| 7573 | double parsedAttenuationStartLimit = 0.0; | |||
| 7574 | double parsedAttenuationEndLimit = 0.0; | |||
| 7575 | double parsedHotspotAngle = 0.0; | |||
| 7576 | double parsedFalloffAngle = 0.0; | |||
| 7577 | bool parsedCastShadows = false; | |||
| 7578 | std::int32_t parsedShadowType = 0; | |||
| 7579 | std::uint16_t parsedShadowMapSize = 0; | |||
| 7580 | std::uint8_t parsedShadowMapSoftness = 0; | |||
| 7581 | if (!readBoundedBitLong(bodyProbe, bodyDataEndBit, parsedClassVersion) | |||
| 7582 | || (stringStream != nullptr | |||
| 7583 | ? !readBoundedVariableText(stringProbe, stringEndBit, v, | |||
| 7584 | parsedName) | |||
| 7585 | : !readBoundedVariableText(bodyProbe, bodyDataEndBit, v, | |||
| 7586 | parsedName)) | |||
| 7587 | || !readBoundedBitLong(bodyProbe, bodyDataEndBit, parsedType) | |||
| 7588 | || !readBoundedBit(bodyProbe, bodyDataEndBit, parsedStatus) | |||
| 7589 | || !readBoundedCmColor(bodyProbe, stringStream, bodyDataEndBit, v, | |||
| 7590 | parsedColor, nullptr, nullptr, nullptr, | |||
| 7591 | nullptr, stringEndBit) | |||
| 7592 | || !readBoundedBit(bodyProbe, bodyDataEndBit, parsedPlotGlyph) | |||
| 7593 | || !readBoundedBitDouble(bodyProbe, bodyDataEndBit, parsedIntensity) | |||
| 7594 | || !readBoundedBitCoord(bodyProbe, bodyDataEndBit, parsedPosition) | |||
| 7595 | || !readBoundedBitCoord(bodyProbe, bodyDataEndBit, parsedTarget) | |||
| 7596 | || !readBoundedBitLong(bodyProbe, bodyDataEndBit, | |||
| 7597 | parsedAttenuationType) | |||
| 7598 | || !readBoundedBit(bodyProbe, bodyDataEndBit, | |||
| 7599 | parsedUseAttenuationLimits) | |||
| 7600 | || !readBoundedBitDouble(bodyProbe, bodyDataEndBit, | |||
| 7601 | parsedAttenuationStartLimit) | |||
| 7602 | || !readBoundedBitDouble(bodyProbe, bodyDataEndBit, | |||
| 7603 | parsedAttenuationEndLimit) | |||
| 7604 | || !readBoundedBitDouble(bodyProbe, bodyDataEndBit, | |||
| 7605 | parsedHotspotAngle) | |||
| 7606 | || !readBoundedBitDouble(bodyProbe, bodyDataEndBit, | |||
| 7607 | parsedFalloffAngle) | |||
| 7608 | || !readBoundedBit(bodyProbe, bodyDataEndBit, parsedCastShadows) | |||
| 7609 | || !readBoundedBitLong(bodyProbe, bodyDataEndBit, parsedShadowType) | |||
| 7610 | || !readBoundedBitShort(bodyProbe, bodyDataEndBit, | |||
| 7611 | parsedShadowMapSize) | |||
| 7612 | || !readBoundedRawChar8(bodyProbe, bodyDataEndBit, | |||
| 7613 | parsedShadowMapSoftness)) | |||
| 7614 | return fail(); | |||
| 7615 | ||||
| 7616 | bool hasPhotometricData = false; | |||
| 7617 | bool hasWebFile = false; | |||
| 7618 | UTF8STRINGstd::string webFile; | |||
| 7619 | std::uint16_t physicalIntensityMethod = 0; | |||
| 7620 | double physicalIntensity = 0.0; | |||
| 7621 | double illuminanceDistance = 0.0; | |||
| 7622 | std::uint16_t lampColorType = 0; | |||
| 7623 | double lampColorTemperature = 0.0; | |||
| 7624 | std::uint16_t lampColorPreset = 0; | |||
| 7625 | DRW_Coord webRotation{1.0, 0.0, 0.0}; | |||
| 7626 | std::uint16_t extendedLightShape = 0; | |||
| 7627 | double extendedLightLength = 0.0; | |||
| 7628 | double extendedLightWidth = 0.0; | |||
| 7629 | double extendedLightRadius = 0.0; | |||
| 7630 | if (v > DRW::AC1018 | |||
| 7631 | && proxyEntityHasBits(bodyProbe, bodyDataEndBit, 1)) { | |||
| 7632 | if (!readBoundedBit(bodyProbe, bodyDataEndBit, hasPhotometricData)) | |||
| 7633 | return fail(); | |||
| 7634 | if (hasPhotometricData) { | |||
| 7635 | if (!readBoundedBit(bodyProbe, bodyDataEndBit, hasWebFile) | |||
| 7636 | || !readBoundedVariableText(stringProbe, stringEndBit, v, | |||
| 7637 | webFile) | |||
| 7638 | || !readBoundedBitShort(bodyProbe, bodyDataEndBit, | |||
| 7639 | physicalIntensityMethod) | |||
| 7640 | || !readBoundedBitDouble(bodyProbe, bodyDataEndBit, | |||
| 7641 | physicalIntensity) | |||
| 7642 | || !readBoundedBitDouble(bodyProbe, bodyDataEndBit, | |||
| 7643 | illuminanceDistance) | |||
| 7644 | || !readBoundedBitShort(bodyProbe, bodyDataEndBit, | |||
| 7645 | lampColorType) | |||
| 7646 | || !readBoundedBitDouble(bodyProbe, bodyDataEndBit, | |||
| 7647 | lampColorTemperature) | |||
| 7648 | || !readBoundedBitShort(bodyProbe, bodyDataEndBit, | |||
| 7649 | lampColorPreset) | |||
| 7650 | || !readBoundedBitCoord(bodyProbe, bodyDataEndBit, | |||
| 7651 | webRotation) | |||
| 7652 | || !readBoundedBitShort(bodyProbe, bodyDataEndBit, | |||
| 7653 | extendedLightShape) | |||
| 7654 | || !readBoundedBitDouble(bodyProbe, bodyDataEndBit, | |||
| 7655 | extendedLightLength) | |||
| 7656 | || !readBoundedBitDouble(bodyProbe, bodyDataEndBit, | |||
| 7657 | extendedLightWidth) | |||
| 7658 | || !readBoundedBitDouble(bodyProbe, bodyDataEndBit, | |||
| 7659 | extendedLightRadius)) | |||
| 7660 | return fail(); | |||
| 7661 | } | |||
| 7662 | } | |||
| 7663 | ||||
| 7664 | const auto finite = [](const DRW_Coord& point) { | |||
| 7665 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 7666 | && std::isfinite(point.z); | |||
| 7667 | }; | |||
| 7668 | if (!bodyProbe.isGood() || !stringProbe.isGood() | |||
| 7669 | || currentDwgBit(&bodyProbe) > bodyDataEndBit | |||
| 7670 | || (stringStream != nullptr && currentDwgBit(&stringProbe) > stringEndBit) | |||
| 7671 | || parsedClassVersion < 0 || parsedType < 0 | |||
| 7672 | || parsedAttenuationType < 0 || parsedShadowType < 0 | |||
| 7673 | || !finite(parsedPosition) || !finite(parsedTarget) | |||
| 7674 | || !finite(webRotation) | |||
| 7675 | || !std::isfinite(parsedIntensity) | |||
| 7676 | || !std::isfinite(parsedAttenuationStartLimit) | |||
| 7677 | || !std::isfinite(parsedAttenuationEndLimit) | |||
| 7678 | || !std::isfinite(parsedHotspotAngle) | |||
| 7679 | || !std::isfinite(parsedFalloffAngle) | |||
| 7680 | || !std::isfinite(physicalIntensity) | |||
| 7681 | || !std::isfinite(illuminanceDistance) | |||
| 7682 | || !std::isfinite(lampColorTemperature) | |||
| 7683 | || !std::isfinite(extendedLightLength) | |||
| 7684 | || !std::isfinite(extendedLightWidth) | |||
| 7685 | || !std::isfinite(extendedLightRadius)) | |||
| 7686 | return fail(); | |||
| 7687 | ||||
| 7688 | std::uint64_t handleEndBit = 0; | |||
| 7689 | if (!dwgHandleStreamEndBit(*sourceBuf, v, objSize, bs, handleEndBit)) | |||
| 7690 | return fail(); | |||
| 7691 | dwgBuffer handleProbe = bodyProbe.forkIndependent(); | |||
| 7692 | if (!DRW_Entity::parseDwgEntHandle(v, &handleProbe, true, handleEndBit) | |||
| 7693 | || !handleProbe.isGood()) | |||
| 7694 | return fail(); | |||
| 7695 | ||||
| 7696 | m_classVersion = static_cast<std::uint32_t>(parsedClassVersion); | |||
| 7697 | m_name = std::move(parsedName); | |||
| 7698 | m_type = static_cast<std::uint32_t>(parsedType); | |||
| 7699 | m_status = parsedStatus; | |||
| 7700 | m_color = parsedColor; | |||
| 7701 | m_plotGlyph = parsedPlotGlyph; | |||
| 7702 | m_intensity = parsedIntensity; | |||
| 7703 | m_position = parsedPosition; | |||
| 7704 | m_target = parsedTarget; | |||
| 7705 | m_attenuationType = static_cast<std::uint32_t>(parsedAttenuationType); | |||
| 7706 | m_useAttenuationLimits = parsedUseAttenuationLimits; | |||
| 7707 | m_attenuationStartLimit = parsedAttenuationStartLimit; | |||
| 7708 | m_attenuationEndLimit = parsedAttenuationEndLimit; | |||
| 7709 | m_hotspotAngle = parsedHotspotAngle; | |||
| 7710 | m_falloffAngle = parsedFalloffAngle; | |||
| 7711 | m_castShadows = parsedCastShadows; | |||
| 7712 | m_shadowType = static_cast<std::uint32_t>(parsedShadowType); | |||
| 7713 | m_shadowMapSize = parsedShadowMapSize; | |||
| 7714 | m_shadowMapSoftness = parsedShadowMapSoftness; | |||
| 7715 | m_hasPhotometricData = hasPhotometricData; | |||
| 7716 | m_hasWebFile = hasWebFile; | |||
| 7717 | m_webFile = std::move(webFile); | |||
| 7718 | m_physicalIntensityMethod = physicalIntensityMethod; | |||
| 7719 | m_physicalIntensity = physicalIntensity; | |||
| 7720 | m_illuminanceDistance = illuminanceDistance; | |||
| 7721 | m_lampColorType = lampColorType; | |||
| 7722 | m_lampColorTemperature = lampColorTemperature; | |||
| 7723 | m_lampColorPreset = lampColorPreset; | |||
| 7724 | m_webRotation = webRotation; | |||
| 7725 | m_extendedLightShape = extendedLightShape; | |||
| 7726 | m_extendedLightLength = extendedLightLength; | |||
| 7727 | m_extendedLightWidth = extendedLightWidth; | |||
| 7728 | m_extendedLightRadius = extendedLightRadius; | |||
| 7729 | DRW_DBG("LIGHT name: ")DRW_dbg::dbg("LIGHT name: "); DRW_DBG(m_name.c_str())DRW_dbg::dbg(m_name.c_str()); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 7730 | *sourceBuf = handleProbe; | |||
| 7731 | return true; | |||
| 7732 | } | |||
| 7733 | ||||
| 7734 | bool DRW_Camera::parseCode(int code, | |||
| 7735 | const std::unique_ptr<dxfReader>& reader) { | |||
| 7736 | if (code == 340) { | |||
| 7737 | m_viewHandle = reader->getHandleString(); | |||
| 7738 | return true; | |||
| 7739 | } | |||
| 7740 | return DRW_Entity::parseCode(code, reader); | |||
| 7741 | } | |||
| 7742 | ||||
| 7743 | void DRW_Camera::resetDwgState() { | |||
| 7744 | DRW_Entity::reset(); | |||
| 7745 | m_viewHandle = 0; | |||
| 7746 | } | |||
| 7747 | ||||
| 7748 | bool DRW_Camera::parseDwg(DRW::Version v, dwgBuffer *buf, | |||
| 7749 | std::uint32_t bs) { | |||
| 7750 | resetDwgState(); | |||
| 7751 | dwgBuffer *sourceBuf = buf; | |||
| 7752 | auto fail = [this, sourceBuf]() { | |||
| 7753 | if (sourceBuf != nullptr) | |||
| 7754 | sourceBuf->invalidate(); | |||
| 7755 | resetDwgState(); | |||
| 7756 | return false; | |||
| 7757 | }; | |||
| 7758 | if (sourceBuf == nullptr || v < DRW::AC1015) | |||
| 7759 | return fail(); | |||
| 7760 | ||||
| 7761 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 7762 | dwgBuffer stringProbe = sourceBuf->forkIndependent(); | |||
| 7763 | if (!DRW_Entity::parseDwg( | |||
| 7764 | v, &bodyProbe, v > DRW::AC1018 ? &stringProbe : nullptr, bs) | |||
| 7765 | || !bodyProbe.isGood() || !stringProbe.isGood()) | |||
| 7766 | return fail(); | |||
| 7767 | ||||
| 7768 | std::uint64_t handleEndBit = 0; | |||
| 7769 | if (!dwgHandleStreamEndBit(*sourceBuf, v, objSize, bs, handleEndBit)) | |||
| 7770 | return fail(); | |||
| 7771 | dwgBuffer handleProbe = bodyProbe.forkIndependent(); | |||
| 7772 | if (!DRW_Entity::parseDwgEntHandle(v, &handleProbe, true, handleEndBit) | |||
| 7773 | || !handleProbe.isGood()) | |||
| 7774 | return fail(); | |||
| 7775 | ||||
| 7776 | std::uint32_t viewHandle = 0; | |||
| 7777 | if (proxyEntityHasBits(handleProbe, handleEndBit, 8)) { | |||
| 7778 | dwgHandle viewH; | |||
| 7779 | if (!readBoundedDwgHandle(handleProbe, handleEndBit, 0, false, viewH)) | |||
| 7780 | return fail(); | |||
| 7781 | viewHandle = viewH.ref; | |||
| 7782 | } else if (currentDwgBit(&handleProbe) != handleEndBit) { | |||
| 7783 | return fail(); | |||
| 7784 | } | |||
| 7785 | ||||
| 7786 | m_viewHandle = viewHandle; | |||
| 7787 | *sourceBuf = handleProbe; | |||
| 7788 | return true; | |||
| 7789 | } | |||
| 7790 | ||||
| 7791 | bool DRW_Camera::encodeDwg(DRW::Version v, dwgBufferW *buf, | |||
| 7792 | std::uint32_t bs, dwgBufferW *strBuf, | |||
| 7793 | dwgBufferW *handleBuf) { | |||
| 7794 | (void)bs; | |||
| 7795 | if (v < DRW::AC1015 || buf == nullptr) | |||
| 7796 | return false; | |||
| 7797 | ||||
| 7798 | oType = kDwgClassNum; | |||
| 7799 | if (!encodeDwgCommon(v, buf, strBuf) | |||
| 7800 | || !encodeDwgEntHandle(v, buf, handleBuf)) { | |||
| 7801 | return false; | |||
| 7802 | } | |||
| 7803 | ||||
| 7804 | putHardPointerHandle(handleBuf ? handleBuf : buf, m_viewHandle); | |||
| 7805 | return true; | |||
| 7806 | } | |||
| 7807 | ||||
| 7808 | bool DRW_GeoPositionMarker::parseCode( | |||
| 7809 | int code, const std::unique_ptr<dxfReader>& reader) { | |||
| 7810 | switch (code) { | |||
| 7811 | case 90: | |||
| 7812 | { | |||
| 7813 | int value = 0; | |||
| 7814 | if (!readDxfIntInRange(reader, 0, std::numeric_limits<int>::max(), value)) | |||
| 7815 | return false; | |||
| 7816 | m_classVersion = static_cast<std::uint32_t>(value); | |||
| 7817 | } | |||
| 7818 | return true; | |||
| 7819 | case 10: | |||
| 7820 | m_position.x = reader->getDouble(); | |||
| 7821 | return true; | |||
| 7822 | case 20: | |||
| 7823 | m_position.y = reader->getDouble(); | |||
| 7824 | return true; | |||
| 7825 | case 30: | |||
| 7826 | m_position.z = reader->getDouble(); | |||
| 7827 | return true; | |||
| 7828 | case 40: | |||
| 7829 | if (m_dxfDouble40Count++ == 0) | |||
| 7830 | m_radius = reader->getDouble(); | |||
| 7831 | else if (m_dxfDouble40Count == 2) | |||
| 7832 | m_landingGap = reader->getDouble(); | |||
| 7833 | else | |||
| 7834 | (void)reader->getDouble(); | |||
| 7835 | return true; | |||
| 7836 | case 1: | |||
| 7837 | m_notes = reader->getUtf8String(); | |||
| 7838 | return true; | |||
| 7839 | case 280: | |||
| 7840 | { | |||
| 7841 | const int value = reader->getInt32(); | |||
| 7842 | if (value < 0 || value > std::numeric_limits<std::uint8_t>::max()) | |||
| 7843 | return false; | |||
| 7844 | m_textAlignment = static_cast<std::uint8_t>(value); | |||
| 7845 | } | |||
| 7846 | return true; | |||
| 7847 | case 290: | |||
| 7848 | { | |||
| 7849 | int value = 0; | |||
| 7850 | if (!readDxfIntInRange(reader, 0, 1, value)) | |||
| 7851 | return false; | |||
| 7852 | if (m_dxfBool290Count++ == 0) | |||
| 7853 | m_mtextVisible = value != 0; | |||
| 7854 | else if (m_dxfBool290Count == 2) | |||
| 7855 | m_enableFrameText = value != 0; | |||
| 7856 | } | |||
| 7857 | return true; | |||
| 7858 | default: | |||
| 7859 | return DRW_Entity::parseCode(code, reader); | |||
| 7860 | } | |||
| 7861 | } | |||
| 7862 | ||||
| 7863 | bool DRW_GeoPositionMarker::parseDxfVariant(const DRW_Variant& value) { | |||
| 7864 | switch (value.code()) { | |||
| 7865 | case 90: | |||
| 7866 | if (value.type() != DRW_Variant::INTEGER) | |||
| 7867 | return false; | |||
| 7868 | if (value.i_val() < 0) | |||
| 7869 | return false; | |||
| 7870 | m_classVersion = static_cast<std::uint32_t>(value.i_val()); | |||
| 7871 | return true; | |||
| 7872 | case 10: | |||
| 7873 | if (value.type() != DRW_Variant::DOUBLE) | |||
| 7874 | return false; | |||
| 7875 | m_position.x = value.d_val(); | |||
| 7876 | return true; | |||
| 7877 | case 20: | |||
| 7878 | if (value.type() != DRW_Variant::DOUBLE) | |||
| 7879 | return false; | |||
| 7880 | m_position.y = value.d_val(); | |||
| 7881 | return true; | |||
| 7882 | case 30: | |||
| 7883 | if (value.type() != DRW_Variant::DOUBLE) | |||
| 7884 | return false; | |||
| 7885 | m_position.z = value.d_val(); | |||
| 7886 | return true; | |||
| 7887 | case 40: | |||
| 7888 | if (value.type() != DRW_Variant::DOUBLE) | |||
| 7889 | return false; | |||
| 7890 | if (m_dxfDouble40Count++ == 0) | |||
| 7891 | m_radius = value.d_val(); | |||
| 7892 | else if (m_dxfDouble40Count == 2) | |||
| 7893 | m_landingGap = value.d_val(); | |||
| 7894 | return true; | |||
| 7895 | case 1: | |||
| 7896 | if (value.type() != DRW_Variant::STRING) | |||
| 7897 | return false; | |||
| 7898 | m_notes = value.c_str(); | |||
| 7899 | return true; | |||
| 7900 | case 280: | |||
| 7901 | if (value.type() != DRW_Variant::INTEGER) | |||
| 7902 | return false; | |||
| 7903 | if (value.i_val() < 0 | |||
| 7904 | || value.i_val() > std::numeric_limits<std::uint8_t>::max()) | |||
| 7905 | return false; | |||
| 7906 | m_textAlignment = static_cast<std::uint8_t>(value.i_val()); | |||
| 7907 | return true; | |||
| 7908 | case 290: | |||
| 7909 | if (value.type() != DRW_Variant::INTEGER) | |||
| 7910 | return false; | |||
| 7911 | if (value.i_val() < 0 || value.i_val() > 1) | |||
| 7912 | return false; | |||
| 7913 | if (m_dxfBool290Count++ == 0) | |||
| 7914 | m_mtextVisible = value.i_val() != 0; | |||
| 7915 | else if (m_dxfBool290Count == 2) | |||
| 7916 | m_enableFrameText = value.i_val() != 0; | |||
| 7917 | return true; | |||
| 7918 | default: | |||
| 7919 | return true; // Common and unknown groups remain raw-authoritative. | |||
| 7920 | } | |||
| 7921 | } | |||
| 7922 | ||||
| 7923 | void DRW_GeoPositionMarker::resetDwgState() { | |||
| 7924 | DRW_Entity::reset(); | |||
| 7925 | m_classVersion = 0; | |||
| 7926 | m_position = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 7927 | m_radius = 0.0; | |||
| 7928 | m_notes.clear(); | |||
| 7929 | m_landingGap = 0.0; | |||
| 7930 | m_mtextVisible = false; | |||
| 7931 | m_textAlignment = 0; | |||
| 7932 | m_enableFrameText = false; | |||
| 7933 | mtext.reset(); | |||
| 7934 | m_dxfDouble40Count = 0; | |||
| 7935 | m_dxfBool290Count = 0; | |||
| 7936 | } | |||
| 7937 | ||||
| 7938 | bool DRW_GeoPositionMarker::parseDwg(DRW::Version v, dwgBuffer *buf, | |||
| 7939 | std::uint32_t bs) { | |||
| 7940 | resetDwgState(); | |||
| 7941 | dwgBuffer *sourceBuf = buf; | |||
| 7942 | auto fail = [this, sourceBuf]() { | |||
| 7943 | if (sourceBuf != nullptr) | |||
| 7944 | sourceBuf->invalidate(); | |||
| 7945 | resetDwgState(); | |||
| 7946 | return false; | |||
| 7947 | }; | |||
| 7948 | if (sourceBuf == nullptr || v < DRW::AC1027) | |||
| 7949 | return fail(); | |||
| 7950 | ||||
| 7951 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 7952 | dwgBuffer stringProbe = sourceBuf->forkIndependent(); | |||
| 7953 | if (!DRW_Entity::parseDwg(v, &bodyProbe, &stringProbe, bs) | |||
| 7954 | || !bodyProbe.isGood() || !stringProbe.isGood()) | |||
| 7955 | return fail(); | |||
| 7956 | ||||
| 7957 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 7958 | std::uint64_t stringStartBit = bodyEndBit; | |||
| 7959 | std::uint64_t stringEndBit = bodyEndBit; | |||
| 7960 | if (v > DRW::AC1018 | |||
| 7961 | && (!bodyProbe.getR2007StringStreamBounds(objSize, stringStartBit, | |||
| 7962 | stringEndBit) | |||
| 7963 | || currentDwgBit(&stringProbe) > stringEndBit)) | |||
| 7964 | return fail(); | |||
| 7965 | ||||
| 7966 | std::int32_t parsedClassVersion = 0; | |||
| 7967 | DRW_Coord position; | |||
| 7968 | double radius = 0.0; | |||
| 7969 | UTF8STRINGstd::string notes; | |||
| 7970 | double landingGap = 0.0; | |||
| 7971 | bool mtextVisible = false; | |||
| 7972 | std::uint8_t textAlignment = 0; | |||
| 7973 | bool enableFrameText = false; | |||
| 7974 | if (!readBoundedBitLong(bodyProbe, bodyEndBit, parsedClassVersion) | |||
| 7975 | || !readBoundedBitCoord(bodyProbe, bodyEndBit, position) | |||
| 7976 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, radius) | |||
| 7977 | || !readBoundedVariableText(stringProbe, stringEndBit, v, notes) | |||
| 7978 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, landingGap) | |||
| 7979 | || !readBoundedBit(bodyProbe, bodyEndBit, mtextVisible) | |||
| 7980 | || !readBoundedRawChar8(bodyProbe, bodyEndBit, textAlignment) | |||
| 7981 | || !readBoundedBit(bodyProbe, bodyEndBit, enableFrameText)) | |||
| 7982 | return fail(); | |||
| 7983 | ||||
| 7984 | const auto finite = [](const DRW_Coord& point) { | |||
| 7985 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 7986 | && std::isfinite(point.z); | |||
| 7987 | }; | |||
| 7988 | if (!bodyProbe.isGood() || !stringProbe.isGood() | |||
| 7989 | || !finite(position) || !std::isfinite(radius) | |||
| 7990 | || !std::isfinite(landingGap)) | |||
| 7991 | return fail(); | |||
| 7992 | ||||
| 7993 | // AcDbMTextObjectEmbedded follows the marker body when framing is enabled. | |||
| 7994 | // Parse it on a bounded probe before the parent and embedded handle passes; | |||
| 7995 | // otherwise a truncated nested body can consume parent handle bytes. | |||
| 7996 | dwgBuffer bodyTailProbe = bodyProbe.forkIndependent(); | |||
| 7997 | std::unique_ptr<DRW_MText> parsedMText; | |||
| 7998 | EmbeddedMTextHandleInfo embeddedHandles; | |||
| 7999 | if (enableFrameText) { | |||
| 8000 | if (objSize == 0 | |||
| 8001 | || !(parsedMText = std::make_unique<DRW_MText>()) | |||
| 8002 | || !parseEmbeddedMTextDwg(v, &bodyTailProbe, &stringProbe, | |||
| 8003 | *parsedMText, embeddedHandles, | |||
| 8004 | bodyEndBit, stringEndBit) | |||
| 8005 | || !bodyTailProbe.isGood() || !stringProbe.isGood()) | |||
| 8006 | return fail(); | |||
| 8007 | } | |||
| 8008 | ||||
| 8009 | std::uint64_t handleEndBit = 0; | |||
| 8010 | if (!dwgHandleStreamEndBit(*sourceBuf, v, objSize, bs, handleEndBit)) | |||
| 8011 | return fail(); | |||
| 8012 | ||||
| 8013 | dwgBuffer handleProbe = bodyTailProbe.forkIndependent(); | |||
| 8014 | if (!DRW_Entity::parseDwgEntHandle(v, &handleProbe, true, handleEndBit) | |||
| 8015 | || !handleProbe.isGood()) | |||
| 8016 | return fail(); | |||
| 8017 | if (enableFrameText) { | |||
| 8018 | if (!consumeEmbeddedMTextHandles(v, &handleProbe, embeddedHandles, | |||
| 8019 | parsedMText.get(), handleEndBit)) | |||
| 8020 | return fail(); | |||
| 8021 | } | |||
| 8022 | ||||
| 8023 | m_classVersion = static_cast<std::uint32_t>(parsedClassVersion); | |||
| 8024 | m_position = position; | |||
| 8025 | m_radius = radius; | |||
| 8026 | m_notes = notes; | |||
| 8027 | m_landingGap = landingGap; | |||
| 8028 | m_mtextVisible = mtextVisible; | |||
| 8029 | m_textAlignment = textAlignment; | |||
| 8030 | m_enableFrameText = enableFrameText; | |||
| 8031 | mtext = std::move(parsedMText); | |||
| 8032 | *sourceBuf = handleProbe; | |||
| 8033 | return true; | |||
| 8034 | } | |||
| 8035 | ||||
| 8036 | bool DRW_Light::encodeDwg(DRW::Version v, dwgBufferW *buf, std::uint32_t bs, | |||
| 8037 | dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 8038 | (void)bs; | |||
| 8039 | if (v < DRW::AC1021) | |||
| 8040 | return false; | |||
| 8041 | ||||
| 8042 | oType = kDwgClassNum; | |||
| 8043 | if (!encodeDwgCommon(v, buf, strBuf)) | |||
| 8044 | return false; | |||
| 8045 | ||||
| 8046 | dwgBufferW *sb = strBuf ? strBuf : buf; | |||
| 8047 | buf->putBitLong(m_classVersion); | |||
| 8048 | sb->putVariableText(v, m_name); | |||
| 8049 | buf->putBitLong(m_type); | |||
| 8050 | buf->putBit(m_status ? 1 : 0); | |||
| 8051 | buf->putCmColor(v, static_cast<std::uint16_t>(m_color)); | |||
| 8052 | buf->putBit(m_plotGlyph ? 1 : 0); | |||
| 8053 | buf->putBitDouble(m_intensity); | |||
| 8054 | buf->put3BitDouble(m_position); | |||
| 8055 | buf->put3BitDouble(m_target); | |||
| 8056 | buf->putBitLong(m_attenuationType); | |||
| 8057 | buf->putBit(m_useAttenuationLimits ? 1 : 0); | |||
| 8058 | buf->putBitDouble(m_attenuationStartLimit); | |||
| 8059 | buf->putBitDouble(m_attenuationEndLimit); | |||
| 8060 | buf->putBitDouble(m_hotspotAngle); | |||
| 8061 | buf->putBitDouble(m_falloffAngle); | |||
| 8062 | buf->putBit(m_castShadows ? 1 : 0); | |||
| 8063 | buf->putBitLong(m_shadowType); | |||
| 8064 | buf->putBitShort(m_shadowMapSize); | |||
| 8065 | buf->putRawChar8(m_shadowMapSoftness); | |||
| 8066 | ||||
| 8067 | buf->putBit(m_hasPhotometricData ? 1 : 0); | |||
| 8068 | if (m_hasPhotometricData) { | |||
| 8069 | buf->putBit(m_hasWebFile ? 1 : 0); | |||
| 8070 | sb->putVariableText(v, m_webFile); | |||
| 8071 | buf->putBitShort(m_physicalIntensityMethod); | |||
| 8072 | buf->putBitDouble(m_physicalIntensity); | |||
| 8073 | buf->putBitDouble(m_illuminanceDistance); | |||
| 8074 | buf->putBitShort(m_lampColorType); | |||
| 8075 | buf->putBitDouble(m_lampColorTemperature); | |||
| 8076 | buf->putBitShort(m_lampColorPreset); | |||
| 8077 | buf->put3BitDouble(m_webRotation); | |||
| 8078 | buf->putBitShort(m_extendedLightShape); | |||
| 8079 | buf->putBitDouble(m_extendedLightLength); | |||
| 8080 | buf->putBitDouble(m_extendedLightWidth); | |||
| 8081 | buf->putBitDouble(m_extendedLightRadius); | |||
| 8082 | } | |||
| 8083 | ||||
| 8084 | return encodeDwgEntHandle(v, buf, handleBuf); | |||
| 8085 | } | |||
| 8086 | ||||
| 8087 | bool DRW_SectionObject::parseCode( | |||
| 8088 | int code, const std::unique_ptr<dxfReader>& reader) { | |||
| 8089 | if (code != 100 && !m_dxfInBody) | |||
| 8090 | return DRW_Entity::parseCode(code, reader); | |||
| 8091 | switch (code) { | |||
| 8092 | case 100: | |||
| 8093 | m_dxfInBody = reader->getUtf8String() == "AcDbSection"; | |||
| 8094 | return true; | |||
| 8095 | case 90: | |||
| 8096 | m_state = static_cast<std::uint32_t>(reader->getInt32()); | |||
| 8097 | return true; | |||
| 8098 | case 91: | |||
| 8099 | m_flags = static_cast<std::uint32_t>(reader->getInt32()); | |||
| 8100 | return true; | |||
| 8101 | case 1: | |||
| 8102 | m_name = reader->getUtf8String(); | |||
| 8103 | return true; | |||
| 8104 | case 10: | |||
| 8105 | m_vertDir.x = reader->getDouble(); | |||
| 8106 | return true; | |||
| 8107 | case 20: | |||
| 8108 | m_vertDir.y = reader->getDouble(); | |||
| 8109 | return true; | |||
| 8110 | case 30: | |||
| 8111 | m_vertDir.z = reader->getDouble(); | |||
| 8112 | return true; | |||
| 8113 | case 40: | |||
| 8114 | m_topHeight = reader->getDouble(); | |||
| 8115 | return true; | |||
| 8116 | case 41: | |||
| 8117 | m_bottomHeight = reader->getDouble(); | |||
| 8118 | return true; | |||
| 8119 | case 70: | |||
| 8120 | { | |||
| 8121 | const int value = reader->getInt32(); | |||
| 8122 | if (value < 0 || value > 0xFFFF) | |||
| 8123 | return false; | |||
| 8124 | m_indicatorAlpha = static_cast<std::uint16_t>(value); | |||
| 8125 | } | |||
| 8126 | return true; | |||
| 8127 | case 62: | |||
| 8128 | m_indicatorColor = static_cast<std::uint32_t>(reader->getInt32()); | |||
| 8129 | return true; | |||
| 8130 | case 92: | |||
| 8131 | { | |||
| 8132 | const int value = reader->getInt32(); | |||
| 8133 | if (value < 0 | |||
| 8134 | || static_cast<std::size_t>(value) > DRW_SectionObject::kMaxVertices) | |||
| 8135 | return false; | |||
| 8136 | m_verts.clear(); | |||
| 8137 | if (!DRW::reserve(m_verts, value)) | |||
| 8138 | return false; | |||
| 8139 | return true; | |||
| 8140 | } | |||
| 8141 | case 93: | |||
| 8142 | { | |||
| 8143 | const int value = reader->getInt32(); | |||
| 8144 | if (value < 0 | |||
| 8145 | || static_cast<std::size_t>(value) > DRW_SectionObject::kMaxVertices) | |||
| 8146 | return false; | |||
| 8147 | m_blVerts.clear(); | |||
| 8148 | if (!DRW::reserve(m_blVerts, value)) | |||
| 8149 | return false; | |||
| 8150 | return true; | |||
| 8151 | } | |||
| 8152 | case 11: | |||
| 8153 | if (m_verts.size() >= DRW_SectionObject::kMaxVertices) | |||
| 8154 | return false; | |||
| 8155 | m_verts.emplace_back(); | |||
| 8156 | m_verts.back().x = reader->getDouble(); | |||
| 8157 | return true; | |||
| 8158 | case 21: | |||
| 8159 | if (m_verts.empty()) | |||
| 8160 | return false; | |||
| 8161 | m_verts.back().y = reader->getDouble(); | |||
| 8162 | return true; | |||
| 8163 | case 31: | |||
| 8164 | if (m_verts.empty()) | |||
| 8165 | return false; | |||
| 8166 | m_verts.back().z = reader->getDouble(); | |||
| 8167 | return true; | |||
| 8168 | case 12: | |||
| 8169 | if (m_blVerts.size() >= DRW_SectionObject::kMaxVertices) | |||
| 8170 | return false; | |||
| 8171 | m_blVerts.emplace_back(); | |||
| 8172 | m_blVerts.back().x = reader->getDouble(); | |||
| 8173 | return true; | |||
| 8174 | case 22: | |||
| 8175 | if (m_blVerts.empty()) | |||
| 8176 | return false; | |||
| 8177 | m_blVerts.back().y = reader->getDouble(); | |||
| 8178 | return true; | |||
| 8179 | case 32: | |||
| 8180 | if (m_blVerts.empty()) | |||
| 8181 | return false; | |||
| 8182 | m_blVerts.back().z = reader->getDouble(); | |||
| 8183 | return true; | |||
| 8184 | case 360: | |||
| 8185 | m_sectionSettingsHandle = reader->getHandleString(); | |||
| 8186 | return true; | |||
| 8187 | default: | |||
| 8188 | return DRW_Entity::parseCode(code, reader); | |||
| 8189 | } | |||
| 8190 | } | |||
| 8191 | ||||
| 8192 | // DRW_SectionObject::parseDwg — SECTIONOBJECT / AcDbSection, field order per | |||
| 8193 | // libreDWG dwg2.spec DWG_ENTITY(SECTIONOBJECT): BL state, BL flags, T name, | |||
| 8194 | // 3BD vert_dir, BD top/bottom height, BS indicator_alpha, CMTC indicator_color, | |||
| 8195 | // BL num_verts + verts, BL num_blverts + blverts; then the common entity handle | |||
| 8196 | // data followed by the section_settings hard reference (H 5, 360). | |||
| 8197 | void DRW_SectionObject::resetDwgState() { | |||
| 8198 | DRW_Entity::reset(); | |||
| 8199 | m_state = 0; | |||
| 8200 | m_flags = 0; | |||
| 8201 | m_name.clear(); | |||
| 8202 | m_vertDir = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 8203 | m_topHeight = 0.0; | |||
| 8204 | m_bottomHeight = 0.0; | |||
| 8205 | m_indicatorAlpha = 0; | |||
| 8206 | m_indicatorColor = 0; | |||
| 8207 | m_verts.clear(); | |||
| 8208 | m_blVerts.clear(); | |||
| 8209 | m_sectionSettingsHandle = 0; | |||
| 8210 | m_dxfInBody = false; | |||
| 8211 | } | |||
| 8212 | ||||
| 8213 | bool DRW_SectionObject::parseDwg(DRW::Version v, dwgBuffer *buf, | |||
| 8214 | std::uint32_t bs) { | |||
| 8215 | resetDwgState(); | |||
| 8216 | dwgBuffer *sourceBuf = buf; | |||
| 8217 | auto fail = [this, sourceBuf]() { | |||
| 8218 | if (sourceBuf != nullptr) | |||
| 8219 | sourceBuf->invalidate(); | |||
| 8220 | resetDwgState(); | |||
| 8221 | return false; | |||
| 8222 | }; | |||
| 8223 | if (sourceBuf == nullptr) | |||
| 8224 | return fail(); | |||
| 8225 | ||||
| 8226 | // R2007+ stores text in a separate stream. Independent cursors keep a | |||
| 8227 | // malformed field from consuming the source or a later handle stream. | |||
| 8228 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 8229 | dwgBuffer stringProbe = sourceBuf->forkIndependent(); | |||
| 8230 | dwgBuffer *stringStream = v > DRW::AC1018 ? &stringProbe : &bodyProbe; | |||
| 8231 | if (!DRW_Entity::parseDwg(v, &bodyProbe, stringStream, bs) | |||
| 8232 | || !bodyProbe.isGood() || !stringStream->isGood()) | |||
| 8233 | return fail(); | |||
| 8234 | DRW_DBG("\n***************************** parsing SECTIONOBJECT *********************\n")DRW_dbg::dbg("\n***************************** parsing SECTIONOBJECT *********************\n" ); | |||
| 8235 | ||||
| 8236 | // The common entity parser leaves bodyProbe at the first SECTIONOBJECT | |||
| 8237 | // field and stringStream at the detached string stream for R2007+. | |||
| 8238 | // Keep both cursors inside their declared data ranges while staging the | |||
| 8239 | // complete header before publishing it. | |||
| 8240 | const std::uint64_t bodyEndBit = tableBodyEndBit(v, stringStream, objSize); | |||
| 8241 | const std::uint64_t stringEndBit = v > DRW::AC1018 | |||
| 8242 | ? objSize : bodyEndBit; | |||
| 8243 | std::int32_t stateValue = 0; | |||
| 8244 | std::int32_t flagsValue = 0; | |||
| 8245 | UTF8STRINGstd::string name; | |||
| 8246 | DRW_Coord vertDir; | |||
| 8247 | double topHeight = 0.0; | |||
| 8248 | double bottomHeight = 0.0; | |||
| 8249 | std::uint16_t indicatorAlpha = 0; | |||
| 8250 | std::uint32_t indicatorColor = 0; | |||
| 8251 | if (!readBoundedBitLong(bodyProbe, bodyEndBit, stateValue) | |||
| 8252 | || !readBoundedBitLong(bodyProbe, bodyEndBit, flagsValue) | |||
| 8253 | || !readBoundedVariableText(*stringStream, stringEndBit, v, name) | |||
| 8254 | || !readBoundedBitCoord(bodyProbe, bodyEndBit, vertDir) | |||
| 8255 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, topHeight) | |||
| 8256 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, bottomHeight) | |||
| 8257 | || !readBoundedBitShort(bodyProbe, bodyEndBit, indicatorAlpha) | |||
| 8258 | || !readBoundedCmColor(bodyProbe, stringStream, bodyEndBit, v, | |||
| 8259 | indicatorColor, nullptr, nullptr, nullptr, | |||
| 8260 | nullptr, stringEndBit)) | |||
| 8261 | return fail(); | |||
| 8262 | ||||
| 8263 | std::uint32_t numVerts = 0; | |||
| 8264 | if (!readTableBodyCount( | |||
| 8265 | v, &bodyProbe, bodyEndBit, | |||
| 8266 | static_cast<std::uint32_t>(DRW_SectionObject::kMaxVertices), 6, | |||
| 8267 | numVerts) | |||
| 8268 | || !proxyEntityHasBits( | |||
| 8269 | bodyProbe, bodyEndBit, static_cast<std::uint64_t>(numVerts) * 6u)) | |||
| 8270 | return fail(); | |||
| 8271 | std::vector<DRW_Coord> verts; | |||
| 8272 | if (!DRW::reserve(verts, static_cast<int>(numVerts))) | |||
| 8273 | return fail(); | |||
| 8274 | for (std::uint32_t i = 0; i < numVerts; ++i) { | |||
| 8275 | DRW_Coord vertex; | |||
| 8276 | if (!readBoundedBitCoord(bodyProbe, bodyEndBit, vertex)) | |||
| 8277 | return fail(); | |||
| 8278 | verts.push_back(vertex); | |||
| 8279 | } | |||
| 8280 | ||||
| 8281 | std::uint32_t numBl = 0; | |||
| 8282 | if (!readTableBodyCount( | |||
| 8283 | v, &bodyProbe, bodyEndBit, | |||
| 8284 | static_cast<std::uint32_t>(DRW_SectionObject::kMaxVertices), 6, | |||
| 8285 | numBl) | |||
| 8286 | || !proxyEntityHasBits( | |||
| 8287 | bodyProbe, bodyEndBit, static_cast<std::uint64_t>(numBl) * 6u)) | |||
| 8288 | return fail(); | |||
| 8289 | std::vector<DRW_Coord> blVerts; | |||
| 8290 | if (!DRW::reserve(blVerts, static_cast<int>(numBl))) | |||
| 8291 | return fail(); | |||
| 8292 | for (std::uint32_t i = 0; i < numBl; ++i) { | |||
| 8293 | DRW_Coord vertex; | |||
| 8294 | if (!readBoundedBitCoord(bodyProbe, bodyEndBit, vertex)) | |||
| 8295 | return fail(); | |||
| 8296 | blVerts.push_back(vertex); | |||
| 8297 | } | |||
| 8298 | ||||
| 8299 | const auto finite = [](const DRW_Coord& point) { | |||
| 8300 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 8301 | && std::isfinite(point.z); | |||
| 8302 | }; | |||
| 8303 | if (!bodyProbe.isGood() || !stringStream->isGood() | |||
| 8304 | || currentDwgBit(&bodyProbe) > bodyEndBit | |||
| 8305 | || !finite(vertDir) || !std::isfinite(topHeight) | |||
| 8306 | || !std::isfinite(bottomHeight)) | |||
| 8307 | return fail(); | |||
| 8308 | if (!std::all_of(verts.begin(), verts.end(), finite) | |||
| 8309 | || !std::all_of(blVerts.begin(), blVerts.end(), finite)) | |||
| 8310 | return fail(); | |||
| 8311 | ||||
| 8312 | // The common entity handle stream starts at the object-data boundary for | |||
| 8313 | // R2007+ and follows the body inline in older versions. The section | |||
| 8314 | // settings reference is a hard pointer (H 5), after those common handles. | |||
| 8315 | std::uint64_t handleEndBit = 0; | |||
| 8316 | if (!dwgHandleStreamEndBit(*sourceBuf, v, objSize, bs, handleEndBit)) | |||
| 8317 | return fail(); | |||
| 8318 | dwgBuffer handleProbe = bodyProbe.forkIndependent(); | |||
| 8319 | if (!DRW_Entity::parseDwgEntHandle(v, &handleProbe, true, handleEndBit) | |||
| 8320 | || !handleProbe.isGood()) | |||
| 8321 | return fail(); | |||
| 8322 | std::uint32_t sectionSettingsHandle = 0; | |||
| 8323 | if (proxyEntityHasBits(handleProbe, handleEndBit, 8)) { | |||
| 8324 | dwgHandle settingsHandle; | |||
| 8325 | if (!readBoundedDwgHandle(handleProbe, handleEndBit, handle, false, | |||
| 8326 | settingsHandle)) | |||
| 8327 | return fail(); | |||
| 8328 | sectionSettingsHandle = settingsHandle.ref; | |||
| 8329 | DRW_DBG(" section_settings Handle: ")DRW_dbg::dbg(" section_settings Handle: "); | |||
| 8330 | DRW_DBGHL(settingsHandle.code, settingsHandle.size,DRW_dbg::dbgHL(settingsHandle.code, settingsHandle.size, settingsHandle .ref) | |||
| 8331 | settingsHandle.ref)DRW_dbg::dbgHL(settingsHandle.code, settingsHandle.size, settingsHandle .ref); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 8332 | } | |||
| 8333 | if (!handleProbe.isGood()) | |||
| 8334 | return fail(); | |||
| 8335 | ||||
| 8336 | m_state = static_cast<std::uint32_t>(stateValue); | |||
| 8337 | m_flags = static_cast<std::uint32_t>(flagsValue); | |||
| 8338 | m_name = name; | |||
| 8339 | m_vertDir = vertDir; | |||
| 8340 | m_topHeight = topHeight; | |||
| 8341 | m_bottomHeight = bottomHeight; | |||
| 8342 | m_indicatorAlpha = indicatorAlpha; | |||
| 8343 | m_indicatorColor = indicatorColor; | |||
| 8344 | m_verts = std::move(verts); | |||
| 8345 | m_blVerts = std::move(blVerts); | |||
| 8346 | m_sectionSettingsHandle = sectionSettingsHandle; | |||
| 8347 | *sourceBuf = handleProbe; | |||
| 8348 | DRW_DBG("SECTIONOBJECT name: ")DRW_dbg::dbg("SECTIONOBJECT name: "); DRW_DBG(m_name.c_str())DRW_dbg::dbg(m_name.c_str()); | |||
| 8349 | DRW_DBG(" verts: ")DRW_dbg::dbg(" verts: "); DRW_DBG(static_cast<int>(m_verts.size()))DRW_dbg::dbg(static_cast<int>(m_verts.size())); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 8350 | return true; | |||
| 8351 | } | |||
| 8352 | ||||
| 8353 | bool DRW_SectionObject::encodeDwg(DRW::Version v, dwgBufferW *buf, | |||
| 8354 | std::uint32_t bs, dwgBufferW *strBuf, | |||
| 8355 | dwgBufferW *handleBuf) { | |||
| 8356 | (void)bs; | |||
| 8357 | if (v < DRW::AC1021 || buf == nullptr | |||
| 8358 | || m_verts.size() > DRW_SectionObject::kMaxVertices | |||
| 8359 | || m_blVerts.size() > DRW_SectionObject::kMaxVertices) | |||
| 8360 | return false; | |||
| 8361 | oType = kDwgClassNum; | |||
| 8362 | if (!encodeDwgCommon(v, buf, strBuf)) | |||
| 8363 | return false; | |||
| 8364 | dwgBufferW *stringBuffer = strBuf != nullptr ? strBuf : buf; | |||
| 8365 | buf->putBitLong(static_cast<std::int32_t>(m_state)); | |||
| 8366 | buf->putBitLong(static_cast<std::int32_t>(m_flags)); | |||
| 8367 | stringBuffer->putVariableText(v, m_name); | |||
| 8368 | buf->put3BitDouble(m_vertDir); | |||
| 8369 | buf->putBitDouble(m_topHeight); | |||
| 8370 | buf->putBitDouble(m_bottomHeight); | |||
| 8371 | buf->putBitShort(m_indicatorAlpha); | |||
| 8372 | buf->putCmColor(v, static_cast<std::uint16_t>(m_indicatorColor)); | |||
| 8373 | buf->putBitLong(static_cast<std::int32_t>(m_verts.size())); | |||
| 8374 | for (const DRW_Coord& point : m_verts) | |||
| 8375 | buf->put3BitDouble(point); | |||
| 8376 | buf->putBitLong(static_cast<std::int32_t>(m_blVerts.size())); | |||
| 8377 | for (const DRW_Coord& point : m_blVerts) | |||
| 8378 | buf->put3BitDouble(point); | |||
| 8379 | if (!encodeDwgEntHandle(v, buf, handleBuf)) | |||
| 8380 | return false; | |||
| 8381 | putHardPointerHandle(handleBuf != nullptr ? handleBuf : buf, | |||
| 8382 | m_sectionSettingsHandle); | |||
| 8383 | return true; | |||
| 8384 | } | |||
| 8385 | ||||
| 8386 | bool DRW_Tolerance::parseCode(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 8387 | switch (code) { | |||
| 8388 | case 1: | |||
| 8389 | text = reader->getUtf8String(); | |||
| 8390 | break; | |||
| 8391 | case 3: | |||
| 8392 | dimStyleName = reader->getUtf8String(); | |||
| 8393 | break; | |||
| 8394 | case 10: | |||
| 8395 | insertionPoint.x = reader->getDouble(); | |||
| 8396 | break; | |||
| 8397 | case 20: | |||
| 8398 | insertionPoint.y = reader->getDouble(); | |||
| 8399 | break; | |||
| 8400 | case 30: | |||
| 8401 | insertionPoint.z = reader->getDouble(); | |||
| 8402 | break; | |||
| 8403 | case 11: | |||
| 8404 | xAxisDirectionVector.x = reader->getDouble(); | |||
| 8405 | break; | |||
| 8406 | case 21: | |||
| 8407 | xAxisDirectionVector.y = reader->getDouble(); | |||
| 8408 | break; | |||
| 8409 | case 31: | |||
| 8410 | xAxisDirectionVector.z = reader->getDouble(); | |||
| 8411 | break; | |||
| 8412 | case 210: | |||
| 8413 | extPoint.x = reader->getDouble(); | |||
| 8414 | break; | |||
| 8415 | case 220: | |||
| 8416 | extPoint.y = reader->getDouble(); | |||
| 8417 | break; | |||
| 8418 | case 230: | |||
| 8419 | extPoint.z = reader->getDouble(); | |||
| 8420 | break; | |||
| 8421 | default: | |||
| 8422 | return DRW_Entity::parseCode(code, reader); | |||
| 8423 | } | |||
| 8424 | return true; | |||
| 8425 | } | |||
| 8426 | ||||
| 8427 | void DRW_Tolerance::resetDwgState() { | |||
| 8428 | DRW_Entity::reset(); | |||
| 8429 | text.clear(); | |||
| 8430 | dimStyleName = "STANDARD"; | |||
| 8431 | dimStyleH = dwgHandle{}; | |||
| 8432 | insertionPoint = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 8433 | xAxisDirectionVector = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 8434 | extPoint = DRW_Coord{0.0, 0.0, 1.0}; | |||
| 8435 | } | |||
| 8436 | ||||
| 8437 | bool DRW_Tolerance::parseDwg(DRW::Version v, dwgBuffer *buf, | |||
| 8438 | std::uint32_t bs) { | |||
| 8439 | resetDwgState(); | |||
| 8440 | dwgBuffer *sourceBuf = buf; | |||
| 8441 | auto fail = [this, sourceBuf]() { | |||
| 8442 | if (sourceBuf != nullptr) | |||
| 8443 | sourceBuf->invalidate(); | |||
| 8444 | resetDwgState(); | |||
| 8445 | return false; | |||
| 8446 | }; | |||
| 8447 | if (sourceBuf == nullptr) | |||
| 8448 | return fail(); | |||
| 8449 | ||||
| 8450 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 8451 | dwgBuffer stringProbe = sourceBuf->forkIndependent(); | |||
| 8452 | dwgBuffer *stringStream = v > DRW::AC1018 ? &stringProbe : &bodyProbe; | |||
| 8453 | if (!DRW_Entity::parseDwg(v, &bodyProbe, stringStream, bs) | |||
| 8454 | || !bodyProbe.isGood() || !stringStream->isGood()) | |||
| 8455 | return fail(); | |||
| 8456 | ||||
| 8457 | DRW_DBG("\n***************************** parsing tolerance *********************************************\n")DRW_dbg::dbg("\n***************************** parsing tolerance *********************************************\n" ); | |||
| 8458 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 8459 | const std::uint64_t stringStartBit = currentDwgBit(stringStream); | |||
| 8460 | std::uint64_t stringEndBit = bodyEndBit; | |||
| 8461 | if (v > DRW::AC1021) { | |||
| 8462 | std::uint64_t ignoredBodyEndBit = 0; | |||
| 8463 | if (!entityBodyDataEndBit(*stringStream, v, objSize, | |||
| 8464 | ignoredBodyEndBit, &stringEndBit)) | |||
| 8465 | return fail(); | |||
| 8466 | } | |||
| 8467 | auto read3BitDoubleChecked = [&](DRW_Coord& point) { | |||
| 8468 | return readBoundedBitDouble(bodyProbe, bodyEndBit, point.x) | |||
| 8469 | && readBoundedBitDouble(bodyProbe, bodyEndBit, point.y) | |||
| 8470 | && readBoundedBitDouble(bodyProbe, bodyEndBit, point.z); | |||
| 8471 | }; | |||
| 8472 | ||||
| 8473 | if (v < DRW::AC1015) { | |||
| 8474 | std::uint16_t unknown = 0; | |||
| 8475 | double heightAtCreation = 0.0; | |||
| 8476 | double dimGapAtCreation = 0.0; | |||
| 8477 | if (!readBoundedBitShort(bodyProbe, bodyEndBit, unknown) | |||
| 8478 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, | |||
| 8479 | heightAtCreation) | |||
| 8480 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, | |||
| 8481 | dimGapAtCreation) | |||
| 8482 | || !std::isfinite(heightAtCreation) | |||
| 8483 | || !std::isfinite(dimGapAtCreation)) | |||
| 8484 | return fail(); | |||
| 8485 | } | |||
| 8486 | ||||
| 8487 | DRW_Coord parsedInsertionPoint; | |||
| 8488 | DRW_Coord parsedXAxisDirectionVector; | |||
| 8489 | DRW_Coord parsedExtPoint; | |||
| 8490 | if (!read3BitDoubleChecked(parsedInsertionPoint) | |||
| 8491 | || !read3BitDoubleChecked(parsedXAxisDirectionVector) | |||
| 8492 | || !read3BitDoubleChecked(parsedExtPoint)) | |||
| 8493 | return fail(); | |||
| 8494 | UTF8STRINGstd::string parsedText; | |||
| 8495 | if (v > DRW::AC1018 && stringStartBit >= stringEndBit) { | |||
| 8496 | parsedText.clear(); | |||
| 8497 | } else if (!readBoundedVariableText(*stringStream, stringEndBit, v, | |||
| 8498 | parsedText)) { | |||
| 8499 | return fail(); | |||
| 8500 | } | |||
| 8501 | ||||
| 8502 | const auto finite = [](const DRW_Coord& point) { | |||
| 8503 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 8504 | && std::isfinite(point.z); | |||
| 8505 | }; | |||
| 8506 | if (!bodyProbe.isGood() || !stringStream->isGood() | |||
| 8507 | || currentDwgBit(&bodyProbe) > bodyEndBit | |||
| 8508 | || currentDwgBit(stringStream) > stringEndBit | |||
| 8509 | || !finite(parsedInsertionPoint) | |||
| 8510 | || !finite(parsedXAxisDirectionVector) | |||
| 8511 | || !finite(parsedExtPoint)) | |||
| 8512 | return fail(); | |||
| 8513 | ||||
| 8514 | std::uint64_t handleEndBit = 0; | |||
| 8515 | if (!dwgHandleStreamEndBit(*sourceBuf, v, objSize, bs, handleEndBit)) | |||
| 8516 | return fail(); | |||
| 8517 | dwgBuffer handleProbe = bodyProbe.forkIndependent(); | |||
| 8518 | if (!DRW_Entity::parseDwgEntHandle(v, &handleProbe, true, handleEndBit) | |||
| 8519 | || !handleProbe.isGood()) | |||
| 8520 | return fail(); | |||
| 8521 | dwgHandle parsedDimStyleH; | |||
| 8522 | if (!readBoundedDwgHandle(handleProbe, handleEndBit, handle, false, | |||
| 8523 | parsedDimStyleH) | |||
| 8524 | || !handleProbe.isGood()) | |||
| 8525 | return fail(); | |||
| 8526 | ||||
| 8527 | insertionPoint = parsedInsertionPoint; | |||
| 8528 | xAxisDirectionVector = parsedXAxisDirectionVector; | |||
| 8529 | extPoint = parsedExtPoint; | |||
| 8530 | text = parsedText; | |||
| 8531 | dimStyleH = parsedDimStyleH; | |||
| 8532 | *sourceBuf = handleProbe; | |||
| 8533 | DRW_DBG("insertionPoint: ")DRW_dbg::dbg("insertionPoint: "); | |||
| 8534 | DRW_DBGPT(insertionPoint.x, insertionPoint.y, insertionPoint.z)DRW_dbg::dbgPT(insertionPoint.x, insertionPoint.y, insertionPoint .z); | |||
| 8535 | DRW_DBG("\ntolerance text: ")DRW_dbg::dbg("\ntolerance text: "); DRW_DBG(text.c_str())DRW_dbg::dbg(text.c_str()); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 8536 | DRW_DBG("dim style Handle: ")DRW_dbg::dbg("dim style Handle: "); | |||
| 8537 | DRW_DBGHL(dimStyleH.code, dimStyleH.size, dimStyleH.ref)DRW_dbg::dbgHL(dimStyleH.code, dimStyleH.size, dimStyleH.ref); | |||
| 8538 | DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 8539 | return true; | |||
| 8540 | } | |||
| 8541 | ||||
| 8542 | bool DRW_Tolerance::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, | |||
| 8543 | dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 8544 | (void)bs; | |||
| 8545 | oType = 46; | |||
| 8546 | if (!encodeDwgCommon(version, buf, strBuf)) | |||
| 8547 | return false; | |||
| 8548 | ||||
| 8549 | if (version < DRW::AC1015) { | |||
| 8550 | buf->putBitShort(0); | |||
| 8551 | buf->putBitDouble(0.0); | |||
| 8552 | buf->putBitDouble(0.0); | |||
| 8553 | } | |||
| 8554 | ||||
| 8555 | buf->put3BitDouble(insertionPoint); | |||
| 8556 | buf->put3BitDouble(xAxisDirectionVector); | |||
| 8557 | buf->put3BitDouble(extPoint); | |||
| 8558 | (strBuf ? strBuf : buf)->putVariableText(version, text); | |||
| 8559 | ||||
| 8560 | if (!encodeDwgEntHandle(version, buf, handleBuf)) | |||
| 8561 | return false; | |||
| 8562 | ||||
| 8563 | dwgBufferW *hb = handleBuf ? handleBuf : buf; | |||
| 8564 | putHardPointerHandle(hb, (dimStyleH.ref == 0) ? 0x15 : dimStyleH.ref); | |||
| 8565 | return true; | |||
| 8566 | } | |||
| 8567 | ||||
| 8568 | ||||
| 8569 | bool DRW_Block::parseCode(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 8570 | switch (code) { | |||
| 8571 | case 1: | |||
| 8572 | xrefPath = reader->getUtf8String(); | |||
| 8573 | break; | |||
| 8574 | case 2: | |||
| 8575 | name = reader->getUtf8String(); | |||
| 8576 | break; | |||
| 8577 | case 70: | |||
| 8578 | flags = reader->getInt32(); | |||
| 8579 | break; | |||
| 8580 | default: | |||
| 8581 | return DRW_Point::parseCode(code, reader); | |||
| 8582 | } | |||
| 8583 | ||||
| 8584 | return true; | |||
| 8585 | } | |||
| 8586 | ||||
| 8587 | void DRW_Block::resetDwgState() { | |||
| 8588 | const bool endBlock = isEnd; | |||
| 8589 | DRW_Point::resetDwgState(); | |||
| 8590 | name = endBlock ? UTF8STRINGstd::string() : UTF8STRINGstd::string("*U0"); | |||
| 8591 | flags = 0; | |||
| 8592 | insUnits = 0; | |||
| 8593 | xrefPath.clear(); | |||
| 8594 | previewData.clear(); | |||
| 8595 | isEnd = endBlock; | |||
| 8596 | } | |||
| 8597 | ||||
| 8598 | bool DRW_Block::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){ | |||
| 8599 | resetDwgState(); | |||
| 8600 | if (buf == nullptr) | |||
| 8601 | return false; | |||
| 8602 | auto fail = [this, buf]() { | |||
| 8603 | buf->invalidate(); | |||
| 8604 | resetDwgState(); | |||
| 8605 | return false; | |||
| 8606 | }; | |||
| 8607 | dwgBuffer bodyProbe = buf->forkIndependent(); | |||
| 8608 | dwgBuffer sBuff = bodyProbe.forkIndependent(); | |||
| 8609 | dwgBuffer *sBuf = &bodyProbe; | |||
| 8610 | if (version > DRW::AC1018) {//2007+ | |||
| 8611 | sBuf = &sBuff; //separate buffer for strings | |||
| 8612 | } | |||
| 8613 | bool ret = DRW_Entity::parseDwg(version, &bodyProbe, sBuf, bs); | |||
| 8614 | if (!ret) | |||
| 8615 | return fail(); | |||
| 8616 | ||||
| 8617 | // BLOCK/ENDBLK carry one entity-specific bit after the common data range; | |||
| 8618 | // the detached string stream begins at dwgDataEndBit and is independent. | |||
| 8619 | const std::uint64_t bodyEndBit = version > DRW::AC1018 | |||
| 8620 | && dwgDataEndBit < std::numeric_limits<std::uint64_t>::max() | |||
| 8621 | ? dwgDataEndBit + 1 : dwgDataEndBit; | |||
| 8622 | std::uint64_t stringStartBit = bodyEndBit; | |||
| 8623 | std::uint64_t stringEndBit = bodyEndBit; | |||
| 8624 | if (version > DRW::AC1018 | |||
| 8625 | && (!bodyProbe.getR2007StringStreamBounds(objSize, stringStartBit, | |||
| 8626 | stringEndBit) | |||
| 8627 | || currentDwgBit(sBuf) > stringEndBit)) | |||
| 8628 | return fail(); | |||
| 8629 | ||||
| 8630 | UTF8STRINGstd::string parsedName; | |||
| 8631 | if (!isEnd){ | |||
| 8632 | DRW_DBG("\n***************************** parsing block *********************************************\n")DRW_dbg::dbg("\n***************************** parsing block *********************************************\n" ); | |||
| 8633 | if (!readBoundedVariableText(*sBuf, stringEndBit, version, | |||
| 8634 | parsedName)) | |||
| 8635 | return fail(); | |||
| 8636 | DRW_DBG("Block name: ")DRW_dbg::dbg("Block name: "); DRW_DBG(parsedName.c_str())DRW_dbg::dbg(parsedName.c_str()); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 8637 | } else { | |||
| 8638 | DRW_DBG("\n***************************** parsing end block *********************************************\n")DRW_dbg::dbg("\n***************************** parsing end block *********************************************\n" ); | |||
| 8639 | } | |||
| 8640 | if (version > DRW::AC1018) {//2007+ | |||
| 8641 | bool ignoredUnknown = false; | |||
| 8642 | if (!readBoundedBit(bodyProbe, bodyEndBit, ignoredUnknown)) | |||
| 8643 | return fail(); | |||
| 8644 | DRW_DBG("unknown bit: ")DRW_dbg::dbg("unknown bit: "); DRW_DBG(ignoredUnknown)DRW_dbg::dbg(ignoredUnknown); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 8645 | } | |||
| 8646 | // X handleAssoc; //X | |||
| 8647 | if (!bodyProbe.isGood() || currentDwgBit(&bodyProbe) > bodyEndBit) | |||
| 8648 | return fail(); | |||
| 8649 | std::uint64_t handleEndBit = 0; | |||
| 8650 | if (!dwgHandleStreamEndBit(*buf, version, objSize, bs, handleEndBit)) | |||
| 8651 | return fail(); | |||
| 8652 | ret = DRW_Entity::parseDwgEntHandle(version, &bodyProbe, true, | |||
| 8653 | handleEndBit); | |||
| 8654 | if (!ret || !bodyProbe.isGood()) | |||
| 8655 | return fail(); | |||
| 8656 | // RS crc; //RS */ | |||
| 8657 | // R13-R2004 keep the handle stream inline and may consume the final | |||
| 8658 | // byte-alignment padding beyond the declared object-data bit count. | |||
| 8659 | // Only R2007+ has a separate string stream range to validate here. | |||
| 8660 | if (!bodyProbe.isGood() || !sBuf->isGood() | |||
| 8661 | || (version > DRW::AC1018 && currentDwgBit(sBuf) > stringEndBit)) | |||
| 8662 | return fail(); | |||
| 8663 | *buf = bodyProbe; | |||
| 8664 | if (!isEnd) | |||
| 8665 | name = std::move(parsedName); | |||
| 8666 | return true; | |||
| 8667 | } | |||
| 8668 | ||||
| 8669 | bool DRW_Insert::parseCode(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 8670 | switch (code) { | |||
| 8671 | case 2: | |||
| 8672 | name = reader->getUtf8String(); | |||
| 8673 | break; | |||
| 8674 | case 41: | |||
| 8675 | xscale = reader->getDouble(); | |||
| 8676 | break; | |||
| 8677 | case 42: | |||
| 8678 | yscale = reader->getDouble(); | |||
| 8679 | break; | |||
| 8680 | case 43: | |||
| 8681 | zscale = reader->getDouble(); | |||
| 8682 | break; | |||
| 8683 | case 50: | |||
| 8684 | angle = reader->getDouble(); | |||
| 8685 | angle = angle/ARAD57.29577951308232; //convert to radian | |||
| 8686 | break; | |||
| 8687 | case 70: { | |||
| 8688 | int value = 0; | |||
| 8689 | if (!readDxfIntInRange(reader, 0, kMaxMInsertCount, value)) | |||
| 8690 | return false; | |||
| 8691 | colcount = value; | |||
| 8692 | break; | |||
| 8693 | } | |||
| 8694 | case 71: { | |||
| 8695 | int value = 0; | |||
| 8696 | if (!readDxfIntInRange(reader, 0, kMaxMInsertCount, value)) | |||
| 8697 | return false; | |||
| 8698 | rowcount = value; | |||
| 8699 | break; | |||
| 8700 | } | |||
| 8701 | case 44: | |||
| 8702 | colspace = reader->getDouble(); | |||
| 8703 | break; | |||
| 8704 | case 45: | |||
| 8705 | rowspace = reader->getDouble(); | |||
| 8706 | break; | |||
| 8707 | default: | |||
| 8708 | return DRW_Point::parseCode(code, reader); | |||
| 8709 | } | |||
| 8710 | ||||
| 8711 | return true; | |||
| 8712 | } | |||
| 8713 | ||||
| 8714 | bool DRW_Table::parseCode(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 8715 | auto ensureGrid = [this]() { | |||
| 8716 | if (m_dxfRowsExpected < 0 || m_dxfColumnsExpected < 0) | |||
| 8717 | return true; | |||
| 8718 | ||||
| 8719 | const std::uint32_t rows = static_cast<std::uint32_t>(m_dxfRowsExpected); | |||
| 8720 | const std::uint32_t columns = static_cast<std::uint32_t>(m_dxfColumnsExpected); | |||
| 8721 | if (rows > kMaxTableRows || columns > kMaxTableColumns | |||
| 8722 | || (columns != 0 && rows > kMaxTableCells / columns)) { | |||
| 8723 | return false; | |||
| 8724 | } | |||
| 8725 | ||||
| 8726 | if (m_content.m_columns.size() != columns) { | |||
| 8727 | m_content.m_columns.clear(); | |||
| 8728 | if (!DRW::reserve(m_content.m_columns, static_cast<int>(columns))) | |||
| 8729 | return false; | |||
| 8730 | if (!DRW::resize(m_content.m_columns, static_cast<int>(columns))) | |||
| 8731 | return false; | |||
| 8732 | m_dxfColumnWidthsRead = 0; | |||
| 8733 | } | |||
| 8734 | if (m_content.m_rows.size() != rows) { | |||
| 8735 | m_content.m_rows.clear(); | |||
| 8736 | if (!DRW::reserve(m_content.m_rows, static_cast<int>(rows))) | |||
| 8737 | return false; | |||
| 8738 | if (!DRW::resize(m_content.m_rows, static_cast<int>(rows))) | |||
| 8739 | return false; | |||
| 8740 | m_dxfRowHeightsRead = 0; | |||
| 8741 | } | |||
| 8742 | for (auto& row : m_content.m_rows) { | |||
| 8743 | if (!DRW::reserve(row.m_cells, static_cast<int>(columns))) | |||
| 8744 | return false; | |||
| 8745 | if (!DRW::resize(row.m_cells, static_cast<int>(columns))) | |||
| 8746 | return false; | |||
| 8747 | } | |||
| 8748 | ||||
| 8749 | m_hasSemanticContent = true; | |||
| 8750 | m_semanticContentComplete = true; | |||
| 8751 | return true; | |||
| 8752 | }; | |||
| 8753 | ||||
| 8754 | auto currentCell = [this]() -> DRW_TableCell* { | |||
| 8755 | if (m_dxfCurrentCell < 0 || m_content.m_columns.empty() | |||
| 8756 | || m_content.m_rows.empty()) { | |||
| 8757 | return nullptr; | |||
| 8758 | } | |||
| 8759 | ||||
| 8760 | const std::size_t columns = m_content.m_columns.size(); | |||
| 8761 | const std::size_t cell = static_cast<std::size_t>(m_dxfCurrentCell); | |||
| 8762 | const std::size_t row = cell / columns; | |||
| 8763 | const std::size_t column = cell % columns; | |||
| 8764 | if (row >= m_content.m_rows.size() | |||
| 8765 | || column >= m_content.m_rows[row].m_cells.size()) { | |||
| 8766 | return nullptr; | |||
| 8767 | } | |||
| 8768 | return &m_content.m_rows[row].m_cells[column]; | |||
| 8769 | }; | |||
| 8770 | ||||
| 8771 | auto currentContent = [¤tCell]() -> DRW_TableCellContent* { | |||
| 8772 | DRW_TableCell *cell = currentCell(); | |||
| 8773 | if (cell == nullptr) | |||
| 8774 | return nullptr; | |||
| 8775 | if (cell->m_contents.empty() || cell->m_contents.back().m_type != 1) { | |||
| 8776 | DRW_TableCellContent content; | |||
| 8777 | content.m_type = 1; | |||
| 8778 | cell->m_contents.push_back(content); | |||
| 8779 | } | |||
| 8780 | return &cell->m_contents.back(); | |||
| 8781 | }; | |||
| 8782 | ||||
| 8783 | if (code == 100) { | |||
| 8784 | const std::string subclass = reader->getString(); | |||
| 8785 | if (subclass == "AcDbBlockReference") { | |||
| 8786 | m_dxfSubclass = DxfSubclass::BlockReference; | |||
| 8787 | } else if (subclass == "AcDbTable") { | |||
| 8788 | m_dxfSubclass = DxfSubclass::Table; | |||
| 8789 | } else if (subclass == "AcDbEntity") { | |||
| 8790 | m_dxfSubclass = DxfSubclass::Entity; | |||
| 8791 | } | |||
| 8792 | return true; | |||
| 8793 | } | |||
| 8794 | ||||
| 8795 | if (m_dxfSubclass != DxfSubclass::Table) | |||
| 8796 | return DRW_Insert::parseCode(code, reader); | |||
| 8797 | ||||
| 8798 | // A cell value's point, double, date and object-id groups reuse codes the | |||
| 8799 | // table itself and its proxy graphics own; only the displayed text is kept. | |||
| 8800 | if (m_dxfInCellValue | |||
| 8801 | && (code == 11 || code == 21 || code == 31 || code == 140 | |||
| 8802 | || code == 310 || code == 330)) { | |||
| 8803 | return true; | |||
| 8804 | } | |||
| 8805 | ||||
| 8806 | switch (code) { | |||
| 8807 | case 342: | |||
| 8808 | m_tableStyleHandle = static_cast<std::uint32_t>(reader->getHandleString()); | |||
| 8809 | m_content.m_tableStyleHandle = m_tableStyleHandle; | |||
| 8810 | break; | |||
| 8811 | case 343: | |||
| 8812 | reader->getHandleString(); | |||
| 8813 | break; | |||
| 8814 | case 11: | |||
| 8815 | m_horizontalDirection.x = reader->getDouble(); | |||
| 8816 | break; | |||
| 8817 | case 21: | |||
| 8818 | m_horizontalDirection.y = reader->getDouble(); | |||
| 8819 | break; | |||
| 8820 | case 31: | |||
| 8821 | m_horizontalDirection.z = reader->getDouble(); | |||
| 8822 | break; | |||
| 8823 | case 90: | |||
| 8824 | if (m_dxfInCellValue) { | |||
| 8825 | if (DRW_TableCellContent *content = currentContent()) | |||
| 8826 | content->m_value.m_dataType = reader->getInt32(); | |||
| 8827 | else | |||
| 8828 | reader->getInt32(); | |||
| 8829 | } else { | |||
| 8830 | m_valueFlag = reader->getInt32(); | |||
| 8831 | } | |||
| 8832 | break; | |||
| 8833 | case 91: | |||
| 8834 | if (m_dxfRowsExpected < 0 && !m_dxfInCellValue) { | |||
| 8835 | int value = 0; | |||
| 8836 | if (!readDxfIntInRange(reader, 0, | |||
| 8837 | static_cast<int>(kMaxTableRows), value)) | |||
| 8838 | return false; | |||
| 8839 | m_dxfRowsExpected = value; | |||
| 8840 | if (!ensureGrid()) | |||
| 8841 | return false; | |||
| 8842 | } else { | |||
| 8843 | reader->getInt32(); | |||
| 8844 | } | |||
| 8845 | break; | |||
| 8846 | case 92: | |||
| 8847 | if (m_dxfColumnsExpected < 0 && !m_dxfInCellValue) { | |||
| 8848 | int value = 0; | |||
| 8849 | if (!readDxfIntInRange(reader, 0, | |||
| 8850 | static_cast<int>(kMaxTableColumns), value)) | |||
| 8851 | return false; | |||
| 8852 | m_dxfColumnsExpected = value; | |||
| 8853 | if (!ensureGrid()) | |||
| 8854 | return false; | |||
| 8855 | } else { | |||
| 8856 | reader->getInt32(); | |||
| 8857 | } | |||
| 8858 | break; | |||
| 8859 | case 93: | |||
| 8860 | case 94: | |||
| 8861 | case 95: | |||
| 8862 | case 96: | |||
| 8863 | case 172: | |||
| 8864 | case 173: | |||
| 8865 | case 174: | |||
| 8866 | case 175: | |||
| 8867 | case 176: | |||
| 8868 | case 178: | |||
| 8869 | reader->getInt32(); | |||
| 8870 | break; | |||
| 8871 | case 141: | |||
| 8872 | if (!ensureGrid()) | |||
| 8873 | return false; | |||
| 8874 | if (m_dxfRowHeightsRead < m_content.m_rows.size()) | |||
| 8875 | m_content.m_rows[m_dxfRowHeightsRead++].m_height = reader->getDouble(); | |||
| 8876 | else | |||
| 8877 | reader->getDouble(); | |||
| 8878 | break; | |||
| 8879 | case 142: | |||
| 8880 | if (!ensureGrid()) | |||
| 8881 | return false; | |||
| 8882 | if (m_dxfColumnWidthsRead < m_content.m_columns.size()) | |||
| 8883 | m_content.m_columns[m_dxfColumnWidthsRead++].m_width = reader->getDouble(); | |||
| 8884 | else | |||
| 8885 | reader->getDouble(); | |||
| 8886 | break; | |||
| 8887 | case 145: | |||
| 8888 | reader->getDouble(); | |||
| 8889 | break; | |||
| 8890 | case 171: | |||
| 8891 | if (!ensureGrid()) | |||
| 8892 | return false; | |||
| 8893 | if (!m_content.m_rows.empty() && !m_content.m_columns.empty() | |||
| 8894 | && m_dxfNextCell < m_content.m_rows.size() * m_content.m_columns.size()) { | |||
| 8895 | m_dxfCurrentCell = static_cast<int>(m_dxfNextCell++); | |||
| 8896 | if (DRW_TableCell *cell = currentCell()) | |||
| 8897 | cell->m_flags = reader->getInt32(); | |||
| 8898 | else | |||
| 8899 | reader->getInt32(); | |||
| 8900 | } else { | |||
| 8901 | m_dxfCurrentCell = -1; | |||
| 8902 | reader->getInt32(); | |||
| 8903 | } | |||
| 8904 | m_dxfInCellValue = false; | |||
| 8905 | break; | |||
| 8906 | case 301: | |||
| 8907 | m_dxfInCellValue = reader->getString() == "CELL_VALUE"; | |||
| 8908 | if (m_dxfInCellValue) | |||
| 8909 | currentContent(); | |||
| 8910 | break; | |||
| 8911 | case 1: | |||
| 8912 | case 302: { | |||
| 8913 | const UTF8STRINGstd::string text = reader->getUtf8String(); | |||
| 8914 | if (m_dxfInCellValue) { | |||
| 8915 | if (DRW_TableCellContent *content = currentContent()) { | |||
| 8916 | content->m_text = text; | |||
| 8917 | content->m_value.m_dataType = 4; | |||
| 8918 | content->m_value.m_value.addString(1, text); | |||
| 8919 | } | |||
| 8920 | } | |||
| 8921 | break; | |||
| 8922 | } | |||
| 8923 | case 300: | |||
| 8924 | if (m_dxfInCellValue) { | |||
| 8925 | if (DRW_TableCellContent *content = currentContent()) | |||
| 8926 | content->m_value.m_valueString = reader->getUtf8String(); | |||
| 8927 | else | |||
| 8928 | reader->getUtf8String(); | |||
| 8929 | } else { | |||
| 8930 | reader->getUtf8String(); | |||
| 8931 | } | |||
| 8932 | break; | |||
| 8933 | case 304: | |||
| 8934 | reader->getString(); | |||
| 8935 | m_dxfInCellValue = false; | |||
| 8936 | break; | |||
| 8937 | default: | |||
| 8938 | return DRW_Entity::parseCode(code, reader); | |||
| 8939 | } | |||
| 8940 | ||||
| 8941 | return true; | |||
| 8942 | } | |||
| 8943 | ||||
| 8944 | void DRW_Insert::resetDwgState() { | |||
| 8945 | DRW_Point::resetDwgState(); | |||
| 8946 | name.clear(); | |||
| 8947 | xscale = yscale = zscale = 1.0; | |||
| 8948 | angle = 0.0; | |||
| 8949 | colcount = rowcount = 1; | |||
| 8950 | colspace = rowspace = 0.0; | |||
| 8951 | attlist.clear(); | |||
| 8952 | blockRecH = dwgHandle{}; | |||
| 8953 | seqendH = dwgHandle{}; | |||
| 8954 | attribHandles.clear(); | |||
| 8955 | } | |||
| 8956 | ||||
| 8957 | bool DRW_Insert::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){ | |||
| 8958 | resetDwgState(); | |||
| 8959 | dwgBuffer *sourceBuf = buf; | |||
| 8960 | auto fail = [this, sourceBuf]() { | |||
| 8961 | if (sourceBuf != nullptr) | |||
| 8962 | sourceBuf->invalidate(); | |||
| 8963 | resetDwgState(); | |||
| 8964 | return false; | |||
| 8965 | }; | |||
| 8966 | if (sourceBuf == nullptr) | |||
| 8967 | return fail(); | |||
| 8968 | ||||
| 8969 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 8970 | buf = &bodyProbe; | |||
| 8971 | if (!DRW_Entity::parseDwgCommon(version, buf, bs) | |||
| 8972 | || !bodyProbe.isGood()) | |||
| 8973 | return fail(); | |||
| 8974 | ||||
| 8975 | std::int32_t objCount = 0; | |||
| 8976 | std::vector<dwgHandle> parsedAttribHandles; | |||
| 8977 | DRW_DBG("\n************************** parsing insert/minsert *****************************************\n")DRW_dbg::dbg("\n************************** parsing insert/minsert *****************************************\n" ); | |||
| 8978 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 8979 | DRW_Coord parsedBasePoint; | |||
| 8980 | DRW_Coord parsedExtPoint; | |||
| 8981 | double parsedXScale = 1.0; | |||
| 8982 | double parsedYScale = 1.0; | |||
| 8983 | double parsedZScale = 1.0; | |||
| 8984 | double parsedAngle = 0.0; | |||
| 8985 | bool hasAttrib = false; | |||
| 8986 | ||||
| 8987 | if (!readBoundedBitCoord(*buf, bodyEndBit, parsedBasePoint)) | |||
| 8988 | return fail(); | |||
| 8989 | DRW_DBG("insertion point: ")DRW_dbg::dbg("insertion point: "); | |||
| 8990 | DRW_DBGPT(parsedBasePoint.x, parsedBasePoint.y, parsedBasePoint.z)DRW_dbg::dbgPT(parsedBasePoint.x, parsedBasePoint.y, parsedBasePoint .z); | |||
| 8991 | DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 8992 | if (version < DRW::AC1015) {//14- | |||
| 8993 | if (!readBoundedBitDouble(*buf, bodyEndBit, parsedXScale) | |||
| 8994 | || !readBoundedBitDouble(*buf, bodyEndBit, parsedYScale) | |||
| 8995 | || !readBoundedBitDouble(*buf, bodyEndBit, parsedZScale)) | |||
| 8996 | return fail(); | |||
| 8997 | } else { | |||
| 8998 | if (!proxyEntityHasBits(*buf, bodyEndBit, 2)) | |||
| 8999 | return fail(); | |||
| 9000 | const std::uint8_t dataFlags = buf->get2Bits(); | |||
| 9001 | if (!buf->isGood()) | |||
| 9002 | return fail(); | |||
| 9003 | if (dataFlags == 3) { | |||
| 9004 | //none default value 1,1,1 | |||
| 9005 | } else if (dataFlags == 1) { //x default value 1, y & z use DD(1) | |||
| 9006 | if (!readBoundedDefaultDouble(*buf, bodyEndBit, 1.0, | |||
| 9007 | parsedYScale) | |||
| 9008 | || !readBoundedDefaultDouble(*buf, bodyEndBit, 1.0, | |||
| 9009 | parsedZScale)) | |||
| 9010 | return fail(); | |||
| 9011 | } else if (dataFlags == 2) { | |||
| 9012 | if (!readBoundedRawDouble(*buf, bodyEndBit, parsedXScale)) | |||
| 9013 | return fail(); | |||
| 9014 | parsedYScale = parsedZScale = parsedXScale; | |||
| 9015 | } else { //dataFlags == 0 | |||
| 9016 | if (!readBoundedRawDouble(*buf, bodyEndBit, parsedXScale) | |||
| 9017 | || !readBoundedDefaultDouble(*buf, bodyEndBit, parsedXScale, | |||
| 9018 | parsedYScale) | |||
| 9019 | || !readBoundedDefaultDouble(*buf, bodyEndBit, parsedXScale, | |||
| 9020 | parsedZScale)) | |||
| 9021 | return fail(); | |||
| 9022 | } | |||
| 9023 | } | |||
| 9024 | if (!readBoundedBitDouble(*buf, bodyEndBit, parsedAngle) | |||
| 9025 | || !readBoundedExtrusion(*buf, bodyEndBit, false, parsedExtPoint) | |||
| 9026 | || !readBoundedBit(*buf, bodyEndBit, hasAttrib)) | |||
| 9027 | return fail(); | |||
| 9028 | DRW_DBG("scale : ")DRW_dbg::dbg("scale : "); | |||
| 9029 | DRW_DBGPT(parsedXScale, parsedYScale, parsedZScale)DRW_dbg::dbgPT(parsedXScale, parsedYScale, parsedZScale); | |||
| 9030 | DRW_DBG(", angle: ")DRW_dbg::dbg(", angle: "); DRW_DBG(parsedAngle)DRW_dbg::dbg(parsedAngle); | |||
| 9031 | DRW_DBG("\nextrusion: ")DRW_dbg::dbg("\nextrusion: "); | |||
| 9032 | DRW_DBGPT(parsedExtPoint.x, parsedExtPoint.y, parsedExtPoint.z)DRW_dbg::dbgPT(parsedExtPoint.x, parsedExtPoint.y, parsedExtPoint .z); | |||
| 9033 | ||||
| 9034 | DRW_DBG(" has Attrib: ")DRW_dbg::dbg(" has Attrib: "); DRW_DBG(hasAttrib)DRW_dbg::dbg(hasAttrib); | |||
| 9035 | ||||
| 9036 | if (hasAttrib && version > DRW::AC1015) {//2004+ | |||
| 9037 | if (!readBoundedBitLong(*buf, bodyEndBit, objCount) | |||
| 9038 | || !dwgSafety::validOwnedObjectCount( | |||
| 9039 | objCount, buf->numRemainingBytes())) { | |||
| 9040 | DRW_DBG("\nWARNING: Invalid INSERT owned-attribute count\n")DRW_dbg::dbg("\nWARNING: Invalid INSERT owned-attribute count\n" ); | |||
| 9041 | return fail(); | |||
| 9042 | } | |||
| 9043 | DRW_DBG(" objCount: ")DRW_dbg::dbg(" objCount: "); DRW_DBG(objCount)DRW_dbg::dbg(objCount); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 9044 | } | |||
| 9045 | int parsedColCount = 1; | |||
| 9046 | int parsedRowCount = 1; | |||
| 9047 | double parsedColSpace = 0.0; | |||
| 9048 | double parsedRowSpace = 0.0; | |||
| 9049 | if (oType == 8) {//entity are minsert | |||
| 9050 | std::uint16_t colCount = 0; | |||
| 9051 | std::uint16_t rowCount = 0; | |||
| 9052 | if (!readBoundedBitShort(*buf, bodyEndBit, colCount) | |||
| 9053 | || !readBoundedBitShort(*buf, bodyEndBit, rowCount) | |||
| 9054 | || !readBoundedBitDouble(*buf, bodyEndBit, parsedColSpace) | |||
| 9055 | || !readBoundedBitDouble(*buf, bodyEndBit, parsedRowSpace)) | |||
| 9056 | return fail(); | |||
| 9057 | parsedColCount = static_cast<int>(colCount); | |||
| 9058 | parsedRowCount = static_cast<int>(rowCount); | |||
| 9059 | } | |||
| 9060 | const auto finite = [](const DRW_Coord& point) { | |||
| 9061 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 9062 | && std::isfinite(point.z); | |||
| 9063 | }; | |||
| 9064 | if (!finite(parsedBasePoint) || !finite(parsedExtPoint) | |||
| 9065 | || !std::isfinite(parsedXScale) || !std::isfinite(parsedYScale) | |||
| 9066 | || !std::isfinite(parsedZScale) || !std::isfinite(parsedAngle) | |||
| 9067 | || !std::isfinite(parsedColSpace) || !std::isfinite(parsedRowSpace)) | |||
| 9068 | return fail(); | |||
| 9069 | DRW_DBG(" Remaining bytes: ")DRW_dbg::dbg(" Remaining bytes: "); DRW_DBG(buf->numRemainingBytes())DRW_dbg::dbg(buf->numRemainingBytes()); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 9070 | std::uint64_t handleEndBit = 0; | |||
| 9071 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, | |||
| 9072 | handleEndBit)) | |||
| 9073 | return fail(); | |||
| 9074 | dwgBuffer handleProbe = buf->forkIndependent(); | |||
| 9075 | if (!DRW_Entity::parseDwgEntHandle(version, &handleProbe, true, | |||
| 9076 | handleEndBit)) | |||
| 9077 | return fail(); | |||
| 9078 | dwgHandle parsedBlockRecH; | |||
| 9079 | if (!readBoundedDwgHandle(handleProbe, handleEndBit, 0, false, | |||
| 9080 | parsedBlockRecH)) | |||
| 9081 | return fail(); | |||
| 9082 | dwgHandle parsedSeqendH; | |||
| 9083 | DRW_DBG("BLOCK HEADER Handle: ")DRW_dbg::dbg("BLOCK HEADER Handle: "); DRW_DBGHL(parsedBlockRecH.code, parsedBlockRecH.size, parsedBlockRecH.ref)DRW_dbg::dbgHL(parsedBlockRecH.code, parsedBlockRecH.size, parsedBlockRecH .ref); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 9084 | DRW_DBG(" Remaining bytes: ")DRW_dbg::dbg(" Remaining bytes: "); DRW_DBG(handleProbe.numRemainingBytes())DRW_dbg::dbg(handleProbe.numRemainingBytes()); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 9085 | ||||
| 9086 | /*attribs follows*/ | |||
| 9087 | if (hasAttrib) { | |||
| 9088 | const std::int32_t expectedCount = | |||
| 9089 | version < DRW::AC1018 ? 2 : objCount; | |||
| 9090 | if (!DRW::reserve(parsedAttribHandles, expectedCount)) | |||
| 9091 | return fail(); | |||
| 9092 | if (version < DRW::AC1018) {//2000- | |||
| 9093 | dwgHandle attH; | |||
| 9094 | if (!readBoundedDwgHandle(handleProbe, handleEndBit, 0, false, | |||
| 9095 | attH)) | |||
| 9096 | return fail(); | |||
| 9097 | DRW_DBG("first attrib Handle: ")DRW_dbg::dbg("first attrib Handle: "); DRW_DBGHL(attH.code, attH.size, attH.ref)DRW_dbg::dbgHL(attH.code, attH.size, attH.ref); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 9098 | parsedAttribHandles.push_back(attH); | |||
| 9099 | if (!readBoundedDwgHandle(handleProbe, handleEndBit, 0, false, | |||
| 9100 | attH)) | |||
| 9101 | return fail(); | |||
| 9102 | DRW_DBG("second attrib Handle: ")DRW_dbg::dbg("second attrib Handle: "); DRW_DBGHL(attH.code, attH.size, attH.ref)DRW_dbg::dbgHL(attH.code, attH.size, attH.ref); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 9103 | parsedAttribHandles.push_back(attH); | |||
| 9104 | } else { | |||
| 9105 | for (std::int32_t i=0; i < objCount; ++i){ | |||
| 9106 | dwgHandle attH; | |||
| 9107 | if (!readBoundedDwgHandle(handleProbe, handleEndBit, 0, | |||
| 9108 | false, attH)) | |||
| 9109 | return fail(); | |||
| 9110 | DRW_DBG("attrib Handle #")DRW_dbg::dbg("attrib Handle #"); DRW_DBG(i)DRW_dbg::dbg(i); DRW_DBG(": ")DRW_dbg::dbg(": "); DRW_DBGHL(attH.code, attH.size, attH.ref)DRW_dbg::dbgHL(attH.code, attH.size, attH.ref); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 9111 | parsedAttribHandles.push_back(attH); | |||
| 9112 | } | |||
| 9113 | } | |||
| 9114 | if (!readBoundedDwgHandle(handleProbe, handleEndBit, 0, false, | |||
| 9115 | parsedSeqendH)) | |||
| 9116 | return fail(); | |||
| 9117 | DRW_DBG("seqendH Handle: ")DRW_dbg::dbg("seqendH Handle: "); DRW_DBGHL(parsedSeqendH.code, parsedSeqendH.size, parsedSeqendH.ref)DRW_dbg::dbgHL(parsedSeqendH.code, parsedSeqendH.size, parsedSeqendH .ref); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 9118 | } | |||
| 9119 | DRW_DBG(" Remaining bytes: ")DRW_dbg::dbg(" Remaining bytes: "); DRW_DBG(handleProbe.numRemainingBytes())DRW_dbg::dbg(handleProbe.numRemainingBytes()); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 9120 | ||||
| 9121 | if (!handleProbe.isGood()) | |||
| 9122 | return fail(); | |||
| 9123 | *sourceBuf = handleProbe; | |||
| 9124 | basePoint = parsedBasePoint; | |||
| 9125 | xscale = parsedXScale; | |||
| 9126 | yscale = parsedYScale; | |||
| 9127 | zscale = parsedZScale; | |||
| 9128 | angle = parsedAngle; | |||
| 9129 | extPoint = parsedExtPoint; | |||
| 9130 | colcount = parsedColCount; | |||
| 9131 | rowcount = parsedRowCount; | |||
| 9132 | colspace = parsedColSpace; | |||
| 9133 | rowspace = parsedRowSpace; | |||
| 9134 | blockRecH = parsedBlockRecH; | |||
| 9135 | seqendH = parsedSeqendH; | |||
| 9136 | attribHandles = std::move(parsedAttribHandles); | |||
| 9137 | // RS crc; //RS */ | |||
| 9138 | return true; | |||
| 9139 | } | |||
| 9140 | ||||
| 9141 | void DRW_Table::resetDwgState() { | |||
| 9142 | DRW_Insert::resetDwgState(); | |||
| 9143 | name.clear(); | |||
| 9144 | xscale = yscale = zscale = 1.0; | |||
| 9145 | angle = 0.0; | |||
| 9146 | colcount = rowcount = 1; | |||
| 9147 | colspace = rowspace = 0.0; | |||
| 9148 | m_valueFlag = 0; | |||
| 9149 | m_horizontalDirection = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 9150 | m_hasSemanticContent = false; | |||
| 9151 | m_semanticContentComplete = false; | |||
| 9152 | m_tableStyleHandle = 0; | |||
| 9153 | m_content = DRW_TableContent{}; | |||
| 9154 | m_dxfSubclass = DxfSubclass::Entity; | |||
| 9155 | m_dxfRowsExpected = -1; | |||
| 9156 | m_dxfColumnsExpected = -1; | |||
| 9157 | m_dxfRowHeightsRead = 0; | |||
| 9158 | m_dxfColumnWidthsRead = 0; | |||
| 9159 | m_dxfNextCell = 0; | |||
| 9160 | m_dxfCurrentCell = -1; | |||
| 9161 | m_dxfInCellValue = false; | |||
| 9162 | } | |||
| 9163 | ||||
| 9164 | bool DRW_Table::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){ | |||
| 9165 | resetDwgState(); | |||
| 9166 | auto fail = [this, buf]() { | |||
| 9167 | if (buf != nullptr) | |||
| 9168 | buf->invalidate(); | |||
| 9169 | resetDwgState(); | |||
| 9170 | return false; | |||
| 9171 | }; | |||
| 9172 | if (buf == nullptr || version < DRW::AC1015) | |||
| 9173 | return fail(); | |||
| 9174 | ||||
| 9175 | dwgBuffer *sourceBuf = buf; | |||
| 9176 | dwgBuffer bodyProbe = buf->forkIndependent(); | |||
| 9177 | buf = &bodyProbe; | |||
| 9178 | auto commit = [&]() { | |||
| 9179 | *sourceBuf = bodyProbe; | |||
| 9180 | return true; | |||
| 9181 | }; | |||
| 9182 | ||||
| 9183 | dwgBuffer sBuff = bodyProbe.forkIndependent(); | |||
| 9184 | sBuff.setVariableTextByteLength(true); | |||
| 9185 | dwgBuffer *sBuf = &sBuff; | |||
| 9186 | bool ret = DRW_Entity::parseDwg(version, buf, sBuf, bs); | |||
| 9187 | if (!ret) | |||
| 9188 | return fail(); | |||
| 9189 | ||||
| 9190 | DRW_DBG("\n************************** parsing table *****************************************\n")DRW_dbg::dbg("\n************************** parsing table *****************************************\n" ); | |||
| 9191 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 9192 | DRW_Coord parsedBasePoint; | |||
| 9193 | std::uint8_t dataFlags = 0; | |||
| 9194 | if (!readBoundedBitCoord(*buf, bodyEndBit, parsedBasePoint) | |||
| 9195 | || !proxyEntityHasBits(*buf, bodyEndBit, 2)) | |||
| 9196 | return fail(); | |||
| 9197 | dataFlags = buf->get2Bits(); | |||
| 9198 | if (!buf->isGood()) | |||
| 9199 | return fail(); | |||
| 9200 | ||||
| 9201 | double parsedXScale = 1.0; | |||
| 9202 | double parsedYScale = 1.0; | |||
| 9203 | double parsedZScale = 1.0; | |||
| 9204 | if (dataFlags == 3) { | |||
| 9205 | // default scale 1,1,1 | |||
| 9206 | } else if (dataFlags == 1) { | |||
| 9207 | if (!readBoundedDefaultDouble(*buf, bodyEndBit, parsedXScale, | |||
| 9208 | parsedYScale) | |||
| 9209 | || !readBoundedDefaultDouble(*buf, bodyEndBit, parsedXScale, | |||
| 9210 | parsedZScale)) | |||
| 9211 | return fail(); | |||
| 9212 | } else if (dataFlags == 2) { | |||
| 9213 | if (!readBoundedRawDouble(*buf, bodyEndBit, parsedXScale)) | |||
| 9214 | return fail(); | |||
| 9215 | parsedYScale = parsedZScale = parsedXScale; | |||
| 9216 | } else { | |||
| 9217 | if (!readBoundedRawDouble(*buf, bodyEndBit, parsedXScale) | |||
| 9218 | || !readBoundedDefaultDouble(*buf, bodyEndBit, parsedXScale, | |||
| 9219 | parsedYScale) | |||
| 9220 | || !readBoundedDefaultDouble(*buf, bodyEndBit, parsedXScale, | |||
| 9221 | parsedZScale)) | |||
| 9222 | return fail(); | |||
| 9223 | } | |||
| 9224 | ||||
| 9225 | double parsedAngle = 0.0; | |||
| 9226 | DRW_Coord parsedExtPoint; | |||
| 9227 | if (!readBoundedBitDouble(*buf, bodyEndBit, parsedAngle) | |||
| 9228 | || !readBoundedExtrusion(*buf, bodyEndBit, false, parsedExtPoint)) | |||
| 9229 | return fail(); | |||
| 9230 | ||||
| 9231 | if (!sBuf->isGood()) | |||
| 9232 | return fail(); | |||
| 9233 | ||||
| 9234 | std::int32_t objCount = 0; | |||
| 9235 | bool hasAttrib = false; | |||
| 9236 | if (!readBoundedBit(*buf, bodyEndBit, hasAttrib)) | |||
| 9237 | return fail(); | |||
| 9238 | if (hasAttrib && version > DRW::AC1015) { | |||
| 9239 | if (!readBoundedBitLong(*buf, bodyEndBit, objCount) | |||
| 9240 | || !dwgSafety::validOwnedObjectCount( | |||
| 9241 | objCount, buf->numRemainingBytes())) { | |||
| 9242 | DRW_DBG("\nWARNING: Invalid TABLE owned-attribute count\n")DRW_dbg::dbg("\nWARNING: Invalid TABLE owned-attribute count\n" ); | |||
| 9243 | return fail(); | |||
| 9244 | } | |||
| 9245 | } | |||
| 9246 | ||||
| 9247 | std::uint64_t handleEndBit = 0; | |||
| 9248 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, | |||
| 9249 | handleEndBit)) | |||
| 9250 | return fail(); | |||
| 9251 | dwgBuffer hBuff = buf->forkIndependent(); | |||
| 9252 | if (version <= DRW::AC1018) { | |||
| 9253 | // R2000/R2004: parseDwgEntHandle only re-seeks to the handle stream | |||
| 9254 | // for version > AC1018 (2007+ string area). For the legacy versions | |||
| 9255 | // seek the snapshot to the handle-stream start (objSize is the | |||
| 9256 | // bit offset of the handle stream, RL field read in | |||
| 9257 | // DRW_Entity::parseDwg) or every handle below reads mid-DATA garbage. | |||
| 9258 | if (!hBuff.setPosition(objSize >> 3)) | |||
| 9259 | return fail(); | |||
| 9260 | hBuff.setBitPos(objSize & 7); | |||
| 9261 | } | |||
| 9262 | ret = DRW_Entity::parseDwgEntHandle(version, &hBuff, true, | |||
| 9263 | handleEndBit); | |||
| 9264 | if (!ret) | |||
| 9265 | return fail(); | |||
| 9266 | dwgHandle parsedBlockRecH; | |||
| 9267 | if (!readBoundedDwgHandle(hBuff, handleEndBit, 0, false, | |||
| 9268 | parsedBlockRecH)) | |||
| 9269 | return fail(); | |||
| 9270 | ||||
| 9271 | std::vector<dwgHandle> parsedAttribHandles; | |||
| 9272 | dwgHandle parsedSeqendH; | |||
| 9273 | ||||
| 9274 | if (hasAttrib) { | |||
| 9275 | if (!DRW::reserve(parsedAttribHandles, objCount)) | |||
| 9276 | return fail(); | |||
| 9277 | for (std::int32_t i = 0; i < objCount; ++i) { | |||
| 9278 | dwgHandle attribHandle; | |||
| 9279 | if (!readBoundedDwgHandle(hBuff, handleEndBit, 0, false, | |||
| 9280 | attribHandle)) | |||
| 9281 | return fail(); | |||
| 9282 | parsedAttribHandles.push_back(attribHandle); | |||
| 9283 | } | |||
| 9284 | if (!readBoundedDwgHandle(hBuff, handleEndBit, 0, false, | |||
| 9285 | parsedSeqendH)) | |||
| 9286 | return fail(); | |||
| 9287 | } | |||
| 9288 | ||||
| 9289 | if (!hBuff.isGood()) | |||
| 9290 | return fail(); | |||
| 9291 | ||||
| 9292 | blockRecH = parsedBlockRecH; | |||
| 9293 | seqendH = parsedSeqendH; | |||
| 9294 | attribHandles = std::move(parsedAttribHandles); | |||
| 9295 | basePoint = parsedBasePoint; | |||
| 9296 | xscale = parsedXScale; | |||
| 9297 | yscale = parsedYScale; | |||
| 9298 | zscale = parsedZScale; | |||
| 9299 | angle = parsedAngle; | |||
| 9300 | extPoint = parsedExtPoint; | |||
| 9301 | ||||
| 9302 | if (version >= DRW::AC1024) { | |||
| 9303 | std::uint8_t ignoredTableVersion = 0; | |||
| 9304 | if (!readBoundedRawChar8(*buf, bodyEndBit, ignoredTableVersion)) | |||
| 9305 | return fail(); | |||
| 9306 | dwgHandle parsedTableStyleHandle; | |||
| 9307 | if (!readBoundedDwgHandle(hBuff, handleEndBit, 0, false, | |||
| 9308 | parsedTableStyleHandle)) | |||
| 9309 | return fail(); | |||
| 9310 | const std::uint32_t tableStyleHandle = parsedTableStyleHandle.ref; | |||
| 9311 | std::int32_t ignoredContentFlag = 0; | |||
| 9312 | if (!readBoundedBitLong(*buf, bodyEndBit, ignoredContentFlag)) | |||
| 9313 | return fail(); | |||
| 9314 | if (version >= DRW::AC1027) { | |||
| 9315 | std::int32_t ignoredContentVersion = 0; | |||
| 9316 | if (!readBoundedBitLong(*buf, bodyEndBit, ignoredContentVersion)) | |||
| 9317 | return fail(); | |||
| 9318 | } else { | |||
| 9319 | bool ignoredContentBit = false; | |||
| 9320 | if (!readBoundedBit(*buf, bodyEndBit, ignoredContentBit)) | |||
| 9321 | return fail(); | |||
| 9322 | } | |||
| 9323 | ||||
| 9324 | if (!buf->isGood() || !hBuff.isGood()) | |||
| 9325 | return fail(); | |||
| 9326 | ||||
| 9327 | m_hasSemanticContent = true; | |||
| 9328 | // TABLECONTENT is an optional semantic tail. Decode it on independent | |||
| 9329 | // cursors so a newer/partially supported cell variant cannot poison the | |||
| 9330 | // already validated entity prefix and common handle stream. | |||
| 9331 | dwgBuffer contentBuf = buf->forkIndependent(); | |||
| 9332 | dwgBuffer contentStringBuf = sBuf->forkIndependent(); | |||
| 9333 | dwgBuffer contentHandleBuf = hBuff.forkIndependent(); | |||
| 9334 | TableDwgBounds tableBounds; | |||
| 9335 | tableBounds.bodyEndBit = tableBodyEndBit(version, sBuf, objSize); | |||
| 9336 | if (version > DRW::AC1021) { | |||
| 9337 | std::uint64_t stringStartBit = 0; | |||
| 9338 | if (!contentStringBuf.getR2007StringStreamBounds( | |||
| 9339 | objSize, stringStartBit, tableBounds.stringEndBit)) | |||
| 9340 | return fail(); | |||
| 9341 | } else { | |||
| 9342 | tableBounds.stringEndBit = proxyEntityEndBit(contentStringBuf, 0); | |||
| 9343 | } | |||
| 9344 | tableBounds.handleEndBit = handleEndBit; | |||
| 9345 | DRW_TableContent parsedContent; | |||
| 9346 | m_semanticContentComplete = parseTableContent( | |||
| 9347 | version, &contentBuf, &contentStringBuf, &contentHandleBuf, | |||
| 9348 | parsedContent, tableBounds); | |||
| 9349 | if (!m_semanticContentComplete || !contentBuf.isGood() | |||
| 9350 | || !contentStringBuf.isGood() || !contentHandleBuf.isGood()) { | |||
| 9351 | // The frame, entity prefix, and common handles remain valid. Keep | |||
| 9352 | // the typed table shell and allow the raw DWG frame to preserve | |||
| 9353 | // content that this reader does not yet model. | |||
| 9354 | m_semanticContentComplete = false; | |||
| 9355 | return commit(); | |||
| 9356 | } | |||
| 9357 | *buf = contentBuf; | |||
| 9358 | *sBuf = contentStringBuf; | |||
| 9359 | hBuff = contentHandleBuf; | |||
| 9360 | m_content = std::move(parsedContent); | |||
| 9361 | if (m_content.m_tableStyleHandle != 0) | |||
| 9362 | m_tableStyleHandle = m_content.m_tableStyleHandle; | |||
| 9363 | else | |||
| 9364 | m_tableStyleHandle = tableStyleHandle; | |||
| 9365 | if (!buf->isGood() || !sBuf->isGood() || !hBuff.isGood()) | |||
| 9366 | return fail(); | |||
| 9367 | if (!m_semanticContentComplete) { | |||
| 9368 | DRW_DBG("TABLECONTENT parse incomplete; anonymous block insert kept\n")DRW_dbg::dbg("TABLECONTENT parse incomplete; anonymous block insert kept\n" ); | |||
| 9369 | return commit(); | |||
| 9370 | } | |||
| 9371 | ||||
| 9372 | std::uint16_t ignoredTableFlags = 0; | |||
| 9373 | DRW_Coord parsedHorizontalDirection; | |||
| 9374 | if (!readBoundedBitShort(*buf, bodyEndBit, ignoredTableFlags) | |||
| 9375 | || !readBoundedBitCoord(*buf, bodyEndBit, | |||
| 9376 | parsedHorizontalDirection)) | |||
| 9377 | return fail(); | |||
| 9378 | m_horizontalDirection = parsedHorizontalDirection; | |||
| 9379 | ||||
| 9380 | const std::uint64_t breakStartBit = currentDwgBit(buf); | |||
| 9381 | std::int32_t breakDataFlag = 0; | |||
| 9382 | if (!readBoundedBitLong(*buf, bodyEndBit, breakDataFlag)) | |||
| 9383 | return fail(); | |||
| 9384 | const bool hasBreakData = breakDataFlag != 0; | |||
| 9385 | if (hasBreakData) { | |||
| 9386 | std::int32_t ignoredBreakType = 0; | |||
| 9387 | double ignoredBreakDistance = 0.0; | |||
| 9388 | std::int32_t manualPositionCount = 0; | |||
| 9389 | if (!readBoundedBitLong(*buf, bodyEndBit, ignoredBreakType) | |||
| 9390 | || !readBoundedBitLong(*buf, bodyEndBit, ignoredBreakType) | |||
| 9391 | || !readBoundedBitDouble(*buf, bodyEndBit, | |||
| 9392 | ignoredBreakDistance) | |||
| 9393 | || !readBoundedBitLong(*buf, bodyEndBit, ignoredBreakType) | |||
| 9394 | || !readBoundedBitLong(*buf, bodyEndBit, ignoredBreakType) | |||
| 9395 | || !readBoundedBitLong(*buf, bodyEndBit, | |||
| 9396 | manualPositionCount)) | |||
| 9397 | return fail(); | |||
| 9398 | if (manualPositionCount < 0 | |||
| 9399 | || static_cast<std::uint32_t>(manualPositionCount) | |||
| 9400 | > kMaxTableItems) { | |||
| 9401 | m_content.m_subrecordRanges.push_back(makeDwgSubrecordRange( | |||
| 9402 | "table-break-data", breakStartBit, currentDwgBit(buf), | |||
| 9403 | version, manualPositionCount, false)); | |||
| 9404 | return commit(); | |||
| 9405 | } | |||
| 9406 | for (std::int32_t i = 0; i < manualPositionCount; ++i) { | |||
| 9407 | DRW_Coord ignoredPosition; | |||
| 9408 | double ignoredRotation = 0.0; | |||
| 9409 | std::int32_t ignoredPositionType = 0; | |||
| 9410 | if (!readBoundedBitCoord(*buf, bodyEndBit, | |||
| 9411 | ignoredPosition) | |||
| 9412 | || !readBoundedBitDouble(*buf, bodyEndBit, | |||
| 9413 | ignoredRotation) | |||
| 9414 | || !readBoundedBitLong(*buf, bodyEndBit, | |||
| 9415 | ignoredPositionType)) | |||
| 9416 | return fail(); | |||
| 9417 | } | |||
| 9418 | m_content.m_subrecordRanges.push_back(makeDwgSubrecordRange( | |||
| 9419 | "table-break-data", breakStartBit, currentDwgBit(buf), | |||
| 9420 | version, static_cast<std::uint32_t>(manualPositionCount), | |||
| 9421 | buf->isGood())); | |||
| 9422 | } | |||
| 9423 | ||||
| 9424 | const std::uint64_t rowRangeStartBit = currentDwgBit(buf); | |||
| 9425 | std::int32_t rowRangeCount = 0; | |||
| 9426 | if (!readBoundedBitLong(*buf, bodyEndBit, rowRangeCount)) | |||
| 9427 | return fail(); | |||
| 9428 | if (rowRangeCount >= 0 | |||
| 9429 | && static_cast<std::uint32_t>(rowRangeCount) <= kMaxTableItems) { | |||
| 9430 | for (std::int32_t i = 0; i < rowRangeCount; ++i) { | |||
| 9431 | DRW_Coord ignoredRangePoint; | |||
| 9432 | std::int32_t ignoredRangeValue = 0; | |||
| 9433 | if (!readBoundedBitCoord(*buf, bodyEndBit, | |||
| 9434 | ignoredRangePoint) | |||
| 9435 | || !readBoundedBitLong(*buf, bodyEndBit, | |||
| 9436 | ignoredRangeValue) | |||
| 9437 | || !readBoundedBitLong(*buf, bodyEndBit, | |||
| 9438 | ignoredRangeValue)) | |||
| 9439 | return fail(); | |||
| 9440 | } | |||
| 9441 | if (rowRangeCount != 0) { | |||
| 9442 | m_content.m_subrecordRanges.push_back(makeDwgSubrecordRange( | |||
| 9443 | "table-row-ranges", rowRangeStartBit, currentDwgBit(buf), | |||
| 9444 | version, static_cast<std::uint32_t>(rowRangeCount), | |||
| 9445 | buf->isGood())); | |||
| 9446 | } | |||
| 9447 | } else { | |||
| 9448 | m_content.m_subrecordRanges.push_back(makeDwgSubrecordRange( | |||
| 9449 | "table-row-ranges", rowRangeStartBit, currentDwgBit(buf), | |||
| 9450 | version, rowRangeCount, false)); | |||
| 9451 | } | |||
| 9452 | ||||
| 9453 | if (!buf->isGood() || !sBuf->isGood() || !hBuff.isGood()) | |||
| 9454 | return fail(); | |||
| 9455 | return commit(); | |||
| 9456 | } | |||
| 9457 | ||||
| 9458 | std::uint16_t parsedValueFlag = 0; | |||
| 9459 | DRW_Coord parsedHorizontalDirection; | |||
| 9460 | std::int32_t parsedColumnCount = 0; | |||
| 9461 | std::int32_t parsedRowCount = 0; | |||
| 9462 | if (!readBoundedBitShort(*buf, bodyEndBit, parsedValueFlag) | |||
| 9463 | || !readBoundedBitCoord(*buf, bodyEndBit, | |||
| 9464 | parsedHorizontalDirection) | |||
| 9465 | || !readBoundedBitLong(*buf, bodyEndBit, parsedColumnCount) | |||
| 9466 | || !readBoundedBitLong(*buf, bodyEndBit, parsedRowCount) | |||
| 9467 | || parsedColumnCount < 0 || parsedRowCount < 0) | |||
| 9468 | return fail(); | |||
| 9469 | const std::uint32_t columns = static_cast<std::uint32_t>(parsedColumnCount); | |||
| 9470 | const std::uint32_t rows = static_cast<std::uint32_t>(parsedRowCount); | |||
| 9471 | if (columns > kMaxTableColumns || rows > kMaxTableRows | |||
| 9472 | || (columns != 0 && rows > kMaxTableCells / columns)) { | |||
| 9473 | return fail(); | |||
| 9474 | } | |||
| 9475 | ||||
| 9476 | m_hasSemanticContent = true; | |||
| 9477 | m_semanticContentComplete = false; | |||
| 9478 | m_content.m_columns.clear(); | |||
| 9479 | m_content.m_rows.clear(); | |||
| 9480 | if (!DRW::reserve(m_content.m_columns, static_cast<int>(columns)) | |||
| 9481 | || !DRW::reserve(m_content.m_rows, static_cast<int>(rows))) | |||
| 9482 | return fail(); | |||
| 9483 | for (std::uint32_t i = 0; i < columns; ++i) { | |||
| 9484 | DRW_TableColumn column; | |||
| 9485 | if (!readBoundedBitDouble(*buf, bodyEndBit, column.m_width)) | |||
| 9486 | return fail(); | |||
| 9487 | m_content.m_columns.push_back(column); | |||
| 9488 | } | |||
| 9489 | for (std::uint32_t i = 0; i < rows; ++i) { | |||
| 9490 | DRW_TableRow row; | |||
| 9491 | if (!readBoundedBitDouble(*buf, bodyEndBit, row.m_height)) | |||
| 9492 | return fail(); | |||
| 9493 | if (!DRW::reserve(row.m_cells, static_cast<int>(columns))) | |||
| 9494 | return fail(); | |||
| 9495 | if (!DRW::resize(row.m_cells, static_cast<int>(columns))) | |||
| 9496 | return fail(); | |||
| 9497 | m_content.m_rows.push_back(row); | |||
| 9498 | } | |||
| 9499 | dwgHandle parsedTableStyleHandle; | |||
| 9500 | if (!readBoundedDwgHandle(hBuff, handleEndBit, 0, false, | |||
| 9501 | parsedTableStyleHandle)) | |||
| 9502 | return fail(); | |||
| 9503 | m_tableStyleHandle = parsedTableStyleHandle.ref; | |||
| 9504 | if (!hBuff.isGood()) | |||
| 9505 | return fail(); | |||
| 9506 | m_content.m_tableStyleHandle = m_tableStyleHandle; | |||
| 9507 | m_semanticContentComplete = true; | |||
| 9508 | // For <=AC1018 (R2000/R2004) there is no separate R2007+ string stream: | |||
| 9509 | // DRW_Entity::parseDwg only seeks sBuf when version > AC1018 (see the | |||
| 9510 | // `strBuf != NULL && version > DRW::AC1018` guard there), so legacy cell | |||
| 9511 | // text is inline in `buf`. Passing the stale sBuf copy here would read | |||
| 9512 | // text from the wrong position and desync `buf`. Pass nullptr so the | |||
| 9513 | // cell readers' `textBuf = strBuf ? strBuf : buf` falls back to the | |||
| 9514 | // inline `buf`. R2007 (AC1021) keeps the separate sBuf stream. | |||
| 9515 | dwgBuffer *cellStrBuf = (version > DRW::AC1018) ? sBuf : nullptr; | |||
| 9516 | TableDwgBounds tableBounds; | |||
| 9517 | tableBounds.bodyEndBit = bodyEndBit; | |||
| 9518 | tableBounds.stringEndBit = cellStrBuf == nullptr | |||
| 9519 | ? bodyEndBit : proxyEntityEndBit(*cellStrBuf, 0); | |||
| 9520 | tableBounds.handleEndBit = handleEndBit; | |||
| 9521 | for (std::uint32_t row = 0; row < rows && m_semanticContentComplete; ++row) { | |||
| 9522 | for (std::uint32_t column = 0; column < columns; ++column) { | |||
| 9523 | if (!parseR2007TableCell(version, buf, cellStrBuf, &hBuff, | |||
| 9524 | m_content.m_rows[row].m_cells[column], | |||
| 9525 | &m_content.m_subrecordRanges, | |||
| 9526 | tableBounds)) { | |||
| 9527 | m_semanticContentComplete = false; | |||
| 9528 | break; | |||
| 9529 | } | |||
| 9530 | } | |||
| 9531 | } | |||
| 9532 | ||||
| 9533 | if (m_semanticContentComplete) | |||
| 9534 | m_semanticContentComplete = skipR2007TableOverrides( | |||
| 9535 | version, buf, cellStrBuf, &hBuff, &m_content.m_subrecordRanges, | |||
| 9536 | tableBounds); | |||
| 9537 | if (!m_semanticContentComplete) | |||
| 9538 | DRW_DBG("R2007 TABLE cell parse incomplete; anonymous block insert kept\n")DRW_dbg::dbg("R2007 TABLE cell parse incomplete; anonymous block insert kept\n" ); | |||
| 9539 | ||||
| 9540 | if (!buf->isGood() || !sBuf->isGood() || !hBuff.isGood()) | |||
| 9541 | return fail(); | |||
| 9542 | m_valueFlag = parsedValueFlag; | |||
| 9543 | m_horizontalDirection = parsedHorizontalDirection; | |||
| 9544 | return commit(); | |||
| 9545 | } | |||
| 9546 | ||||
| 9547 | bool DRW_TableContentObject::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){ | |||
| 9548 | reset(); | |||
| 9549 | const auto fail = [this, buf]() { | |||
| 9550 | if (buf != nullptr) | |||
| 9551 | buf->invalidate(); | |||
| 9552 | reset(); | |||
| 9553 | return false; | |||
| 9554 | }; | |||
| 9555 | if (buf == nullptr || version <= DRW::AC1018) | |||
| 9556 | return fail(); | |||
| 9557 | ||||
| 9558 | dwgBuffer sBuff = *buf; | |||
| 9559 | sBuff.setVariableTextByteLength(true); | |||
| 9560 | dwgBuffer *sBuf = &sBuff; | |||
| 9561 | bool ret = DRW_TableEntry::parseDwg(version, buf, sBuf, bs); | |||
| 9562 | DRW_DBG("\n************************** parsing table content object ************************\n")DRW_dbg::dbg("\n************************** parsing table content object ************************\n" ); | |||
| 9563 | if (!ret) | |||
| 9564 | return fail(); | |||
| 9565 | ||||
| 9566 | dwgBuffer bodyBuff = *buf; | |||
| 9567 | dwgBuffer *bodyBuf = &bodyBuff; | |||
| 9568 | ||||
| 9569 | dwgBuffer hBuff = *buf; | |||
| 9570 | seekTableObjectHandleStream(version, &hBuff, objSize); | |||
| 9571 | std::uint64_t handleEndBit = 0; | |||
| 9572 | if (!dwgHandleStreamEndBit(*buf, version, objSize, bs, handleEndBit)) | |||
| 9573 | return fail(); | |||
| 9574 | std::uint32_t parsedParentHandle = 0; | |||
| 9575 | std::vector<std::uint32_t> parsedReactors; | |||
| 9576 | std::uint32_t parsedXDictHandle = 0; | |||
| 9577 | if (!readTableObjectCommonHandles(&hBuff, handle, numReactors, xDictFlag, | |||
| 9578 | &parsedParentHandle, &parsedReactors, | |||
| 9579 | &parsedXDictHandle, handleEndBit)) | |||
| 9580 | return fail(); | |||
| 9581 | ||||
| 9582 | DRW_TableContent parsedContent; | |||
| 9583 | TableDwgBounds tableBounds; | |||
| 9584 | tableBounds.bodyEndBit = tableBodyEndBit(version, sBuf, objSize); | |||
| 9585 | tableBounds.stringEndBit = proxyEntityEndBit(*sBuf, 0); | |||
| 9586 | tableBounds.handleEndBit = handleEndBit; | |||
| 9587 | const bool parseComplete = parseTableContent( | |||
| 9588 | version, bodyBuf, sBuf, &hBuff, parsedContent, tableBounds); | |||
| 9589 | const std::uint64_t bodyBitOffset = | |||
| 9590 | bodyBuf->getPosition() * 8u + bodyBuf->getBitPos(); | |||
| 9591 | if (!parseComplete || !bodyBuf->isGood() || !sBuf->isGood() | |||
| 9592 | || !hBuff.isGood() || bodyBitOffset > objSize) | |||
| 9593 | return fail(); | |||
| 9594 | ||||
| 9595 | m_content = std::move(parsedContent); | |||
| 9596 | m_parseComplete = true; | |||
| 9597 | parentHandle = parsedParentHandle; | |||
| 9598 | reactorHandles = std::move(parsedReactors); | |||
| 9599 | xDictHandle = parsedXDictHandle; | |||
| 9600 | return true; | |||
| 9601 | } | |||
| 9602 | ||||
| 9603 | void DRW_LWPolyline::applyExtrusion(){ | |||
| 9604 | if (haveExtrusion) { | |||
| 9605 | calculateAxis(extPoint); | |||
| 9606 | for (unsigned int i=0; i<vertlist.size(); i++) { | |||
| 9607 | auto& vert = vertlist.at(i); | |||
| 9608 | DRW_Coord v(vert->x, vert->y, elevation); | |||
| 9609 | extrudePoint(extPoint, &v); | |||
| 9610 | vert->x = v.x; | |||
| 9611 | vert->y = v.y; | |||
| 9612 | } | |||
| 9613 | } | |||
| 9614 | } | |||
| 9615 | ||||
| 9616 | bool DRW_LWPolyline::parseCode(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 9617 | switch (code) { | |||
| 9618 | case 10: { | |||
| 9619 | if (vertlist.size() >= static_cast<std::size_t>(kMaxLWPolylineVertices) | |||
| 9620 | || (m_dxfVertexCountSeen | |||
| 9621 | && vertlist.size() >= static_cast<std::size_t>(vertexnum))) | |||
| 9622 | return false; | |||
| 9623 | vertex = std::make_shared<DRW_Vertex2D>(); | |||
| 9624 | vertlist.push_back(vertex); | |||
| 9625 | vertex->x = reader->getDouble(); | |||
| 9626 | break; } | |||
| 9627 | case 20: | |||
| 9628 | if(vertex) | |||
| 9629 | vertex->y = reader->getDouble(); | |||
| 9630 | break; | |||
| 9631 | case 40: | |||
| 9632 | if(vertex) | |||
| 9633 | vertex->stawidth = reader->getDouble(); | |||
| 9634 | break; | |||
| 9635 | case 41: | |||
| 9636 | if(vertex) | |||
| 9637 | vertex->endwidth = reader->getDouble(); | |||
| 9638 | break; | |||
| 9639 | case 42: | |||
| 9640 | if(vertex) | |||
| 9641 | vertex->bulge = reader->getDouble(); | |||
| 9642 | break; | |||
| 9643 | case 91: | |||
| 9644 | if (vertex) | |||
| 9645 | vertex->identifier = reader->getInt32(); | |||
| 9646 | break; | |||
| 9647 | case 38: | |||
| 9648 | elevation = reader->getDouble(); | |||
| 9649 | break; | |||
| 9650 | case 39: | |||
| 9651 | thickness = reader->getDouble(); | |||
| 9652 | break; | |||
| 9653 | case 43: | |||
| 9654 | width = reader->getDouble(); | |||
| 9655 | break; | |||
| 9656 | case 70: | |||
| 9657 | flags = reader->getInt32(); | |||
| 9658 | break; | |||
| 9659 | case 90: | |||
| 9660 | if (m_dxfVertexCountSeen) | |||
| 9661 | return false; | |||
| 9662 | vertexnum = reader->getInt32(); | |||
| 9663 | if (!isValidCount(vertexnum, kMaxLWPolylineVertices)) | |||
| 9664 | return false; | |||
| 9665 | m_dxfVertexCountSeen = true; | |||
| 9666 | return DRW::reserve(vertlist, vertexnum); | |||
| 9667 | case 210: | |||
| 9668 | haveExtrusion = true; | |||
| 9669 | extPoint.x = reader->getDouble(); | |||
| 9670 | break; | |||
| 9671 | case 220: | |||
| 9672 | extPoint.y = reader->getDouble(); | |||
| 9673 | break; | |||
| 9674 | case 230: | |||
| 9675 | extPoint.z = reader->getDouble(); | |||
| 9676 | break; | |||
| 9677 | default: | |||
| 9678 | return DRW_Entity::parseCode(code, reader); | |||
| 9679 | } | |||
| 9680 | ||||
| 9681 | return true; | |||
| 9682 | } | |||
| 9683 | ||||
| 9684 | bool DRW_LWPolyline::validateDxf() const { | |||
| 9685 | return (!m_dxfVertexCountSeen | |||
| 9686 | || vertlist.size() == static_cast<std::size_t>(vertexnum)) | |||
| 9687 | && validatePayloadFields(); | |||
| 9688 | } | |||
| 9689 | ||||
| 9690 | bool DRW_LWPolyline::validatePayloadFields() const { | |||
| 9691 | const auto finite = [](double value) { return std::isfinite(value); }; | |||
| 9692 | const auto finiteVertex = [&finite](const auto& vertex) { | |||
| 9693 | return vertex != nullptr && finite(vertex->x) && finite(vertex->y) | |||
| 9694 | && finite(vertex->stawidth) && finite(vertex->endwidth) | |||
| 9695 | && finite(vertex->bulge) | |||
| 9696 | && vertex->identifier >= std::numeric_limits<std::int32_t>::min() | |||
| 9697 | && vertex->identifier <= std::numeric_limits<std::int32_t>::max(); | |||
| 9698 | }; | |||
| 9699 | ||||
| 9700 | // LWPOLYLINE group 70 has only the closed and linetype-generation bits. | |||
| 9701 | return flags >= 0 && (flags & ~0x81) == 0 | |||
| 9702 | && finite(width) && finite(elevation) && finite(thickness) | |||
| 9703 | && finite(extPoint.x) && finite(extPoint.y) && finite(extPoint.z) | |||
| 9704 | && vertlist.size() <= static_cast<std::size_t>(kMaxLWPolylineVertices) | |||
| 9705 | && vertlist.size() | |||
| 9706 | <= static_cast<std::size_t>(std::numeric_limits<std::int32_t>::max()) | |||
| 9707 | && std::all_of(vertlist.cbegin(), vertlist.cend(), finiteVertex); | |||
| 9708 | } | |||
| 9709 | ||||
| 9710 | bool DRW_LWPolyline::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){ | |||
| 9711 | const auto resetState = [this]() { | |||
| 9712 | DRW_Entity::reset(); | |||
| 9713 | vertexnum = 0; | |||
| 9714 | flags = 0; | |||
| 9715 | width = 0.0; | |||
| 9716 | elevation = 0.0; | |||
| 9717 | thickness = 0.0; | |||
| 9718 | extPoint = DRW_Coord{0.0, 0.0, 1.0}; | |||
| 9719 | vertlist.clear(); | |||
| 9720 | vertex.reset(); | |||
| 9721 | m_dxfVertexCountSeen = false; | |||
| 9722 | }; | |||
| 9723 | resetState(); | |||
| 9724 | dwgBuffer *sourceBuf = buf; | |||
| 9725 | const auto fail = [sourceBuf, resetState]() { | |||
| 9726 | if (sourceBuf != nullptr) | |||
| 9727 | sourceBuf->invalidate(); | |||
| 9728 | resetState(); | |||
| 9729 | return false; | |||
| 9730 | }; | |||
| 9731 | if (sourceBuf == nullptr) | |||
| 9732 | return fail(); | |||
| 9733 | ||||
| 9734 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 9735 | buf = &bodyProbe; | |||
| 9736 | bool ret = DRW_Entity::parseDwgCommon(version, buf, bs); | |||
| 9737 | if (!ret || !buf->isGood()) | |||
| 9738 | return fail(); | |||
| 9739 | DRW_DBG("\n***************************** parsing LWPolyline *******************************************\n")DRW_dbg::dbg("\n***************************** parsing LWPolyline *******************************************\n" ); | |||
| 9740 | ||||
| 9741 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 9742 | std::uint16_t rawFlagsValue = 0; | |||
| 9743 | if (!readBoundedBitShort(*buf, bodyEndBit, rawFlagsValue)) | |||
| 9744 | return fail(); | |||
| 9745 | const int rawFlags = static_cast<int>(rawFlagsValue); | |||
| 9746 | double parsedWidth = 0.0; | |||
| 9747 | double parsedElevation = 0.0; | |||
| 9748 | double parsedThickness = 0.0; | |||
| 9749 | DRW_Coord parsedExtPoint{0.0, 0.0, 1.0}; | |||
| 9750 | if ((rawFlags & 4) | |||
| 9751 | && !readBoundedBitDouble(*buf, bodyEndBit, parsedWidth)) | |||
| 9752 | return fail(); | |||
| 9753 | if ((rawFlags & 8) | |||
| 9754 | && !readBoundedBitDouble(*buf, bodyEndBit, parsedElevation)) | |||
| 9755 | return fail(); | |||
| 9756 | if ((rawFlags & 2) | |||
| 9757 | && !readBoundedBitDouble(*buf, bodyEndBit, parsedThickness)) | |||
| 9758 | return fail(); | |||
| 9759 | if ((rawFlags & 1) | |||
| 9760 | && !readBoundedExtrusion(*buf, bodyEndBit, false, parsedExtPoint)) | |||
| 9761 | return fail(); | |||
| 9762 | DRW_DBG("flags value: ")DRW_dbg::dbg("flags value: "); DRW_DBG(rawFlags)DRW_dbg::dbg(rawFlags); | |||
| 9763 | ||||
| 9764 | const std::uint32_t minimumVertexBits = version < DRW::AC1015 ? 128u : 4u; | |||
| 9765 | std::uint32_t parsedVertexCount = 0; | |||
| 9766 | if (!readTableBodyCount(version, buf, objSize, | |||
| 9767 | kMaxLWPolylineVertices, minimumVertexBits, | |||
| 9768 | parsedVertexCount)) { | |||
| 9769 | return fail(); | |||
| 9770 | } | |||
| 9771 | ||||
| 9772 | std::uint64_t vertexBits = 0; | |||
| 9773 | if (parsedVertexCount > 0) { | |||
| 9774 | if (version < DRW::AC1015) { | |||
| 9775 | if (!dwgSafety::multiply(parsedVertexCount, 128, vertexBits)) | |||
| 9776 | return fail(); | |||
| 9777 | } else { | |||
| 9778 | std::uint64_t deltaBits = 0; | |||
| 9779 | if (!dwgSafety::multiply(parsedVertexCount - 1, 4, deltaBits) | |||
| 9780 | || !dwgSafety::add(128, deltaBits, vertexBits)) | |||
| 9781 | return fail(); | |||
| 9782 | } | |||
| 9783 | } | |||
| 9784 | if (!proxyEntityHasBits(*buf, bodyEndBit, vertexBits)) | |||
| 9785 | return fail(); | |||
| 9786 | ||||
| 9787 | std::vector<std::shared_ptr<DRW_Vertex2D>> parsedVertices; | |||
| 9788 | if (!DRW::reserve(parsedVertices, parsedVertexCount)) | |||
| 9789 | return fail(); | |||
| 9790 | ||||
| 9791 | std::uint32_t bulgesnum = 0; | |||
| 9792 | if (rawFlags & 16) { | |||
| 9793 | if (!readTableBodyCount(version, buf, objSize, | |||
| 9794 | kMaxLWPolylineVertices, 2, | |||
| 9795 | bulgesnum)) | |||
| 9796 | return fail(); | |||
| 9797 | } | |||
| 9798 | std::uint32_t vertexIdCount = 0; | |||
| 9799 | if (version > DRW::AC1021) {//2010+ | |||
| 9800 | if (rawFlags & 1024) { | |||
| 9801 | if (!readTableBodyCount(version, buf, objSize, | |||
| 9802 | kMaxLWPolylineVertices, 2, | |||
| 9803 | vertexIdCount)) | |||
| 9804 | return fail(); | |||
| 9805 | } | |||
| 9806 | } | |||
| 9807 | std::uint32_t widthsnum = 0; | |||
| 9808 | if (rawFlags & 32) { | |||
| 9809 | if (!readTableBodyCount(version, buf, objSize, | |||
| 9810 | kMaxLWPolylineVertices, 4, | |||
| 9811 | widthsnum)) | |||
| 9812 | return fail(); | |||
| 9813 | } | |||
| 9814 | std::uint64_t bulgeBits = 0; | |||
| 9815 | std::uint64_t vertexIdBits = 0; | |||
| 9816 | std::uint64_t widthBits = 0; | |||
| 9817 | std::uint64_t optionalBits = 0; | |||
| 9818 | if (!dwgSafety::multiply(bulgesnum, 2, bulgeBits) | |||
| 9819 | || !dwgSafety::multiply(vertexIdCount, 2, vertexIdBits) | |||
| 9820 | || !dwgSafety::multiply(widthsnum, 4, widthBits) | |||
| 9821 | || !dwgSafety::add(bulgeBits, vertexIdBits, optionalBits) | |||
| 9822 | || !dwgSafety::add(optionalBits, widthBits, optionalBits)) { | |||
| 9823 | return fail(); | |||
| 9824 | } | |||
| 9825 | if (!proxyEntityHasBits(*buf, bodyEndBit, optionalBits)) | |||
| 9826 | return fail(); | |||
| 9827 | DRW_DBG("\nvertex num: ")DRW_dbg::dbg("\nvertex num: "); DRW_DBG(parsedVertexCount)DRW_dbg::dbg(parsedVertexCount); DRW_DBG(" bulges num: ")DRW_dbg::dbg(" bulges num: "); DRW_DBG(bulgesnum)DRW_dbg::dbg(bulgesnum); | |||
| 9828 | DRW_DBG(" vertexIdCount: ")DRW_dbg::dbg(" vertexIdCount: "); DRW_DBG(vertexIdCount)DRW_dbg::dbg(vertexIdCount); DRW_DBG(" widths num: ")DRW_dbg::dbg(" widths num: "); DRW_DBG(widthsnum)DRW_dbg::dbg(widthsnum); | |||
| 9829 | ||||
| 9830 | if (parsedVertexCount > 0) { //verify if is lwpol without vertex (empty) | |||
| 9831 | // add vertexes | |||
| 9832 | auto parsedVertex = std::make_shared<DRW_Vertex2D>(); | |||
| 9833 | if (!readBoundedRawDouble(*buf, bodyEndBit, parsedVertex->x) | |||
| 9834 | || !readBoundedRawDouble(*buf, bodyEndBit, parsedVertex->y)) | |||
| 9835 | return fail(); | |||
| 9836 | parsedVertices.push_back(parsedVertex); | |||
| 9837 | auto pv = parsedVertex; | |||
| 9838 | for (std::uint32_t i = 1; i < parsedVertexCount; ++i){ | |||
| 9839 | parsedVertex = std::make_shared<DRW_Vertex2D>(); | |||
| 9840 | if (version < DRW::AC1015) {//14- | |||
| 9841 | if (!readBoundedRawDouble(*buf, bodyEndBit, parsedVertex->x) | |||
| 9842 | || !readBoundedRawDouble(*buf, bodyEndBit, parsedVertex->y)) | |||
| 9843 | return fail(); | |||
| 9844 | } else { | |||
| 9845 | if (!readBoundedDefaultDouble(*buf, bodyEndBit, pv->x, | |||
| 9846 | parsedVertex->x) | |||
| 9847 | || !readBoundedDefaultDouble(*buf, bodyEndBit, pv->y, | |||
| 9848 | parsedVertex->y)) | |||
| 9849 | return fail(); | |||
| 9850 | } | |||
| 9851 | pv = parsedVertex; | |||
| 9852 | parsedVertices.push_back(parsedVertex); | |||
| 9853 | } | |||
| 9854 | } | |||
| 9855 | // The optional vectors are independent DWG fields, not per-point | |||
| 9856 | // conditionals. Consume them even when num_points is zero so the handle | |||
| 9857 | // stream remains aligned; values without a corresponding vertex are | |||
| 9858 | // intentionally discarded by the existing model. | |||
| 9859 | for (std::uint32_t i = 0; i < bulgesnum; i++){ | |||
| 9860 | double bulge = 0.0; | |||
| 9861 | if (!readBoundedBitDouble(*buf, bodyEndBit, bulge)) | |||
| 9862 | return fail(); | |||
| 9863 | if (i < parsedVertices.size()) | |||
| 9864 | parsedVertices.at(i)->bulge = bulge; | |||
| 9865 | } | |||
| 9866 | //add vertexId | |||
| 9867 | if (version > DRW::AC1021) {//2010+ | |||
| 9868 | for (std::uint32_t i = 0; i < vertexIdCount; i++){ | |||
| 9869 | std::int32_t vertexId = 0; | |||
| 9870 | if (!readBoundedBitLong(*buf, bodyEndBit, vertexId)) | |||
| 9871 | return fail(); | |||
| 9872 | if (i < parsedVertices.size()) | |||
| 9873 | parsedVertices.at(i)->identifier = vertexId; | |||
| 9874 | } | |||
| 9875 | } | |||
| 9876 | //add widths | |||
| 9877 | for (std::uint32_t i = 0; i < widthsnum; i++){ | |||
| 9878 | double staW = 0.0; | |||
| 9879 | double endW = 0.0; | |||
| 9880 | if (!readBoundedBitDouble(*buf, bodyEndBit, staW) | |||
| 9881 | || !readBoundedBitDouble(*buf, bodyEndBit, endW)) | |||
| 9882 | return fail(); | |||
| 9883 | if (i < parsedVertices.size()) { | |||
| 9884 | parsedVertices.at(i)->stawidth = staW; | |||
| 9885 | parsedVertices.at(i)->endwidth = endW; | |||
| 9886 | } | |||
| 9887 | } | |||
| 9888 | if (DRW_DBGGLDRW_dbg::getInstance()->getLevel() == DRW_dbg::Level::Debug){ | |||
| 9889 | DRW_DBG("\nVertex list: ")DRW_dbg::dbg("\nVertex list: "); | |||
| 9890 | for (auto& pv: parsedVertices) { | |||
| 9891 | DRW_DBG("\n x: ")DRW_dbg::dbg("\n x: "); DRW_DBG(pv->x)DRW_dbg::dbg(pv->x); DRW_DBG(" y: ")DRW_dbg::dbg(" y: "); DRW_DBG(pv->y)DRW_dbg::dbg(pv->y); DRW_DBG(" bulge: ")DRW_dbg::dbg(" bulge: "); DRW_DBG(pv->bulge)DRW_dbg::dbg(pv->bulge); | |||
| 9892 | DRW_DBG(" stawidth: ")DRW_dbg::dbg(" stawidth: "); DRW_DBG(pv->stawidth)DRW_dbg::dbg(pv->stawidth); DRW_DBG(" endwidth: ")DRW_dbg::dbg(" endwidth: "); DRW_DBG(pv->endwidth)DRW_dbg::dbg(pv->endwidth); | |||
| 9893 | DRW_DBG(" identifier: ")DRW_dbg::dbg(" identifier: "); DRW_DBG(pv->identifier)DRW_dbg::dbg(pv->identifier); | |||
| 9894 | } | |||
| 9895 | } | |||
| 9896 | ||||
| 9897 | const auto finite = [](const DRW_Coord& point) { | |||
| 9898 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 9899 | && std::isfinite(point.z); | |||
| 9900 | }; | |||
| 9901 | if (!finite(parsedExtPoint) || !std::isfinite(parsedWidth) | |||
| 9902 | || !std::isfinite(parsedElevation) || !std::isfinite(parsedThickness) | |||
| 9903 | || !std::all_of(parsedVertices.begin(), parsedVertices.end(), | |||
| 9904 | [](const std::shared_ptr<DRW_Vertex2D>& point) { | |||
| 9905 | return point != nullptr | |||
| 9906 | && std::isfinite(point->x) | |||
| 9907 | && std::isfinite(point->y) | |||
| 9908 | && std::isfinite(point->bulge) | |||
| 9909 | && std::isfinite(point->stawidth) | |||
| 9910 | && std::isfinite(point->endwidth); | |||
| 9911 | })) | |||
| 9912 | return fail(); | |||
| 9913 | ||||
| 9914 | DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 9915 | /* Common Entity Handle Data */ | |||
| 9916 | std::uint64_t handleEndBit = 0; | |||
| 9917 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, | |||
| 9918 | handleEndBit)) | |||
| 9919 | return fail(); | |||
| 9920 | dwgBuffer handleProbe = buf->forkIndependent(); | |||
| 9921 | ret = DRW_Entity::parseDwgEntHandle(version, &handleProbe, true, | |||
| 9922 | handleEndBit); | |||
| 9923 | if (!ret || !handleProbe.isGood()) | |||
| 9924 | return fail(); | |||
| 9925 | ||||
| 9926 | // Translate DWG LWPLINE flag bits to DXF group 70 bits. | |||
| 9927 | int dxfFlags = 0; | |||
| 9928 | if (rawFlags & 512) | |||
| 9929 | dxfFlags |= 1; | |||
| 9930 | if (rawFlags & 256) | |||
| 9931 | dxfFlags |= 128; | |||
| 9932 | vertexnum = static_cast<std::int32_t>(parsedVertexCount); | |||
| 9933 | flags = dxfFlags; | |||
| 9934 | width = parsedWidth; | |||
| 9935 | elevation = parsedElevation; | |||
| 9936 | thickness = parsedThickness; | |||
| 9937 | extPoint = parsedExtPoint; | |||
| 9938 | vertlist = std::move(parsedVertices); | |||
| 9939 | *sourceBuf = handleProbe; | |||
| 9940 | DRW_DBG("end flags value: ")DRW_dbg::dbg("end flags value: "); DRW_DBG(flags)DRW_dbg::dbg(flags); | |||
| 9941 | /* CRC X --- */ | |||
| 9942 | return true; | |||
| 9943 | } | |||
| 9944 | ||||
| 9945 | ||||
| 9946 | // ---------------------------------------------------------------------------- | |||
| 9947 | // DRW_MLine — multiline entity (ODA §19.4.78, fixed type 0x2F = 47). | |||
| 9948 | // ---------------------------------------------------------------------------- | |||
| 9949 | ||||
| 9950 | bool DRW_MLine::parseCode(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 9951 | switch (code) { | |||
| 9952 | case 2: | |||
| 9953 | styleName = reader->getString(); | |||
| 9954 | break; | |||
| 9955 | case 340: | |||
| 9956 | styleHandle = static_cast<std::uint32_t>(reader->getHandleString()); | |||
| 9957 | break; | |||
| 9958 | case 40: | |||
| 9959 | scale = reader->getDouble(); | |||
| 9960 | break; | |||
| 9961 | case 70: | |||
| 9962 | { | |||
| 9963 | int value = 0; | |||
| 9964 | if (!readDxfIntInRange(reader, 0, 2, value)) | |||
| 9965 | return false; | |||
| 9966 | justification = static_cast<std::uint8_t>(value); | |||
| 9967 | } | |||
| 9968 | break; | |||
| 9969 | case 71: | |||
| 9970 | openClosed = reader->getInt32(); | |||
| 9971 | break; | |||
| 9972 | case 72: | |||
| 9973 | if (m_dxfVertexCountSeen) | |||
| 9974 | return false; | |||
| 9975 | { | |||
| 9976 | const std::int32_t count = reader->getInt32(); | |||
| 9977 | if (!isValidCount(count, kMaxDxfVertices)) | |||
| 9978 | return false; | |||
| 9979 | numVerts = static_cast<std::uint16_t>(count); | |||
| 9980 | m_dxfVertexCountSeen = true; | |||
| 9981 | } | |||
| 9982 | break; | |||
| 9983 | case 73: | |||
| 9984 | if (m_dxfLineCountSeen) | |||
| 9985 | return false; | |||
| 9986 | { | |||
| 9987 | const std::int32_t count = reader->getInt32(); | |||
| 9988 | if (!isValidCount(count, kMaxDxfLines)) | |||
| 9989 | return false; | |||
| 9990 | numLines = static_cast<std::uint8_t>(count); | |||
| 9991 | m_dxfLineCountSeen = true; | |||
| 9992 | } | |||
| 9993 | break; | |||
| 9994 | case 10: | |||
| 9995 | basePoint.x = reader->getDouble(); | |||
| 9996 | break; | |||
| 9997 | case 20: | |||
| 9998 | basePoint.y = reader->getDouble(); | |||
| 9999 | break; | |||
| 10000 | case 30: | |||
| 10001 | basePoint.z = reader->getDouble(); | |||
| 10002 | break; | |||
| 10003 | case 210: | |||
| 10004 | extPoint.x = reader->getDouble(); | |||
| 10005 | break; | |||
| 10006 | case 220: | |||
| 10007 | extPoint.y = reader->getDouble(); | |||
| 10008 | break; | |||
| 10009 | case 230: | |||
| 10010 | extPoint.z = reader->getDouble(); | |||
| 10011 | break; | |||
| 10012 | // Per-vertex block: code 11 starts a new vertex; 12/13 follow. | |||
| 10013 | case 11: | |||
| 10014 | if (m_currentSegExpected >= 0 || m_currentAreaExpected >= 0) | |||
| 10015 | return false; | |||
| 10016 | ++m_currentVertexIdx; | |||
| 10017 | m_currentElementIdx = 0; | |||
| 10018 | if (m_currentVertexIdx >= kMaxDxfVertices | |||
| 10019 | || (m_dxfVertexCountSeen | |||
| 10020 | && m_currentVertexIdx >= static_cast<int>(numVerts))) | |||
| 10021 | return false; | |||
| 10022 | vertlist.emplace_back(); | |||
| 10023 | vertlist[m_currentVertexIdx].position.x = reader->getDouble(); | |||
| 10024 | break; | |||
| 10025 | case 21: | |||
| 10026 | if (m_currentVertexIdx >= 0) | |||
| 10027 | vertlist[m_currentVertexIdx].position.y = reader->getDouble(); | |||
| 10028 | break; | |||
| 10029 | case 31: | |||
| 10030 | if (m_currentVertexIdx >= 0) | |||
| 10031 | vertlist[m_currentVertexIdx].position.z = reader->getDouble(); | |||
| 10032 | break; | |||
| 10033 | case 12: | |||
| 10034 | if (m_currentVertexIdx >= 0) | |||
| 10035 | vertlist[m_currentVertexIdx].vertexDir.x = reader->getDouble(); | |||
| 10036 | break; | |||
| 10037 | case 22: | |||
| 10038 | if (m_currentVertexIdx >= 0) | |||
| 10039 | vertlist[m_currentVertexIdx].vertexDir.y = reader->getDouble(); | |||
| 10040 | break; | |||
| 10041 | case 32: | |||
| 10042 | if (m_currentVertexIdx >= 0) | |||
| 10043 | vertlist[m_currentVertexIdx].vertexDir.z = reader->getDouble(); | |||
| 10044 | break; | |||
| 10045 | case 13: | |||
| 10046 | if (m_currentVertexIdx >= 0) | |||
| 10047 | vertlist[m_currentVertexIdx].miterDir.x = reader->getDouble(); | |||
| 10048 | break; | |||
| 10049 | case 23: | |||
| 10050 | if (m_currentVertexIdx >= 0) | |||
| 10051 | vertlist[m_currentVertexIdx].miterDir.y = reader->getDouble(); | |||
| 10052 | break; | |||
| 10053 | case 33: | |||
| 10054 | if (m_currentVertexIdx >= 0) | |||
| 10055 | vertlist[m_currentVertexIdx].miterDir.z = reader->getDouble(); | |||
| 10056 | break; | |||
| 10057 | // 74 = segment-param count for current element. Sets up the inner | |||
| 10058 | // vector and resets the running param count. 41 reads each param. | |||
| 10059 | // 75 = fill-param count; 42 reads each. After fills are consumed, | |||
| 10060 | // advance to the next element. AutoCAD emits 74/41*/75/42* per element. | |||
| 10061 | case 74: | |||
| 10062 | if (m_currentVertexIdx < 0 | |||
| 10063 | || m_currentSegExpected >= 0 || m_currentAreaExpected >= 0) | |||
| 10064 | return false; | |||
| 10065 | { | |||
| 10066 | auto& v = vertlist[m_currentVertexIdx]; | |||
| 10067 | if (m_currentElementIdx != static_cast<int>(v.segParms.size()) | |||
| 10068 | || m_currentElementIdx >= kMaxDxfLines | |||
| 10069 | || (m_dxfLineCountSeen | |||
| 10070 | && m_currentElementIdx >= static_cast<int>(numLines))) | |||
| 10071 | return false; | |||
| 10072 | const std::int32_t count = reader->getInt32(); | |||
| 10073 | if (!isValidCount(count, kMaxDxfParameters)) | |||
| 10074 | return false; | |||
| 10075 | v.segParms.emplace_back(); | |||
| 10076 | v.areaFillParms.emplace_back(); | |||
| 10077 | m_currentSegExpected = count; | |||
| 10078 | m_currentSegFillCount = 0; | |||
| 10079 | } | |||
| 10080 | break; | |||
| 10081 | case 41: | |||
| 10082 | if (m_currentVertexIdx < 0 || m_currentSegExpected < 0 | |||
| 10083 | || m_currentElementIdx >= static_cast<int>(vertlist[m_currentVertexIdx].segParms.size())) | |||
| 10084 | return false; | |||
| 10085 | if (static_cast<std::int32_t>( | |||
| 10086 | vertlist[m_currentVertexIdx].segParms[m_currentElementIdx].size()) | |||
| 10087 | >= m_currentSegExpected) | |||
| 10088 | return false; | |||
| 10089 | vertlist[m_currentVertexIdx].segParms[m_currentElementIdx] | |||
| 10090 | .push_back(reader->getDouble()); | |||
| 10091 | break; | |||
| 10092 | case 75: | |||
| 10093 | if (m_currentVertexIdx < 0 || m_currentSegExpected < 0 | |||
| 10094 | || m_currentAreaExpected >= 0 | |||
| 10095 | || m_currentElementIdx >= static_cast<int>(vertlist[m_currentVertexIdx].segParms.size())) | |||
| 10096 | return false; | |||
| 10097 | if (static_cast<std::int32_t>( | |||
| 10098 | vertlist[m_currentVertexIdx].segParms[m_currentElementIdx].size()) | |||
| 10099 | != m_currentSegExpected) | |||
| 10100 | return false; | |||
| 10101 | m_currentSegExpected = -1; | |||
| 10102 | m_currentSegFillCount = reader->getInt32(); | |||
| 10103 | if (!isValidCount(m_currentSegFillCount, kMaxDxfParameters)) | |||
| 10104 | return false; | |||
| 10105 | m_currentAreaExpected = m_currentSegFillCount; | |||
| 10106 | if (m_currentAreaExpected == 0) { | |||
| 10107 | m_currentAreaExpected = -1; | |||
| 10108 | ++m_currentElementIdx; | |||
| 10109 | } | |||
| 10110 | break; | |||
| 10111 | case 42: | |||
| 10112 | if (m_currentVertexIdx < 0 || m_currentAreaExpected < 0 | |||
| 10113 | || m_currentElementIdx >= static_cast<int>(vertlist[m_currentVertexIdx].areaFillParms.size())) | |||
| 10114 | return false; | |||
| 10115 | if (static_cast<std::int32_t>( | |||
| 10116 | vertlist[m_currentVertexIdx].areaFillParms[m_currentElementIdx].size()) | |||
| 10117 | >= m_currentAreaExpected) | |||
| 10118 | return false; | |||
| 10119 | vertlist[m_currentVertexIdx].areaFillParms[m_currentElementIdx] | |||
| 10120 | .push_back(reader->getDouble()); | |||
| 10121 | if (static_cast<std::int32_t>( | |||
| 10122 | vertlist[m_currentVertexIdx].areaFillParms[m_currentElementIdx].size()) | |||
| 10123 | == m_currentAreaExpected) { | |||
| 10124 | m_currentAreaExpected = -1; | |||
| 10125 | ++m_currentElementIdx; | |||
| 10126 | } | |||
| 10127 | break; | |||
| 10128 | default: | |||
| 10129 | return DRW_Entity::parseCode(code, reader); | |||
| 10130 | } | |||
| 10131 | return true; | |||
| 10132 | } | |||
| 10133 | ||||
| 10134 | bool DRW_MLine::validateDxf() const { | |||
| 10135 | if (m_currentSegExpected >= 0 || m_currentAreaExpected >= 0) | |||
| 10136 | return false; | |||
| 10137 | if (m_dxfVertexCountSeen && vertlist.size() != numVerts) | |||
| 10138 | return false; | |||
| 10139 | if (!m_dxfLineCountSeen) | |||
| 10140 | return true; | |||
| 10141 | for (const DRW_MLineVertex& vertex : vertlist) { | |||
| 10142 | if (vertex.segParms.size() != numLines | |||
| 10143 | || vertex.areaFillParms.size() != numLines) | |||
| 10144 | return false; | |||
| 10145 | } | |||
| 10146 | return validatePayloadFields(); | |||
| 10147 | } | |||
| 10148 | ||||
| 10149 | bool DRW_MLine::validatePayloadFields() const { | |||
| 10150 | const auto finite = [](const DRW_Coord& point) { | |||
| 10151 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 10152 | && std::isfinite(point.z); | |||
| 10153 | }; | |||
| 10154 | if (!finite(basePoint) || !finite(extPoint) || !std::isfinite(scale) | |||
| 10155 | || openClosed < 0 || openClosed > 0xffff | |||
| 10156 | || numVerts > static_cast<std::uint16_t>(kMaxDxfVertices) | |||
| 10157 | || vertlist.size() > static_cast<std::size_t>(kMaxDxfVertices) | |||
| 10158 | || vertlist.size() != static_cast<std::size_t>(numVerts)) | |||
| 10159 | return false; | |||
| 10160 | ||||
| 10161 | for (const DRW_MLineVertex& vertex : vertlist) { | |||
| 10162 | if (!finite(vertex.position) || !finite(vertex.vertexDir) | |||
| 10163 | || !finite(vertex.miterDir) | |||
| 10164 | || vertex.segParms.size() != numLines | |||
| 10165 | || vertex.areaFillParms.size() != numLines) | |||
| 10166 | return false; | |||
| 10167 | const auto validParameters = [](const auto& parameterLists) { | |||
| 10168 | return std::all_of( | |||
| 10169 | parameterLists.cbegin(), parameterLists.cend(), | |||
| 10170 | [](const std::vector<double>& values) { | |||
| 10171 | return values.size() <= static_cast<std::size_t>( | |||
| 10172 | DRW_MLine::kMaxDxfParameters) | |||
| 10173 | && std::all_of(values.cbegin(), values.cend(), | |||
| 10174 | [](double value) { | |||
| 10175 | return std::isfinite(value); | |||
| 10176 | }); | |||
| 10177 | }); | |||
| 10178 | }; | |||
| 10179 | if (!validParameters(vertex.segParms) | |||
| 10180 | || !validParameters(vertex.areaFillParms)) | |||
| 10181 | return false; | |||
| 10182 | } | |||
| 10183 | return true; | |||
| 10184 | } | |||
| 10185 | ||||
| 10186 | void DRW_MLine::resetDwgState() { | |||
| 10187 | DRW_Entity::reset(); | |||
| 10188 | scale = 1.0; | |||
| 10189 | justification = 0; | |||
| 10190 | basePoint = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 10191 | extPoint = DRW_Coord{0.0, 0.0, 1.0}; | |||
| 10192 | openClosed = 1; | |||
| 10193 | numLines = 0; | |||
| 10194 | numVerts = 0; | |||
| 10195 | styleName.clear(); | |||
| 10196 | styleHandle = 0; | |||
| 10197 | vertlist.clear(); | |||
| 10198 | m_currentVertexIdx = -1; | |||
| 10199 | m_currentElementIdx = 0; | |||
| 10200 | m_currentSegFillCount = 0; | |||
| 10201 | m_currentSegExpected = -1; | |||
| 10202 | m_currentAreaExpected = -1; | |||
| 10203 | m_dxfVertexCountSeen = false; | |||
| 10204 | m_dxfLineCountSeen = false; | |||
| 10205 | } | |||
| 10206 | ||||
| 10207 | bool DRW_MLine::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){ | |||
| 10208 | resetDwgState(); | |||
| 10209 | dwgBuffer *sourceBuf = buf; | |||
| 10210 | auto fail = [this, sourceBuf]() { | |||
| 10211 | if (sourceBuf != nullptr) | |||
| 10212 | sourceBuf->invalidate(); | |||
| 10213 | resetDwgState(); | |||
| 10214 | return false; | |||
| 10215 | }; | |||
| 10216 | if (sourceBuf == nullptr) | |||
| 10217 | return fail(); | |||
| 10218 | ||||
| 10219 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 10220 | buf = &bodyProbe; | |||
| 10221 | ||||
| 10222 | if (!DRW_Entity::parseDwgCommon(version, buf, bs)) return fail(); | |||
| 10223 | DRW_DBG("\n***************************** parsing MLINE *********************\n")DRW_dbg::dbg("\n***************************** parsing MLINE *********************\n" ); | |||
| 10224 | // Per ODA §19.4.78 / libreDWG dwg_decode_MLINE: | |||
| 10225 | // BD scale, RC justification, 3BD basePoint, BE extrusion, | |||
| 10226 | // BS open/closed flag, RC num_lines, BS num_verts, | |||
| 10227 | // then per-vertex: 3BD pos, 3BD vdir, 3BD mdir, | |||
| 10228 | // per-line: BS num_segparms × BD parm, BS num_areafillparms × BD parm. | |||
| 10229 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 10230 | double parsedScale = 0.0; | |||
| 10231 | std::uint8_t parsedJustification = 0; | |||
| 10232 | DRW_Coord parsedBasePoint; | |||
| 10233 | DRW_Coord parsedExtPoint; | |||
| 10234 | std::uint16_t parsedOpenClosed = 0; | |||
| 10235 | std::uint8_t parsedNumLines = 0; | |||
| 10236 | std::uint16_t parsedNumVerts = 0; | |||
| 10237 | if (!readBoundedBitDouble(*buf, bodyEndBit, parsedScale) | |||
| 10238 | || !readBoundedRawChar8(*buf, bodyEndBit, parsedJustification) | |||
| 10239 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedBasePoint) | |||
| 10240 | || !readBoundedExtrusion(*buf, bodyEndBit, false, parsedExtPoint) | |||
| 10241 | || !readBoundedBitShort(*buf, bodyEndBit, parsedOpenClosed) | |||
| 10242 | || !readBoundedRawChar8(*buf, bodyEndBit, parsedNumLines) | |||
| 10243 | || !readBoundedBitShort(*buf, bodyEndBit, parsedNumVerts)) | |||
| 10244 | return fail(); | |||
| 10245 | if (!std::isfinite(parsedScale) | |||
| 10246 | || !std::isfinite(parsedBasePoint.x) | |||
| 10247 | || !std::isfinite(parsedBasePoint.y) | |||
| 10248 | || !std::isfinite(parsedBasePoint.z) | |||
| 10249 | || !std::isfinite(parsedExtPoint.x) | |||
| 10250 | || !std::isfinite(parsedExtPoint.y) | |||
| 10251 | || !std::isfinite(parsedExtPoint.z)) | |||
| 10252 | return fail(); | |||
| 10253 | DRW_DBG(" mline scale: ")DRW_dbg::dbg(" mline scale: "); DRW_DBG(parsedScale)DRW_dbg::dbg(parsedScale); | |||
| 10254 | DRW_DBG(" just: ")DRW_dbg::dbg(" just: "); DRW_DBG(static_cast<int>(parsedJustification))DRW_dbg::dbg(static_cast<int>(parsedJustification)); | |||
| 10255 | DRW_DBG(" openClosed: ")DRW_dbg::dbg(" openClosed: "); DRW_DBG(parsedOpenClosed)DRW_dbg::dbg(parsedOpenClosed); | |||
| 10256 | DRW_DBG(" lines: ")DRW_dbg::dbg(" lines: "); DRW_DBG(static_cast<int>(parsedNumLines))DRW_dbg::dbg(static_cast<int>(parsedNumLines)); | |||
| 10257 | DRW_DBG(" verts: ")DRW_dbg::dbg(" verts: "); DRW_DBG(parsedNumVerts)DRW_dbg::dbg(parsedNumVerts); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 10258 | if (!buf->isGood() | |||
| 10259 | || !isValidCount(static_cast<std::int32_t>(parsedNumVerts), kMaxDxfVertices) | |||
| 10260 | || !isValidCount(static_cast<std::int32_t>(parsedNumLines), kMaxDxfLines)) | |||
| 10261 | return fail(); | |||
| 10262 | ||||
| 10263 | // Each vertex always contains three minimum-width 3BD values and one | |||
| 10264 | // minimum-width BS for each segment/fill parameter count. Check this | |||
| 10265 | // before allocating the per-vertex/per-line vector grid. | |||
| 10266 | const std::uint64_t minimumBitsPerVertex = | |||
| 10267 | 18u + static_cast<std::uint64_t>(parsedNumLines) * 4u; | |||
| 10268 | std::uint64_t minimumVertexBits = 0; | |||
| 10269 | if (!dwgSafety::multiply(static_cast<std::uint64_t>(parsedNumVerts), | |||
| 10270 | minimumBitsPerVertex, minimumVertexBits) | |||
| 10271 | || !proxyEntityHasBits(*buf, bodyEndBit, minimumVertexBits)) | |||
| 10272 | return fail(); | |||
| 10273 | ||||
| 10274 | // The per-vertex parameter lists are also capped by the DWG spec. Keep a | |||
| 10275 | // combined budget so a valid per-list maximum cannot multiply into an | |||
| 10276 | // unbounded number of vector allocations on hostile input. | |||
| 10277 | constexpr std::uint64_t kMaxDwgParameters = 1000000; | |||
| 10278 | std::uint64_t totalParameters = 0; | |||
| 10279 | std::vector<DRW_MLineVertex> parsedVertices; | |||
| 10280 | if (!DRW::reserve(parsedVertices, parsedNumVerts)) | |||
| 10281 | return fail(); | |||
| 10282 | for (int vi = 0; vi < parsedNumVerts; ++vi) { | |||
| 10283 | DRW_MLineVertex vtx; | |||
| 10284 | if (!readBoundedBitCoord(*buf, bodyEndBit, vtx.position) | |||
| 10285 | || !readBoundedBitCoord(*buf, bodyEndBit, vtx.vertexDir) | |||
| 10286 | || !readBoundedBitCoord(*buf, bodyEndBit, vtx.miterDir)) | |||
| 10287 | return fail(); | |||
| 10288 | if (!DRW::reserve(vtx.segParms, parsedNumLines) | |||
| 10289 | || !DRW::reserve(vtx.areaFillParms, parsedNumLines)) | |||
| 10290 | return fail(); | |||
| 10291 | if (!DRW::resize(vtx.segParms, parsedNumLines) | |||
| 10292 | || !DRW::resize(vtx.areaFillParms, parsedNumLines)) | |||
| 10293 | return fail(); | |||
| 10294 | for (int li = 0; li < parsedNumLines; ++li) { | |||
| 10295 | std::uint16_t nSeg = 0; | |||
| 10296 | if (!readBoundedBitShort(*buf, bodyEndBit, nSeg) | |||
| 10297 | || !proxyEntityHasBits(*buf, bodyEndBit, | |||
| 10298 | static_cast<std::uint64_t>(nSeg) * 2u)) | |||
| 10299 | return fail(); | |||
| 10300 | if (!buf->isGood() | |||
| 10301 | || !isValidCount(static_cast<std::int32_t>(nSeg), | |||
| 10302 | kMaxDxfParameters) | |||
| 10303 | || totalParameters > kMaxDwgParameters - nSeg) | |||
| 10304 | return fail(); | |||
| 10305 | totalParameters += nSeg; | |||
| 10306 | if (!DRW::reserve(vtx.segParms[li], nSeg)) | |||
| 10307 | return fail(); | |||
| 10308 | for (int s = 0; s < nSeg; ++s) { | |||
| 10309 | double value = 0.0; | |||
| 10310 | if (!readBoundedBitDouble(*buf, bodyEndBit, value) | |||
| 10311 | || !std::isfinite(value)) | |||
| 10312 | return fail(); | |||
| 10313 | vtx.segParms[li].push_back(value); | |||
| 10314 | } | |||
| 10315 | std::uint16_t nFill = 0; | |||
| 10316 | if (!readBoundedBitShort(*buf, bodyEndBit, nFill) | |||
| 10317 | || !proxyEntityHasBits(*buf, bodyEndBit, | |||
| 10318 | static_cast<std::uint64_t>(nFill) * 2u)) | |||
| 10319 | return fail(); | |||
| 10320 | if (!buf->isGood() | |||
| 10321 | || !isValidCount(static_cast<std::int32_t>(nFill), | |||
| 10322 | kMaxDxfParameters) | |||
| 10323 | || totalParameters > kMaxDwgParameters - nFill) | |||
| 10324 | return fail(); | |||
| 10325 | totalParameters += nFill; | |||
| 10326 | if (!DRW::reserve(vtx.areaFillParms[li], nFill)) | |||
| 10327 | return fail(); | |||
| 10328 | for (int f = 0; f < nFill; ++f) { | |||
| 10329 | double value = 0.0; | |||
| 10330 | if (!readBoundedBitDouble(*buf, bodyEndBit, value) | |||
| 10331 | || !std::isfinite(value)) | |||
| 10332 | return fail(); | |||
| 10333 | vtx.areaFillParms[li].push_back(value); | |||
| 10334 | } | |||
| 10335 | } | |||
| 10336 | const auto finite = [](const DRW_Coord& point) { | |||
| 10337 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 10338 | && std::isfinite(point.z); | |||
| 10339 | }; | |||
| 10340 | if (!finite(vtx.position) || !finite(vtx.vertexDir) | |||
| 10341 | || !finite(vtx.miterDir)) | |||
| 10342 | return fail(); | |||
| 10343 | parsedVertices.push_back(std::move(vtx)); | |||
| 10344 | } | |||
| 10345 | if (!buf->isGood()) | |||
| 10346 | return fail(); | |||
| 10347 | ||||
| 10348 | std::uint64_t handleEndBit = 0; | |||
| 10349 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, | |||
| 10350 | handleEndBit)) | |||
| 10351 | return fail(); | |||
| 10352 | dwgBuffer handleProbe = buf->forkIndependent(); | |||
| 10353 | if (!DRW_Entity::parseDwgEntHandle(version, &handleProbe, true, | |||
| 10354 | handleEndBit)) | |||
| 10355 | return fail(); | |||
| 10356 | // MLINE has one extra handle in the handle stream after the standard | |||
| 10357 | // entity handles: the MLINESTYLE reference. Read if available — some | |||
| 10358 | // older files (R14) store the style name inline instead. | |||
| 10359 | std::uint32_t parsedStyleHandle = 0; | |||
| 10360 | if (version > DRW::AC1014 | |||
| 10361 | && proxyEntityHasBits(handleProbe, handleEndBit, 8)) { | |||
| 10362 | dwgHandle styleH; | |||
| 10363 | if (!readBoundedDwgHandle(handleProbe, handleEndBit, handle, true, | |||
| 10364 | styleH)) | |||
| 10365 | return fail(); | |||
| 10366 | if (!handleProbe.isGood()) | |||
| 10367 | return fail(); | |||
| 10368 | parsedStyleHandle = styleH.ref; | |||
| 10369 | DRW_DBG(" MLINE style handle: ")DRW_dbg::dbg(" MLINE style handle: "); | |||
| 10370 | DRW_DBGHL(styleH.code, styleH.size, styleH.ref)DRW_dbg::dbgHL(styleH.code, styleH.size, styleH.ref); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 10371 | } | |||
| 10372 | if (!handleProbe.isGood()) | |||
| 10373 | return fail(); | |||
| 10374 | *sourceBuf = handleProbe; | |||
| 10375 | scale = parsedScale; | |||
| 10376 | justification = parsedJustification; | |||
| 10377 | basePoint = parsedBasePoint; | |||
| 10378 | extPoint = parsedExtPoint; | |||
| 10379 | openClosed = parsedOpenClosed; | |||
| 10380 | numLines = parsedNumLines; | |||
| 10381 | numVerts = parsedNumVerts; | |||
| 10382 | styleHandle = parsedStyleHandle; | |||
| 10383 | vertlist = std::move(parsedVertices); | |||
| 10384 | return true; | |||
| 10385 | } | |||
| 10386 | ||||
| 10387 | ||||
| 10388 | // ---------------------------------------------------------------------------- | |||
| 10389 | // DRW_Underlay — UNDERLAY entity (PDFUNDERLAY/DGNUNDERLAY/DWFUNDERLAY). | |||
| 10390 | // libreDWG UNDERLAYREFERENCE.spec field order: | |||
| 10391 | // extrusion (BE) -> position (3BD) -> angle (BD radians) -> scale (BD x 3) | |||
| 10392 | // -> flags (RC) -> contrast (RC) -> fade (RC) -> num_clip (BL) | |||
| 10393 | // -> clip_verts (2RD × num_clip). | |||
| 10394 | // Handle stream after standard entity handles: definition_id (H). | |||
| 10395 | // ---------------------------------------------------------------------------- | |||
| 10396 | ||||
| 10397 | bool DRW_Underlay::parseCode(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 10398 | switch (code) { | |||
| 10399 | case 340: | |||
| 10400 | definitionHandle = static_cast<std::uint32_t>(reader->getHandleString()); | |||
| 10401 | break; | |||
| 10402 | case 10: position.x = reader->getDouble(); break; | |||
| 10403 | case 20: position.y = reader->getDouble(); break; | |||
| 10404 | case 30: position.z = reader->getDouble(); break; | |||
| 10405 | case 41: scale.x = reader->getDouble(); break; | |||
| 10406 | case 42: scale.y = reader->getDouble(); break; | |||
| 10407 | case 43: scale.z = reader->getDouble(); break; | |||
| 10408 | case 50: rotation = reader->getDouble(); break; // degrees in DXF | |||
| 10409 | case 210: extPoint.x = reader->getDouble(); break; | |||
| 10410 | case 220: extPoint.y = reader->getDouble(); break; | |||
| 10411 | case 230: extPoint.z = reader->getDouble(); break; | |||
| 10412 | case 280: { | |||
| 10413 | int value = 0; | |||
| 10414 | if (!readDxfIntInRange(reader, 0, 0xFF, value)) | |||
| 10415 | return false; | |||
| 10416 | flags = static_cast<std::uint8_t>(value); | |||
| 10417 | break; | |||
| 10418 | } | |||
| 10419 | case 281: { | |||
| 10420 | int value = 0; | |||
| 10421 | if (!readDxfIntInRange(reader, 0, 100, value)) | |||
| 10422 | return false; | |||
| 10423 | contrast = static_cast<std::uint8_t>(value); | |||
| 10424 | break; | |||
| 10425 | } | |||
| 10426 | case 282: { | |||
| 10427 | int value = 0; | |||
| 10428 | if (!readDxfIntInRange(reader, 0, 100, value)) | |||
| 10429 | return false; | |||
| 10430 | fade = static_cast<std::uint8_t>(value); | |||
| 10431 | break; | |||
| 10432 | } | |||
| 10433 | case 11: { | |||
| 10434 | if (clipBoundary.size() >= kMaxClipVertices) | |||
| 10435 | return false; | |||
| 10436 | ++m_currentClipVertexIdx; | |||
| 10437 | if (m_currentClipVertexIdx >= static_cast<int>(clipBoundary.size())) { | |||
| 10438 | if (!DRW::resize(clipBoundary, m_currentClipVertexIdx + 1)) | |||
| 10439 | return false; | |||
| 10440 | } | |||
| 10441 | clipBoundary[m_currentClipVertexIdx].x = reader->getDouble(); | |||
| 10442 | break; | |||
| 10443 | } | |||
| 10444 | case 21: | |||
| 10445 | if (m_currentClipVertexIdx >= 0 | |||
| 10446 | && m_currentClipVertexIdx < static_cast<int>(clipBoundary.size())) { | |||
| 10447 | clipBoundary[m_currentClipVertexIdx].y = reader->getDouble(); | |||
| 10448 | } | |||
| 10449 | break; | |||
| 10450 | case 170: { | |||
| 10451 | const int count = reader->getInt32(); | |||
| 10452 | if (!isValidCount(count, static_cast<std::int32_t>(kMaxClipVertices))) | |||
| 10453 | return false; | |||
| 10454 | m_inverseClipVertexCount = static_cast<std::uint32_t>(count); | |||
| 10455 | m_inverseClipCountSeen = true; | |||
| 10456 | if (!DRW::reserve(inverseClipBoundary, count)) | |||
| 10457 | return false; | |||
| 10458 | break; | |||
| 10459 | } | |||
| 10460 | case 12: { | |||
| 10461 | if (inverseClipBoundary.size() >= kMaxClipVertices | |||
| 10462 | || (m_inverseClipCountSeen | |||
| 10463 | && inverseClipBoundary.size() >= m_inverseClipVertexCount)) | |||
| 10464 | return false; | |||
| 10465 | ++m_currentInverseClipVertexIdx; | |||
| 10466 | if (m_currentInverseClipVertexIdx | |||
| 10467 | >= static_cast<int>(inverseClipBoundary.size())) { | |||
| 10468 | if (!DRW::resize(inverseClipBoundary, | |||
| 10469 | m_currentInverseClipVertexIdx + 1)) | |||
| 10470 | return false; | |||
| 10471 | } | |||
| 10472 | inverseClipBoundary[m_currentInverseClipVertexIdx].x = reader->getDouble(); | |||
| 10473 | break; | |||
| 10474 | } | |||
| 10475 | case 22: | |||
| 10476 | if (m_currentInverseClipVertexIdx >= 0 | |||
| 10477 | && m_currentInverseClipVertexIdx | |||
| 10478 | < static_cast<int>(inverseClipBoundary.size())) { | |||
| 10479 | inverseClipBoundary[m_currentInverseClipVertexIdx].y = reader->getDouble(); | |||
| 10480 | } | |||
| 10481 | break; | |||
| 10482 | default: | |||
| 10483 | return DRW_Entity::parseCode(code, reader); | |||
| 10484 | } | |||
| 10485 | return true; | |||
| 10486 | } | |||
| 10487 | ||||
| 10488 | void DRW_Underlay::resetDwgState() { | |||
| 10489 | DRW_Entity::reset(); | |||
| 10490 | // Entity carriers can be reused by callers. Clip payloads and their | |||
| 10491 | // parser counters belong to this record, not to the carrier lifetime. | |||
| 10492 | position = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 10493 | scale = DRW_Coord{1.0, 1.0, 1.0}; | |||
| 10494 | rotation = 0.0; | |||
| 10495 | extPoint = DRW_Coord{0.0, 0.0, 1.0}; | |||
| 10496 | flags = 2; | |||
| 10497 | contrast = 100; | |||
| 10498 | fade = 0; | |||
| 10499 | clipBoundary.clear(); | |||
| 10500 | inverseClipBoundary.clear(); | |||
| 10501 | m_currentClipVertexIdx = -1; | |||
| 10502 | m_currentInverseClipVertexIdx = -1; | |||
| 10503 | m_inverseClipVertexCount = 0; | |||
| 10504 | m_inverseClipCountSeen = false; | |||
| 10505 | definitionHandle = 0; | |||
| 10506 | } | |||
| 10507 | ||||
| 10508 | bool DRW_Underlay::validatePayloadFields() const { | |||
| 10509 | const auto finite = [](const DRW_Coord& point) { | |||
| 10510 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 10511 | && std::isfinite(point.z); | |||
| 10512 | }; | |||
| 10513 | const auto finiteClipPoint = [](const DRW_Coord& point) { | |||
| 10514 | return std::isfinite(point.x) && std::isfinite(point.y); | |||
| 10515 | }; | |||
| 10516 | return finite(position) && finite(scale) && finite(extPoint) | |||
| 10517 | && std::isfinite(rotation) | |||
| 10518 | && std::all_of(clipBoundary.cbegin(), clipBoundary.cend(), | |||
| 10519 | finiteClipPoint) | |||
| 10520 | && std::all_of(inverseClipBoundary.cbegin(), | |||
| 10521 | inverseClipBoundary.cend(), finiteClipPoint); | |||
| 10522 | } | |||
| 10523 | ||||
| 10524 | bool DRW_Underlay::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){ | |||
| 10525 | resetDwgState(); | |||
| 10526 | dwgBuffer *sourceBuf = buf; | |||
| 10527 | auto fail = [this, sourceBuf]() { | |||
| 10528 | if (sourceBuf != nullptr) | |||
| 10529 | sourceBuf->invalidate(); | |||
| 10530 | resetDwgState(); | |||
| 10531 | return false; | |||
| 10532 | }; | |||
| 10533 | if (sourceBuf == nullptr) | |||
| 10534 | return fail(); | |||
| 10535 | ||||
| 10536 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 10537 | buf = &bodyProbe; | |||
| 10538 | ||||
| 10539 | if (!DRW_Entity::parseDwgCommon(version, buf, bs)) return fail(); | |||
| 10540 | DRW_DBG("\n***************************** parsing UNDERLAY ***************\n")DRW_dbg::dbg("\n***************************** parsing UNDERLAY ***************\n" ); | |||
| 10541 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 10542 | DRW_Coord parsedExtPoint; | |||
| 10543 | DRW_Coord parsedPosition; | |||
| 10544 | DRW_Coord parsedScale; | |||
| 10545 | double parsedRotation = 0.0; | |||
| 10546 | std::uint8_t parsedFlags = 0; | |||
| 10547 | std::uint8_t parsedContrast = 0; | |||
| 10548 | std::uint8_t parsedFade = 0; | |||
| 10549 | if (!readBoundedExtrusion(*buf, bodyEndBit, false, parsedExtPoint) | |||
| 10550 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedPosition) | |||
| 10551 | || !readBoundedBitDouble(*buf, bodyEndBit, parsedRotation) | |||
| 10552 | || !readBoundedBitDouble(*buf, bodyEndBit, parsedScale.x) | |||
| 10553 | || !readBoundedBitDouble(*buf, bodyEndBit, parsedScale.y) | |||
| 10554 | || !readBoundedBitDouble(*buf, bodyEndBit, parsedScale.z) | |||
| 10555 | || !readBoundedRawChar8(*buf, bodyEndBit, parsedFlags) | |||
| 10556 | || !readBoundedRawChar8(*buf, bodyEndBit, parsedContrast) | |||
| 10557 | || !readBoundedRawChar8(*buf, bodyEndBit, parsedFade)) | |||
| 10558 | return fail(); | |||
| 10559 | const auto finite = [](const DRW_Coord& point) { | |||
| 10560 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 10561 | && std::isfinite(point.z); | |||
| 10562 | }; | |||
| 10563 | if (!finite(parsedExtPoint) || !finite(parsedPosition) | |||
| 10564 | || !finite(parsedScale) || !std::isfinite(parsedRotation)) | |||
| 10565 | return fail(); | |||
| 10566 | std::uint32_t nClip = 0; | |||
| 10567 | DRW_DBG(" UNDERLAY pos: ")DRW_dbg::dbg(" UNDERLAY pos: "); DRW_DBG(parsedPosition.x)DRW_dbg::dbg(parsedPosition.x); DRW_DBG(",")DRW_dbg::dbg(","); | |||
| 10568 | DRW_DBG(parsedPosition.y)DRW_dbg::dbg(parsedPosition.y); DRW_DBG(" rot: ")DRW_dbg::dbg(" rot: "); DRW_DBG(parsedRotation)DRW_dbg::dbg(parsedRotation); | |||
| 10569 | DRW_DBG(" flags: ")DRW_dbg::dbg(" flags: "); DRW_DBGH(parsedFlags)DRW_dbg::dbgH(parsedFlags); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 10570 | if (!readTableBodyCount(version, buf, objSize, kMaxClipVertices, 128, | |||
| 10571 | nClip) | |||
| 10572 | || !proxyEntityHasBits(*buf, bodyEndBit, | |||
| 10573 | static_cast<std::uint64_t>(nClip) * 128u)) | |||
| 10574 | return fail(); | |||
| 10575 | std::vector<DRW_Coord> parsedClipBoundary; | |||
| 10576 | if (!DRW::reserve(parsedClipBoundary, static_cast<std::size_t>(nClip))) | |||
| 10577 | return fail(); | |||
| 10578 | for (std::uint32_t i = 0; i < nClip; ++i) { | |||
| 10579 | DRW_Coord p; | |||
| 10580 | if (!readBoundedRawDouble(*buf, bodyEndBit, p.x) | |||
| 10581 | || !readBoundedRawDouble(*buf, bodyEndBit, p.y) | |||
| 10582 | || !std::isfinite(p.x) || !std::isfinite(p.y)) | |||
| 10583 | return fail(); | |||
| 10584 | p.z = 0.0; | |||
| 10585 | parsedClipBoundary.push_back(p); | |||
| 10586 | } | |||
| 10587 | std::vector<DRW_Coord> parsedInverseClipBoundary; | |||
| 10588 | if (version > DRW::AC1021 && (parsedFlags & 0x10) != 0) { | |||
| 10589 | std::uint16_t nInverse = 0; | |||
| 10590 | if (!readBoundedBitShort(*buf, bodyEndBit, nInverse) | |||
| 10591 | || nInverse > kMaxClipVertices | |||
| 10592 | || !proxyEntityHasBits( | |||
| 10593 | *buf, bodyEndBit, | |||
| 10594 | static_cast<std::uint64_t>(nInverse) * 128u) | |||
| 10595 | || !DRW::reserve(parsedInverseClipBoundary, | |||
| 10596 | static_cast<std::size_t>(nInverse))) | |||
| 10597 | return fail(); | |||
| 10598 | for (std::uint16_t i = 0; i < nInverse; ++i) { | |||
| 10599 | DRW_Coord p; | |||
| 10600 | if (!readBoundedRawDouble(*buf, bodyEndBit, p.x) | |||
| 10601 | || !readBoundedRawDouble(*buf, bodyEndBit, p.y) | |||
| 10602 | || !std::isfinite(p.x) || !std::isfinite(p.y)) | |||
| 10603 | return fail(); | |||
| 10604 | p.z = 0.0; | |||
| 10605 | parsedInverseClipBoundary.push_back(p); | |||
| 10606 | } | |||
| 10607 | } | |||
| 10608 | if (!buf->isGood()) | |||
| 10609 | return fail(); | |||
| 10610 | ||||
| 10611 | std::uint64_t handleEndBit = 0; | |||
| 10612 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, | |||
| 10613 | handleEndBit)) | |||
| 10614 | return fail(); | |||
| 10615 | dwgBuffer handleProbe = buf->forkIndependent(); | |||
| 10616 | if (!DRW_Entity::parseDwgEntHandle(version, &handleProbe, true, | |||
| 10617 | handleEndBit)) | |||
| 10618 | return fail(); | |||
| 10619 | std::uint32_t parsedDefinitionHandle = 0; | |||
| 10620 | if (version > DRW::AC1014 | |||
| 10621 | && proxyEntityHasBits(handleProbe, handleEndBit, 16)) { | |||
| 10622 | dwgHandle defH; | |||
| 10623 | if (!readBoundedDwgHandle(handleProbe, handleEndBit, handle, true, | |||
| 10624 | defH)) | |||
| 10625 | return fail(); | |||
| 10626 | if (!handleProbe.isGood()) | |||
| 10627 | return fail(); | |||
| 10628 | parsedDefinitionHandle = defH.ref; | |||
| 10629 | DRW_DBG(" UNDERLAY definitionHandle: ")DRW_dbg::dbg(" UNDERLAY definitionHandle: "); | |||
| 10630 | DRW_DBGHL(defH.code, defH.size, defH.ref)DRW_dbg::dbgHL(defH.code, defH.size, defH.ref); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 10631 | } | |||
| 10632 | if (!handleProbe.isGood()) | |||
| 10633 | return fail(); | |||
| 10634 | *sourceBuf = handleProbe; | |||
| 10635 | extPoint = parsedExtPoint; | |||
| 10636 | position = parsedPosition; | |||
| 10637 | rotation = parsedRotation; | |||
| 10638 | scale = parsedScale; | |||
| 10639 | flags = parsedFlags; | |||
| 10640 | contrast = parsedContrast; | |||
| 10641 | fade = parsedFade; | |||
| 10642 | clipBoundary = std::move(parsedClipBoundary); | |||
| 10643 | inverseClipBoundary = std::move(parsedInverseClipBoundary); | |||
| 10644 | definitionHandle = parsedDefinitionHandle; | |||
| 10645 | return true; | |||
| 10646 | } | |||
| 10647 | ||||
| 10648 | bool DRW_Underlay::encodeDwg(DRW::Version version, dwgBufferW *buf, | |||
| 10649 | std::uint32_t bs, dwgBufferW *strBuf, | |||
| 10650 | dwgBufferW *handleBuf) { | |||
| 10651 | (void)bs; (void)strBuf; | |||
| 10652 | if (!validatePayloadFields() | |||
| 10653 | || clipBoundary.size() > kMaxClipVertices | |||
| 10654 | || inverseClipBoundary.size() > kMaxClipVertices | |||
| 10655 | || (version <= DRW::AC1021 && !inverseClipBoundary.empty())) | |||
| 10656 | return false; | |||
| 10657 | ||||
| 10658 | switch (kind) { | |||
| 10659 | case DGN: | |||
| 10660 | oType = kDwgClassNumDgn; | |||
| 10661 | break; | |||
| 10662 | case DWF: | |||
| 10663 | oType = kDwgClassNumDwf; | |||
| 10664 | break; | |||
| 10665 | case PDF: | |||
| 10666 | default: | |||
| 10667 | oType = kDwgClassNumPdf; | |||
| 10668 | break; | |||
| 10669 | } | |||
| 10670 | if (!encodeDwgCommon(version, buf)) | |||
| 10671 | return false; | |||
| 10672 | ||||
| 10673 | const bool hasInverseClip = !inverseClipBoundary.empty() || (flags & 0x10) != 0; | |||
| 10674 | const std::uint8_t wireFlags = | |||
| 10675 | hasInverseClip ? static_cast<std::uint8_t>(flags | 0x10) : flags; | |||
| 10676 | ||||
| 10677 | buf->putExtrusion(extPoint, false); | |||
| 10678 | buf->put3BitDouble(position); | |||
| 10679 | buf->putBitDouble(rotation); | |||
| 10680 | buf->putBitDouble(scale.x); | |||
| 10681 | buf->putBitDouble(scale.y); | |||
| 10682 | buf->putBitDouble(scale.z); | |||
| 10683 | buf->putRawChar8(wireFlags); | |||
| 10684 | buf->putRawChar8(contrast); | |||
| 10685 | buf->putRawChar8(fade); | |||
| 10686 | buf->putBitLong(static_cast<std::int32_t>(clipBoundary.size())); | |||
| 10687 | for (const auto& vertex : clipBoundary) { | |||
| 10688 | buf->putRawDouble(vertex.x); | |||
| 10689 | buf->putRawDouble(vertex.y); | |||
| 10690 | } | |||
| 10691 | if (version > DRW::AC1021 && hasInverseClip) { | |||
| 10692 | buf->putBitShort(static_cast<std::uint16_t>(inverseClipBoundary.size())); | |||
| 10693 | for (const auto& vertex : inverseClipBoundary) { | |||
| 10694 | buf->putRawDouble(vertex.x); | |||
| 10695 | buf->putRawDouble(vertex.y); | |||
| 10696 | } | |||
| 10697 | } | |||
| 10698 | ||||
| 10699 | if (!encodeDwgEntHandle(version, buf, handleBuf)) | |||
| 10700 | return false; | |||
| 10701 | putNullableHardPointerHandle(handleBuf ? handleBuf : buf, definitionHandle); | |||
| 10702 | return true; | |||
| 10703 | } | |||
| 10704 | ||||
| 10705 | ||||
| 10706 | bool DRW_Text::parseCode(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 10707 | switch (code) { | |||
| 10708 | case 40: | |||
| 10709 | height = reader->getDouble(); | |||
| 10710 | break; | |||
| 10711 | case 41: | |||
| 10712 | widthscale = reader->getDouble(); | |||
| 10713 | break; | |||
| 10714 | case 50: | |||
| 10715 | angle = reader->getDouble(); | |||
| 10716 | break; | |||
| 10717 | case 51: | |||
| 10718 | oblique = reader->getDouble(); | |||
| 10719 | break; | |||
| 10720 | case 71: | |||
| 10721 | textgen = reader->getInt32(); | |||
| 10722 | break; | |||
| 10723 | case 72: | |||
| 10724 | alignH = (HAlign)reader->getInt32(); | |||
| 10725 | break; | |||
| 10726 | case 73: | |||
| 10727 | alignV = (VAlign)reader->getInt32(); | |||
| 10728 | break; | |||
| 10729 | case 1: | |||
| 10730 | text = reader->getUtf8String(); | |||
| 10731 | break; | |||
| 10732 | case 7: | |||
| 10733 | style = reader->getUtf8String(); | |||
| 10734 | break; | |||
| 10735 | default: | |||
| 10736 | return DRW_Line::parseCode(code, reader); | |||
| 10737 | } | |||
| 10738 | ||||
| 10739 | return true; | |||
| 10740 | } | |||
| 10741 | ||||
| 10742 | void DRW_Text::resetDwgState() { | |||
| 10743 | DRW_Entity::reset(); | |||
| 10744 | basePoint = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 10745 | secPoint = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 10746 | thickness = 0.0; | |||
| 10747 | extPoint = DRW_Coord{0.0, 0.0, 1.0}; | |||
| 10748 | xAxisAngle = 0.0; | |||
| 10749 | height = 0.0; | |||
| 10750 | text.clear(); | |||
| 10751 | angle = 0.0; | |||
| 10752 | widthscale = 1.0; | |||
| 10753 | oblique = 0.0; | |||
| 10754 | style = "STANDARD"; | |||
| 10755 | textgen = 0; | |||
| 10756 | alignH = HLeft; | |||
| 10757 | alignV = VBaseLine; | |||
| 10758 | styleH = dwgHandle{}; | |||
| 10759 | } | |||
| 10760 | ||||
| 10761 | bool DRW_Text::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){ | |||
| 10762 | resetDwgState(); | |||
| 10763 | dwgBuffer *sourceBuf = buf; | |||
| 10764 | auto fail = [this, sourceBuf]() { | |||
| 10765 | if (sourceBuf != nullptr) | |||
| 10766 | sourceBuf->invalidate(); | |||
| 10767 | resetDwgState(); | |||
| 10768 | return false; | |||
| 10769 | }; | |||
| 10770 | if (sourceBuf == nullptr) | |||
| 10771 | return fail(); | |||
| 10772 | ||||
| 10773 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 10774 | buf = &bodyProbe; | |||
| 10775 | dwgBuffer sBuff = buf->forkIndependent(); | |||
| 10776 | dwgBuffer *sBuf = buf; | |||
| 10777 | if (version > DRW::AC1018) {//2007+ | |||
| 10778 | sBuf = &sBuff; //separate buffer for strings | |||
| 10779 | } | |||
| 10780 | bool ret = DRW_Entity::parseDwg(version, buf, sBuf, bs); | |||
| 10781 | if (!ret) | |||
| 10782 | return fail(); | |||
| 10783 | DRW_DBG("\n***************************** parsing text *********************************************\n")DRW_dbg::dbg("\n***************************** parsing text *********************************************\n" ); | |||
| 10784 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 10785 | ||||
| 10786 | // DataFlags RC Used to determine presence of subsequent data, set to 0xFF for R14- | |||
| 10787 | std::uint8_t data_flags = 0x00; | |||
| 10788 | if (version > DRW::AC1014) {//2000+ | |||
| 10789 | if (!readBoundedRawChar8(*buf, bodyEndBit, data_flags)) | |||
| 10790 | return fail(); /* DataFlags RC Used to determine presence of subsequent data */ | |||
| 10791 | DRW_DBG("data_flags: ")DRW_dbg::dbg("data_flags: "); DRW_DBG(data_flags)DRW_dbg::dbg(data_flags); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 10792 | if ( !(data_flags & 0x01) ) { /* Elevation RD --- present if !(DataFlags & 0x01) */ | |||
| 10793 | if (!readBoundedRawDouble(*buf, bodyEndBit, basePoint.z)) | |||
| 10794 | return fail(); | |||
| 10795 | } | |||
| 10796 | } else {//14- | |||
| 10797 | if (!readBoundedBitDouble(*buf, bodyEndBit, basePoint.z)) | |||
| 10798 | return fail(); /* Elevation BD --- */ | |||
| 10799 | } | |||
| 10800 | if (!readBoundedRawDouble(*buf, bodyEndBit, basePoint.x) | |||
| 10801 | || !readBoundedRawDouble(*buf, bodyEndBit, basePoint.y)) | |||
| 10802 | return fail(); /* Insertion pt 2RD 10 */ | |||
| 10803 | DRW_DBG("Insert point: ")DRW_dbg::dbg("Insert point: "); DRW_DBGPT(basePoint.x, basePoint.y, basePoint.z)DRW_dbg::dbgPT(basePoint.x, basePoint.y, basePoint.z); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 10804 | if (version > DRW::AC1014) {//2000+ | |||
| 10805 | if ( !(data_flags & 0x02) ) { /* Alignment pt 2DD 11 present if !(DataFlags & 0x02), use 10 & 20 values for 2 default values.*/ | |||
| 10806 | if (!readBoundedDefaultDouble(*buf, bodyEndBit, basePoint.x, | |||
| 10807 | secPoint.x) | |||
| 10808 | || !readBoundedDefaultDouble(*buf, bodyEndBit, basePoint.y, | |||
| 10809 | secPoint.y)) | |||
| 10810 | return fail(); | |||
| 10811 | } else { | |||
| 10812 | secPoint = basePoint; | |||
| 10813 | } | |||
| 10814 | } else {//14- | |||
| 10815 | if (!readBoundedRawDouble(*buf, bodyEndBit, secPoint.x) | |||
| 10816 | || !readBoundedRawDouble(*buf, bodyEndBit, secPoint.y)) | |||
| 10817 | return fail(); /* Alignment pt 2RD 11 */ | |||
| 10818 | } | |||
| 10819 | secPoint.z = basePoint.z; | |||
| 10820 | DRW_DBG("Alignment: ")DRW_dbg::dbg("Alignment: "); DRW_DBGPT(secPoint.x, secPoint.y, basePoint.z)DRW_dbg::dbgPT(secPoint.x, secPoint.y, basePoint.z); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 10821 | if (!readBoundedExtrusion(*buf, bodyEndBit, version > DRW::AC1014, | |||
| 10822 | extPoint)) | |||
| 10823 | return fail(); | |||
| 10824 | DRW_DBG("Extrusion: ")DRW_dbg::dbg("Extrusion: "); DRW_DBGPT(extPoint.x, extPoint.y, extPoint.z)DRW_dbg::dbgPT(extPoint.x, extPoint.y, extPoint.z); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 10825 | if (!readBoundedThickness(*buf, bodyEndBit, version > DRW::AC1014, | |||
| 10826 | thickness)) | |||
| 10827 | return fail(); /* Thickness BD 39 */ | |||
| 10828 | ||||
| 10829 | if (version > DRW::AC1014) {//2000+ | |||
| 10830 | if ( !(data_flags & 0x04) ) { /* Oblique ang RD 51 present if !(DataFlags & 0x04) */ | |||
| 10831 | if (!readBoundedRawDouble(*buf, bodyEndBit, oblique)) | |||
| 10832 | return fail(); | |||
| 10833 | } | |||
| 10834 | if ( !(data_flags & 0x08) ) { /* Rotation ang RD 50 present if !(DataFlags & 0x08) */ | |||
| 10835 | if (!readBoundedRawDouble(*buf, bodyEndBit, angle)) | |||
| 10836 | return fail(); | |||
| 10837 | } | |||
| 10838 | if (!readBoundedRawDouble(*buf, bodyEndBit, height)) | |||
| 10839 | return fail(); /* Height RD 40 */ | |||
| 10840 | if ( !(data_flags & 0x10) ) { /* Width factor RD 41 present if !(DataFlags & 0x10) */ | |||
| 10841 | if (!readBoundedRawDouble(*buf, bodyEndBit, widthscale)) | |||
| 10842 | return fail(); | |||
| 10843 | } | |||
| 10844 | } else {//14- | |||
| 10845 | if (!readBoundedBitDouble(*buf, bodyEndBit, oblique) | |||
| 10846 | || !readBoundedBitDouble(*buf, bodyEndBit, angle) | |||
| 10847 | || !readBoundedBitDouble(*buf, bodyEndBit, height) | |||
| 10848 | || !readBoundedBitDouble(*buf, bodyEndBit, widthscale)) | |||
| 10849 | return fail(); /* Oblique/rotation/height/width BD */ | |||
| 10850 | } | |||
| 10851 | angle *= ARAD57.29577951308232; | |||
| 10852 | if (!std::isfinite(basePoint.x) || !std::isfinite(basePoint.y) | |||
| 10853 | || !std::isfinite(basePoint.z) || !std::isfinite(secPoint.x) | |||
| 10854 | || !std::isfinite(secPoint.y) || !std::isfinite(secPoint.z) | |||
| 10855 | || !std::isfinite(extPoint.x) || !std::isfinite(extPoint.y) | |||
| 10856 | || !std::isfinite(extPoint.z) || !std::isfinite(thickness) | |||
| 10857 | || !std::isfinite(oblique) || !std::isfinite(angle) | |||
| 10858 | || !std::isfinite(height) || !std::isfinite(widthscale)) | |||
| 10859 | return fail(); | |||
| 10860 | DRW_DBG("thickness: ")DRW_dbg::dbg("thickness: "); DRW_DBG(thickness)DRW_dbg::dbg(thickness); DRW_DBG(", Oblique ang: ")DRW_dbg::dbg(", Oblique ang: "); DRW_DBG(oblique)DRW_dbg::dbg(oblique); DRW_DBG(", Width: ")DRW_dbg::dbg(", Width: "); | |||
| 10861 | DRW_DBG(widthscale)DRW_dbg::dbg(widthscale); DRW_DBG(", Rotation: ")DRW_dbg::dbg(", Rotation: "); DRW_DBG(angle)DRW_dbg::dbg(angle); DRW_DBG(", height: ")DRW_dbg::dbg(", height: "); DRW_DBG(height)DRW_dbg::dbg(height); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 10862 | std::uint64_t stringEndBit = bodyEndBit; | |||
| 10863 | if (version > DRW::AC1021) { | |||
| 10864 | std::uint64_t ignoredBodyEndBit = 0; | |||
| 10865 | if (!entityBodyDataEndBit(*sBuf, version, objSize, | |||
| 10866 | ignoredBodyEndBit, &stringEndBit)) | |||
| 10867 | return fail(); | |||
| 10868 | } | |||
| 10869 | UTF8STRINGstd::string parsedText; | |||
| 10870 | if (version > DRW::AC1018 | |||
| 10871 | && currentDwgBit(sBuf) >= stringEndBit) { | |||
| 10872 | parsedText.clear(); | |||
| 10873 | } else if (!readBoundedVariableText(*sBuf, stringEndBit, version, | |||
| 10874 | parsedText)) { | |||
| 10875 | return fail(); | |||
| 10876 | } | |||
| 10877 | DRW_DBG("text string: ")DRW_dbg::dbg("text string: "); DRW_DBG(parsedText.c_str())DRW_dbg::dbg(parsedText.c_str());DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 10878 | //textgen, alignH, alignV always present in R14-, data_flags set in initialisation | |||
| 10879 | if ( !(data_flags & 0x20) ) { /* Generation BS 71 present if !(DataFlags & 0x20) */ | |||
| 10880 | std::uint16_t parsedTextgen = 0; | |||
| 10881 | if (!readBoundedBitShort(*buf, bodyEndBit, parsedTextgen)) | |||
| 10882 | return fail(); | |||
| 10883 | textgen = parsedTextgen; | |||
| 10884 | DRW_DBG("textgen: ")DRW_dbg::dbg("textgen: "); DRW_DBG(textgen)DRW_dbg::dbg(textgen); | |||
| 10885 | } | |||
| 10886 | if ( !(data_flags & 0x40) ) { /* Horiz align. BS 72 present if !(DataFlags & 0x40) */ | |||
| 10887 | std::uint16_t parsedAlignH = 0; | |||
| 10888 | if (!readBoundedBitShort(*buf, bodyEndBit, parsedAlignH)) | |||
| 10889 | return fail(); | |||
| 10890 | alignH = static_cast<HAlign>(parsedAlignH); | |||
| 10891 | DRW_DBG(", alignH: ")DRW_dbg::dbg(", alignH: "); DRW_DBG(alignH)DRW_dbg::dbg(alignH); | |||
| 10892 | } | |||
| 10893 | if ( !(data_flags & 0x80) ) { /* Vert align. BS 73 present if !(DataFlags & 0x80) */ | |||
| 10894 | std::uint16_t parsedAlignV = 0; | |||
| 10895 | if (!readBoundedBitShort(*buf, bodyEndBit, parsedAlignV)) | |||
| 10896 | return fail(); | |||
| 10897 | alignV = static_cast<VAlign>(parsedAlignV); | |||
| 10898 | DRW_DBG(", alignV: ")DRW_dbg::dbg(", alignV: "); DRW_DBG(alignV)DRW_dbg::dbg(alignV); | |||
| 10899 | } | |||
| 10900 | DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 10901 | ||||
| 10902 | if (!buf->isGood() || !sBuf->isGood() | |||
| 10903 | || currentDwgBit(buf) > bodyEndBit | |||
| 10904 | || currentDwgBit(sBuf) > stringEndBit) | |||
| 10905 | return fail(); | |||
| 10906 | ||||
| 10907 | /* Common Entity Handle Data */ | |||
| 10908 | std::uint64_t handleEndBit = 0; | |||
| 10909 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, | |||
| 10910 | handleEndBit)) | |||
| 10911 | return fail(); | |||
| 10912 | dwgBuffer handleProbe = buf->forkIndependent(); | |||
| 10913 | ret = DRW_Entity::parseDwgEntHandle(version, &handleProbe, true, | |||
| 10914 | handleEndBit); | |||
| 10915 | if (!ret) | |||
| 10916 | return fail(); | |||
| 10917 | ||||
| 10918 | dwgHandle parsedStyleH; | |||
| 10919 | if (!readBoundedDwgHandle(handleProbe, handleEndBit, 0, false, | |||
| 10920 | parsedStyleH) | |||
| 10921 | || !handleProbe.isGood() || !sBuf->isGood()) | |||
| 10922 | return fail(); | |||
| 10923 | ||||
| 10924 | *sourceBuf = handleProbe; | |||
| 10925 | text = std::move(parsedText); | |||
| 10926 | styleH = parsedStyleH; | |||
| 10927 | DRW_DBG("text style Handle: ")DRW_dbg::dbg("text style Handle: "); DRW_DBGHL(styleH.code, styleH.size, styleH.ref)DRW_dbg::dbgHL(styleH.code, styleH.size, styleH.ref); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 10928 | /* CRC X --- */ | |||
| 10929 | return true; | |||
| 10930 | } | |||
| 10931 | ||||
| 10932 | // --------------------------------------------------------------------------- | |||
| 10933 | // RTEXT (RText, Express Tools) — read-only, mapped onto DRW_Text. | |||
| 10934 | // --------------------------------------------------------------------------- | |||
| 10935 | bool DRW_RText::parseCode(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 10936 | // RTEXT's DXF layout is a TEXT subset (1 text, 7 style, 10/20/30 insertion, | |||
| 10937 | // 40 height, 50 rotation deg, 210/220/230 extrusion) plus a flags long (70) | |||
| 10938 | // that plain TEXT does not carry. | |||
| 10939 | if (70 == code) { | |||
| 10940 | m_rTextFlags = reader->getInt32(); | |||
| 10941 | return true; | |||
| 10942 | } | |||
| 10943 | return DRW_Text::parseCode(code, reader); | |||
| 10944 | } | |||
| 10945 | ||||
| 10946 | bool DRW_RText::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){ | |||
| 10947 | resetDwgState(); | |||
| 10948 | m_rTextFlags = 0; | |||
| 10949 | dwgBuffer *sourceBuf = buf; | |||
| 10950 | auto fail = [this, sourceBuf]() { | |||
| 10951 | if (sourceBuf != nullptr) | |||
| 10952 | sourceBuf->invalidate(); | |||
| 10953 | resetDwgState(); | |||
| 10954 | m_rTextFlags = 0; | |||
| 10955 | return false; | |||
| 10956 | }; | |||
| 10957 | if (sourceBuf == nullptr) | |||
| 10958 | return fail(); | |||
| 10959 | ||||
| 10960 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 10961 | buf = &bodyProbe; | |||
| 10962 | dwgBuffer sBuff = buf->forkIndependent(); | |||
| 10963 | dwgBuffer *sBuf = buf; | |||
| 10964 | if (version > DRW::AC1018) // 2007+ strings live in a separate stream | |||
| 10965 | sBuf = &sBuff; | |||
| 10966 | bool ret = DRW_Entity::parseDwg(version, buf, sBuf, bs); | |||
| 10967 | if (!ret) | |||
| 10968 | return fail(); | |||
| 10969 | DRW_DBG("\n***************************** parsing rtext ********************************************\n")DRW_dbg::dbg("\n***************************** parsing rtext ********************************************\n" ); | |||
| 10970 | ||||
| 10971 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 10972 | DRW_Coord parsedBasePoint; | |||
| 10973 | DRW_Coord parsedExtrusion; | |||
| 10974 | double parsedAngle = 0.0; | |||
| 10975 | double parsedHeight = 0.0; | |||
| 10976 | std::uint16_t parsedFlags = 0; | |||
| 10977 | if (!readBoundedBitCoord(*buf, bodyEndBit, parsedBasePoint) | |||
| 10978 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedExtrusion) | |||
| 10979 | || !readBoundedBitDouble(*buf, bodyEndBit, parsedAngle) | |||
| 10980 | || !readBoundedBitDouble(*buf, bodyEndBit, parsedHeight) | |||
| 10981 | || !readBoundedBitShort(*buf, bodyEndBit, parsedFlags) | |||
| 10982 | || !std::isfinite(parsedBasePoint.x) | |||
| 10983 | || !std::isfinite(parsedBasePoint.y) | |||
| 10984 | || !std::isfinite(parsedBasePoint.z) | |||
| 10985 | || !std::isfinite(parsedExtrusion.x) | |||
| 10986 | || !std::isfinite(parsedExtrusion.y) | |||
| 10987 | || !std::isfinite(parsedExtrusion.z) | |||
| 10988 | || !std::isfinite(parsedAngle) | |||
| 10989 | || !std::isfinite(parsedHeight)) | |||
| 10990 | return fail(); | |||
| 10991 | basePoint = parsedBasePoint; // insertion 3BD | |||
| 10992 | secPoint = parsedBasePoint; // no separate alignment point | |||
| 10993 | extPoint = parsedExtrusion; // extrusion 3BD | |||
| 10994 | angle = parsedAngle * ARAD57.29577951308232; // rotation BD (radians) -> degrees | |||
| 10995 | height = parsedHeight; // height BD | |||
| 10996 | m_rTextFlags = parsedFlags; // flags BS | |||
| 10997 | if (!std::isfinite(angle)) | |||
| 10998 | return fail(); | |||
| 10999 | std::uint64_t stringEndBit = bodyEndBit; | |||
| 11000 | if (version > DRW::AC1021) { | |||
| 11001 | std::uint64_t ignoredBodyEndBit = 0; | |||
| 11002 | if (!entityBodyDataEndBit(*sBuf, version, objSize, | |||
| 11003 | ignoredBodyEndBit, &stringEndBit)) | |||
| 11004 | return fail(); | |||
| 11005 | } | |||
| 11006 | UTF8STRINGstd::string parsedText; | |||
| 11007 | if (version > DRW::AC1018 | |||
| 11008 | && currentDwgBit(sBuf) >= stringEndBit) { | |||
| 11009 | parsedText.clear(); | |||
| 11010 | } else if (!readBoundedVariableText(*sBuf, stringEndBit, version, | |||
| 11011 | parsedText)) { | |||
| 11012 | return fail(); | |||
| 11013 | } | |||
| 11014 | DRW_DBG("rtext string: ")DRW_dbg::dbg("rtext string: "); DRW_DBG(parsedText.c_str())DRW_dbg::dbg(parsedText.c_str()); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 11015 | ||||
| 11016 | if (!buf->isGood() || !sBuf->isGood() | |||
| 11017 | || currentDwgBit(buf) > bodyEndBit | |||
| 11018 | || currentDwgBit(sBuf) > stringEndBit) | |||
| 11019 | return fail(); | |||
| 11020 | ||||
| 11021 | std::uint64_t handleEndBit = 0; | |||
| 11022 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, | |||
| 11023 | handleEndBit)) | |||
| 11024 | return fail(); | |||
| 11025 | dwgBuffer handleProbe = buf->forkIndependent(); | |||
| 11026 | ret = DRW_Entity::parseDwgEntHandle(version, &handleProbe, true, | |||
| 11027 | handleEndBit); | |||
| 11028 | if (!ret) | |||
| 11029 | return fail(); | |||
| 11030 | dwgHandle parsedStyleH; | |||
| 11031 | if (!readBoundedDwgHandle(handleProbe, handleEndBit, 0, false, | |||
| 11032 | parsedStyleH) | |||
| 11033 | || !handleProbe.isGood() || !sBuf->isGood()) | |||
| 11034 | return fail(); | |||
| 11035 | ||||
| 11036 | *sourceBuf = handleProbe; | |||
| 11037 | text = std::move(parsedText); | |||
| 11038 | styleH = parsedStyleH; | |||
| 11039 | return true; | |||
| 11040 | } | |||
| 11041 | ||||
| 11042 | // --------------------------------------------------------------------------- | |||
| 11043 | // ARCALIGNEDTEXT (AcDbArcAlignedText, Express Tools) — read-only, mapped onto | |||
| 11044 | // DRW_Text as a 2D approximation (text at the arc mid-point, tangent baseline). | |||
| 11045 | // --------------------------------------------------------------------------- | |||
| 11046 | bool DRW_RText::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, | |||
| 11047 | dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 11048 | (void)bs; | |||
| 11049 | oType = kDwgClassNum; | |||
| 11050 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 11051 | ||||
| 11052 | buf->put3BitDouble(basePoint); | |||
| 11053 | buf->put3BitDouble(extPoint); | |||
| 11054 | buf->putBitDouble(angle / ARAD57.29577951308232); | |||
| 11055 | buf->putBitDouble(height); | |||
| 11056 | buf->putBitShort(bitShortFromInt(m_rTextFlags)); | |||
| 11057 | (strBuf ? strBuf : buf)->putVariableText(version, text); | |||
| 11058 | ||||
| 11059 | if (!encodeDwgEntHandle(version, buf, handleBuf)) return false; | |||
| 11060 | putHardPointerHandle(handleBuf ? handleBuf : buf, | |||
| 11061 | (styleH.ref == 0) ? 0x13 : styleH.ref); | |||
| 11062 | return true; | |||
| 11063 | } | |||
| 11064 | ||||
| 11065 | void DRW_ArcAlignedText::applyArcApproximation(){ | |||
| 11066 | const double mid = 0.5 * (m_startAngle + m_endAngle); | |||
| 11067 | basePoint.x = m_center.x + m_radius * std::cos(mid); | |||
| 11068 | basePoint.y = m_center.y + m_radius * std::sin(mid); | |||
| 11069 | basePoint.z = m_center.z; | |||
| 11070 | secPoint = basePoint; | |||
| 11071 | // Baseline tangent to the arc at the mid-point; angle stored in degrees to | |||
| 11072 | // match DRW_Text (which the DWG path fills via `angle *= ARAD`). | |||
| 11073 | angle = (mid + M_PI_21.57079632679489661923) * ARAD57.29577951308232; | |||
| 11074 | // Height from the text-size D2T string when parseable, else a fraction of | |||
| 11075 | // the radius so the approximation is at least visible. | |||
| 11076 | double h = 0.0; | |||
| 11077 | try { h = std::stod(m_textSize); } catch (...) { h = 0.0; } | |||
| 11078 | if (h > 0.0) | |||
| 11079 | height = h; | |||
| 11080 | else if (height <= 0.0) | |||
| 11081 | height = 0.1 * m_radius; | |||
| 11082 | } | |||
| 11083 | ||||
| 11084 | // Format a D2T (double-to-text) field the way the ARCALIGNEDTEXT model stores | |||
| 11085 | // it: the DWG body carries these as text ("2.5", "1", "0"), while the DXF path | |||
| 11086 | // reads them as doubles (group codes 41-46 fall in the double range, so the | |||
| 11087 | // reader populates doubleData and leaves strData stale — getString() is unsafe | |||
| 11088 | // here). %g reproduces the same compact textual form. | |||
| 11089 | static std::string arcAlignedD2T(double v){ | |||
| 11090 | char buf[32]; | |||
| 11091 | std::snprintf(buf, sizeof(buf), "%g", v); | |||
| 11092 | return std::string(buf); | |||
| 11093 | } | |||
| 11094 | ||||
| 11095 | static std::string arcAlignedStringOrDefault(const UTF8STRINGstd::string& value, | |||
| 11096 | const std::string& fallback) { | |||
| 11097 | return value.empty() ? fallback : value; | |||
| 11098 | } | |||
| 11099 | ||||
| 11100 | bool DRW_ArcAlignedText::encodeDwg(DRW::Version version, dwgBufferW *buf, | |||
| 11101 | std::uint32_t bs, dwgBufferW *strBuf, | |||
| 11102 | dwgBufferW *handleBuf) { | |||
| 11103 | (void)bs; | |||
| 11104 | oType = kDwgClassNum; | |||
| 11105 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 11106 | ||||
| 11107 | dwgBufferW *sb = strBuf ? strBuf : buf; | |||
| 11108 | sb->putVariableText(version, arcAlignedStringOrDefault( | |||
| 11109 | m_textSize, arcAlignedD2T(height > 0.0 ? height : 0.0))); | |||
| 11110 | sb->putVariableText(version, arcAlignedStringOrDefault( | |||
| 11111 | m_xScale, arcAlignedD2T(widthscale > 0.0 ? widthscale : 1.0))); | |||
| 11112 | sb->putVariableText(version, arcAlignedStringOrDefault(m_charSpacing, "1")); | |||
| 11113 | sb->putVariableText(version, style.empty() ? "Standard" : style); | |||
| 11114 | sb->putVariableText(version, m_fontName); | |||
| 11115 | sb->putVariableText(version, m_bigFontName); | |||
| 11116 | sb->putVariableText(version, text); | |||
| 11117 | sb->putVariableText(version, arcAlignedStringOrDefault(m_offsetFromArc, "0")); | |||
| 11118 | sb->putVariableText(version, arcAlignedStringOrDefault(m_rightOffset, "0")); | |||
| 11119 | sb->putVariableText(version, arcAlignedStringOrDefault(m_leftOffset, "0")); | |||
| 11120 | ||||
| 11121 | buf->put3BitDouble(m_center); | |||
| 11122 | buf->putBitDouble(m_radius); | |||
| 11123 | buf->putBitDouble(m_startAngle); | |||
| 11124 | buf->putBitDouble(m_endAngle); | |||
| 11125 | buf->put3BitDouble(extPoint); | |||
| 11126 | buf->putBitLong(static_cast<std::int32_t>(m_rawColor)); | |||
| 11127 | buf->putBitShort(bitShortFromInt(m_characterSet)); | |||
| 11128 | buf->putBitShort(bitShortFromInt(m_pitchAndFamily)); | |||
| 11129 | buf->putBitShort(bitShortFromInt(m_isShx)); | |||
| 11130 | buf->putBitShort(bitShortFromInt(m_isBold)); | |||
| 11131 | buf->putBitShort(bitShortFromInt(m_isItalic)); | |||
| 11132 | buf->putBitShort(bitShortFromInt(m_isUnderlined)); | |||
| 11133 | buf->putBitShort(bitShortFromInt(m_alignment)); | |||
| 11134 | buf->putBitShort(bitShortFromInt(m_isReverse)); | |||
| 11135 | buf->putBitShort(bitShortFromInt(m_wizardFlag)); | |||
| 11136 | buf->putBitShort(bitShortFromInt(m_textPosition)); | |||
| 11137 | buf->putBitShort(bitShortFromInt(m_textDirection)); | |||
| 11138 | ||||
| 11139 | if (version <= DRW::AC1018) | |||
| 11140 | putNullableHardPointerHandle(buf, m_arcHandle); | |||
| 11141 | if (!encodeDwgEntHandle(version, buf, handleBuf)) return false; | |||
| 11142 | if (version > DRW::AC1018) | |||
| 11143 | putNullableHardPointerHandle(handleBuf ? handleBuf : buf, m_arcHandle); | |||
| 11144 | return true; | |||
| 11145 | } | |||
| 11146 | ||||
| 11147 | bool DRW_ArcAlignedText::parseCode(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 11148 | // ARCALIGNEDTEXT repurposes several TEXT codes (2/10/40/41/50/51/70…), so it | |||
| 11149 | // must not delegate those to DRW_Text; unknown codes fall through to the | |||
| 11150 | // AcDbEntity common parser. Angles (50/51) are DXF degrees -> radians. | |||
| 11151 | switch (code) { | |||
| 11152 | case 1: text = reader->getUtf8String(); break; | |||
| 11153 | case 2: m_fontName = reader->getUtf8String(); break; | |||
| 11154 | case 3: m_bigFontName = reader->getUtf8String(); break; | |||
| 11155 | case 7: style = reader->getUtf8String(); break; | |||
| 11156 | case 10: m_center.x = reader->getDouble(); break; | |||
| 11157 | case 20: m_center.y = reader->getDouble(); break; | |||
| 11158 | case 30: m_center.z = reader->getDouble(); break; | |||
| 11159 | case 40: m_radius = reader->getDouble(); break; | |||
| 11160 | case 41: m_xScale = arcAlignedD2T(reader->getDouble()); break; | |||
| 11161 | case 42: m_textSize = arcAlignedD2T(reader->getDouble()); break; | |||
| 11162 | case 43: m_charSpacing = arcAlignedD2T(reader->getDouble()); break; | |||
| 11163 | case 44: m_offsetFromArc = arcAlignedD2T(reader->getDouble()); break; | |||
| 11164 | case 45: m_rightOffset = arcAlignedD2T(reader->getDouble()); break; | |||
| 11165 | case 46: m_leftOffset = arcAlignedD2T(reader->getDouble()); break; | |||
| 11166 | case 50: m_startAngle = reader->getDouble() / ARAD57.29577951308232; break; | |||
| 11167 | case 51: m_endAngle = reader->getDouble() / ARAD57.29577951308232; break; | |||
| 11168 | case 70: m_isReverse = reader->getInt32(); break; | |||
| 11169 | case 71: m_textDirection = reader->getInt32(); break; | |||
| 11170 | case 72: m_alignment = reader->getInt32(); break; | |||
| 11171 | case 73: m_textPosition = reader->getInt32(); break; | |||
| 11172 | case 74: m_isBold = reader->getInt32(); break; | |||
| 11173 | case 75: m_isItalic = reader->getInt32(); break; | |||
| 11174 | case 76: m_isUnderlined = reader->getInt32(); break; | |||
| 11175 | case 77: m_characterSet = reader->getInt32(); break; | |||
| 11176 | case 78: m_pitchAndFamily = reader->getInt32(); break; | |||
| 11177 | case 79: m_isShx = reader->getInt32(); break; | |||
| 11178 | case 90: m_rawColor = reader->getInt32(); break; | |||
| 11179 | case 210: extPoint.x = reader->getDouble(); break; | |||
| 11180 | case 220: extPoint.y = reader->getDouble(); break; | |||
| 11181 | case 230: extPoint.z = reader->getDouble(); break; | |||
| 11182 | case 280: m_wizardFlag = reader->getInt32(); break; | |||
| 11183 | default: return DRW_Entity::parseCode(code, reader); | |||
| 11184 | } | |||
| 11185 | return true; | |||
| 11186 | } | |||
| 11187 | ||||
| 11188 | void DRW_ArcAlignedText::resetDwgState() { | |||
| 11189 | DRW_Text::resetDwgState(); | |||
| 11190 | m_center = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 11191 | m_radius = 0.0; | |||
| 11192 | m_startAngle = 0.0; | |||
| 11193 | m_endAngle = 0.0; | |||
| 11194 | m_textSize.clear(); | |||
| 11195 | m_xScale.clear(); | |||
| 11196 | m_charSpacing.clear(); | |||
| 11197 | m_offsetFromArc.clear(); | |||
| 11198 | m_rightOffset.clear(); | |||
| 11199 | m_leftOffset.clear(); | |||
| 11200 | m_fontName.clear(); | |||
| 11201 | m_bigFontName.clear(); | |||
| 11202 | m_rawColor = 0; | |||
| 11203 | m_characterSet = 0; | |||
| 11204 | m_pitchAndFamily = 0; | |||
| 11205 | m_isShx = 0; | |||
| 11206 | m_isBold = 0; | |||
| 11207 | m_isItalic = 0; | |||
| 11208 | m_isUnderlined = 0; | |||
| 11209 | m_alignment = 0; | |||
| 11210 | m_isReverse = 0; | |||
| 11211 | m_wizardFlag = 0; | |||
| 11212 | m_textPosition = 0; | |||
| 11213 | m_textDirection = 0; | |||
| 11214 | m_arcHandle = 0; | |||
| 11215 | } | |||
| 11216 | ||||
| 11217 | bool DRW_ArcAlignedText::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){ | |||
| 11218 | // The arc reference is an optional trailer whose position depends on the | |||
| 11219 | // DWG version. Never carry it across a reused or truncated record. | |||
| 11220 | resetDwgState(); | |||
| 11221 | dwgBuffer *sourceBuf = buf; | |||
| 11222 | auto fail = [this, sourceBuf]() { | |||
| 11223 | if (sourceBuf != nullptr) | |||
| 11224 | sourceBuf->invalidate(); | |||
| 11225 | resetDwgState(); | |||
| 11226 | return false; | |||
| 11227 | }; | |||
| 11228 | if (sourceBuf == nullptr) | |||
| 11229 | return fail(); | |||
| 11230 | ||||
| 11231 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 11232 | buf = &bodyProbe; | |||
| 11233 | ||||
| 11234 | dwgBuffer sBuff = buf->forkIndependent(); | |||
| 11235 | dwgBuffer *sBuf = buf; | |||
| 11236 | if (version > DRW::AC1018) // 2007+ strings live in a separate stream | |||
| 11237 | sBuf = &sBuff; | |||
| 11238 | bool ret = DRW_Entity::parseDwg(version, buf, sBuf, bs); | |||
| 11239 | if (!ret) | |||
| 11240 | return fail(); | |||
| 11241 | DRW_DBG("\n***************************** parsing arcalignedtext **********************************\n")DRW_dbg::dbg("\n***************************** parsing arcalignedtext **********************************\n" ); | |||
| 11242 | ||||
| 11243 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 11244 | std::uint64_t stringEndBit = bodyEndBit; | |||
| 11245 | if (version > DRW::AC1021) { | |||
| 11246 | std::uint64_t ignoredBodyEndBit = 0; | |||
| 11247 | if (!entityBodyDataEndBit(*sBuf, version, objSize, | |||
| 11248 | ignoredBodyEndBit, &stringEndBit)) | |||
| 11249 | return fail(); | |||
| 11250 | } | |||
| 11251 | ||||
| 11252 | UTF8STRINGstd::string parsedTextSize; | |||
| 11253 | UTF8STRINGstd::string parsedXScale; | |||
| 11254 | UTF8STRINGstd::string parsedCharSpacing; | |||
| 11255 | UTF8STRINGstd::string parsedStyle; | |||
| 11256 | UTF8STRINGstd::string parsedFontName; | |||
| 11257 | UTF8STRINGstd::string parsedBigFontName; | |||
| 11258 | UTF8STRINGstd::string parsedText; | |||
| 11259 | UTF8STRINGstd::string parsedOffsetFromArc; | |||
| 11260 | UTF8STRINGstd::string parsedRightOffset; | |||
| 11261 | UTF8STRINGstd::string parsedLeftOffset; | |||
| 11262 | if (!readBoundedVariableText(*sBuf, stringEndBit, version, | |||
| 11263 | parsedTextSize) | |||
| 11264 | || !readBoundedVariableText(*sBuf, stringEndBit, version, | |||
| 11265 | parsedXScale) | |||
| 11266 | || !readBoundedVariableText(*sBuf, stringEndBit, version, | |||
| 11267 | parsedCharSpacing) | |||
| 11268 | || !readBoundedVariableText(*sBuf, stringEndBit, version, | |||
| 11269 | parsedStyle) | |||
| 11270 | || !readBoundedVariableText(*sBuf, stringEndBit, version, | |||
| 11271 | parsedFontName) | |||
| 11272 | || !readBoundedVariableText(*sBuf, stringEndBit, version, | |||
| 11273 | parsedBigFontName) | |||
| 11274 | || !readBoundedVariableText(*sBuf, stringEndBit, version, | |||
| 11275 | parsedText) | |||
| 11276 | || !readBoundedVariableText(*sBuf, stringEndBit, version, | |||
| 11277 | parsedOffsetFromArc) | |||
| 11278 | || !readBoundedVariableText(*sBuf, stringEndBit, version, | |||
| 11279 | parsedRightOffset) | |||
| 11280 | || !readBoundedVariableText(*sBuf, stringEndBit, version, | |||
| 11281 | parsedLeftOffset)) | |||
| 11282 | return fail(); | |||
| 11283 | ||||
| 11284 | DRW_Coord parsedCenter; | |||
| 11285 | double parsedRadius = 0.0; | |||
| 11286 | double parsedStartAngle = 0.0; | |||
| 11287 | double parsedEndAngle = 0.0; | |||
| 11288 | DRW_Coord parsedExtPoint; | |||
| 11289 | std::int32_t parsedRawColor = 0; | |||
| 11290 | std::uint16_t parsedCharacterSet = 0; | |||
| 11291 | std::uint16_t parsedPitchAndFamily = 0; | |||
| 11292 | std::uint16_t parsedIsShx = 0; | |||
| 11293 | std::uint16_t parsedIsBold = 0; | |||
| 11294 | std::uint16_t parsedIsItalic = 0; | |||
| 11295 | std::uint16_t parsedIsUnderlined = 0; | |||
| 11296 | std::uint16_t parsedAlignment = 0; | |||
| 11297 | std::uint16_t parsedIsReverse = 0; | |||
| 11298 | std::uint16_t parsedWizardFlag = 0; | |||
| 11299 | std::uint16_t parsedTextPosition = 0; | |||
| 11300 | std::uint16_t parsedTextDirection = 0; | |||
| 11301 | if (!readBoundedBitCoord(*buf, bodyEndBit, parsedCenter) | |||
| 11302 | || !readBoundedBitDouble(*buf, bodyEndBit, parsedRadius) | |||
| 11303 | || !readBoundedBitDouble(*buf, bodyEndBit, parsedStartAngle) | |||
| 11304 | || !readBoundedBitDouble(*buf, bodyEndBit, parsedEndAngle) | |||
| 11305 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedExtPoint) | |||
| 11306 | || !readBoundedBitLong(*buf, bodyEndBit, parsedRawColor) | |||
| 11307 | || !readBoundedBitShort(*buf, bodyEndBit, parsedCharacterSet) | |||
| 11308 | || !readBoundedBitShort(*buf, bodyEndBit, parsedPitchAndFamily) | |||
| 11309 | || !readBoundedBitShort(*buf, bodyEndBit, parsedIsShx) | |||
| 11310 | || !readBoundedBitShort(*buf, bodyEndBit, parsedIsBold) | |||
| 11311 | || !readBoundedBitShort(*buf, bodyEndBit, parsedIsItalic) | |||
| 11312 | || !readBoundedBitShort(*buf, bodyEndBit, parsedIsUnderlined) | |||
| 11313 | || !readBoundedBitShort(*buf, bodyEndBit, parsedAlignment) | |||
| 11314 | || !readBoundedBitShort(*buf, bodyEndBit, parsedIsReverse) | |||
| 11315 | || !readBoundedBitShort(*buf, bodyEndBit, parsedWizardFlag) | |||
| 11316 | || !readBoundedBitShort(*buf, bodyEndBit, parsedTextPosition) | |||
| 11317 | || !readBoundedBitShort(*buf, bodyEndBit, parsedTextDirection)) | |||
| 11318 | return fail(); | |||
| 11319 | DRW_DBG("arcalignedtext string: ")DRW_dbg::dbg("arcalignedtext string: "); DRW_DBG(parsedText.c_str())DRW_dbg::dbg(parsedText.c_str()); | |||
| 11320 | DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 11321 | ||||
| 11322 | if (!buf->isGood() || !sBuf->isGood() | |||
| 11323 | || currentDwgBit(buf) > bodyEndBit | |||
| 11324 | || currentDwgBit(sBuf) > stringEndBit | |||
| 11325 | || !std::isfinite(parsedCenter.x) || !std::isfinite(parsedCenter.y) | |||
| 11326 | || !std::isfinite(parsedCenter.z) || !std::isfinite(parsedRadius) | |||
| 11327 | || parsedRadius < 0.0 || !std::isfinite(parsedStartAngle) | |||
| 11328 | || !std::isfinite(parsedEndAngle) || !std::isfinite(parsedExtPoint.x) | |||
| 11329 | || !std::isfinite(parsedExtPoint.y) | |||
| 11330 | || !std::isfinite(parsedExtPoint.z)) | |||
| 11331 | return fail(); | |||
| 11332 | ||||
| 11333 | std::uint64_t handleEndBit = 0; | |||
| 11334 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, | |||
| 11335 | handleEndBit)) | |||
| 11336 | return fail(); | |||
| 11337 | // R2004- keeps the arc handle before the common handle stream; R2007+ after. | |||
| 11338 | dwgBuffer handleProbe = buf->forkIndependent(); | |||
| 11339 | std::uint32_t parsedArcHandle = 0; | |||
| 11340 | if (version <= DRW::AC1018 | |||
| 11341 | && proxyEntityHasBits(handleProbe, handleEndBit, 8)) { | |||
| 11342 | dwgHandle arcHandle; | |||
| 11343 | if (!readBoundedDwgHandle(handleProbe, handleEndBit, 0, false, | |||
| 11344 | arcHandle)) | |||
| 11345 | return fail(); | |||
| 11346 | parsedArcHandle = arcHandle.ref; | |||
| 11347 | } | |||
| 11348 | ||||
| 11349 | ret = DRW_Entity::parseDwgEntHandle(version, &handleProbe, true, | |||
| 11350 | handleEndBit); | |||
| 11351 | if (!ret) | |||
| 11352 | return fail(); | |||
| 11353 | if (version > DRW::AC1018 | |||
| 11354 | && proxyEntityHasBits(handleProbe, handleEndBit, 8)) { | |||
| 11355 | dwgHandle arcHandle; | |||
| 11356 | if (!readBoundedDwgHandle(handleProbe, handleEndBit, 0, false, | |||
| 11357 | arcHandle)) | |||
| 11358 | return fail(); | |||
| 11359 | parsedArcHandle = arcHandle.ref; | |||
| 11360 | } | |||
| 11361 | if (!handleProbe.isGood()) | |||
| 11362 | return fail(); | |||
| 11363 | ||||
| 11364 | *sourceBuf = handleProbe; | |||
| 11365 | m_textSize = std::move(parsedTextSize); | |||
| 11366 | m_xScale = std::move(parsedXScale); | |||
| 11367 | m_charSpacing = std::move(parsedCharSpacing); | |||
| 11368 | style = std::move(parsedStyle); | |||
| 11369 | m_fontName = std::move(parsedFontName); | |||
| 11370 | m_bigFontName = std::move(parsedBigFontName); | |||
| 11371 | text = std::move(parsedText); | |||
| 11372 | m_offsetFromArc = std::move(parsedOffsetFromArc); | |||
| 11373 | m_rightOffset = std::move(parsedRightOffset); | |||
| 11374 | m_leftOffset = std::move(parsedLeftOffset); | |||
| 11375 | m_center = parsedCenter; | |||
| 11376 | m_radius = parsedRadius; | |||
| 11377 | m_startAngle = parsedStartAngle; | |||
| 11378 | m_endAngle = parsedEndAngle; | |||
| 11379 | extPoint = parsedExtPoint; | |||
| 11380 | m_rawColor = parsedRawColor; | |||
| 11381 | m_characterSet = parsedCharacterSet; | |||
| 11382 | m_pitchAndFamily = parsedPitchAndFamily; | |||
| 11383 | m_isShx = parsedIsShx; | |||
| 11384 | m_isBold = parsedIsBold; | |||
| 11385 | m_isItalic = parsedIsItalic; | |||
| 11386 | m_isUnderlined = parsedIsUnderlined; | |||
| 11387 | m_alignment = parsedAlignment; | |||
| 11388 | m_isReverse = parsedIsReverse; | |||
| 11389 | m_wizardFlag = parsedWizardFlag; | |||
| 11390 | m_textPosition = parsedTextPosition; | |||
| 11391 | m_textDirection = parsedTextDirection; | |||
| 11392 | m_arcHandle = parsedArcHandle; | |||
| 11393 | applyArcApproximation(); | |||
| 11394 | return true; | |||
| 11395 | } | |||
| 11396 | ||||
| 11397 | // Out-of-line special members: required because mtext is a unique_ptr<DRW_MText> | |||
| 11398 | // declared with a forward-declared element type in the header. | |||
| 11399 | DRW_Attrib::~DRW_Attrib() = default; | |||
| 11400 | DRW_Attrib::DRW_Attrib(const DRW_Attrib& o) | |||
| 11401 | : DRW_Text(o), tag(o.tag), attribFlags(o.attribFlags), | |||
| 11402 | m_fieldLength(o.m_fieldLength), | |||
| 11403 | lockPosition(o.lockPosition), attVersion(o.attVersion), | |||
| 11404 | m_attributeType(o.m_attributeType), | |||
| 11405 | keepDuplicateRecords(o.keepDuplicateRecords), | |||
| 11406 | mtext(o.mtext ? std::make_unique<DRW_MText>(*o.mtext) : nullptr) {} | |||
| 11407 | DRW_Attrib& DRW_Attrib::operator=(const DRW_Attrib& o) { | |||
| 11408 | if (this != &o) { | |||
| 11409 | DRW_Text::operator=(o); | |||
| 11410 | tag = o.tag; | |||
| 11411 | attribFlags = o.attribFlags; | |||
| 11412 | m_fieldLength = o.m_fieldLength; | |||
| 11413 | lockPosition = o.lockPosition; | |||
| 11414 | attVersion = o.attVersion; | |||
| 11415 | m_attributeType = o.m_attributeType; | |||
| 11416 | keepDuplicateRecords = o.keepDuplicateRecords; | |||
| 11417 | mtext = o.mtext ? std::make_unique<DRW_MText>(*o.mtext) : nullptr; | |||
| 11418 | } | |||
| 11419 | return *this; | |||
| 11420 | } | |||
| 11421 | DRW_Attrib::DRW_Attrib(DRW_Attrib&&) noexcept = default; | |||
| 11422 | DRW_Attrib& DRW_Attrib::operator=(DRW_Attrib&&) noexcept = default; | |||
| 11423 | ||||
| 11424 | DRW_GeoPositionMarker::~DRW_GeoPositionMarker() = default; | |||
| 11425 | DRW_GeoPositionMarker::DRW_GeoPositionMarker( | |||
| 11426 | const DRW_GeoPositionMarker& o) | |||
| 11427 | : DRW_Entity(o), m_classVersion(o.m_classVersion), | |||
| 11428 | m_position(o.m_position), m_radius(o.m_radius), m_notes(o.m_notes), | |||
| 11429 | m_landingGap(o.m_landingGap), m_mtextVisible(o.m_mtextVisible), | |||
| 11430 | m_textAlignment(o.m_textAlignment), | |||
| 11431 | m_enableFrameText(o.m_enableFrameText), | |||
| 11432 | mtext(o.mtext ? std::make_unique<DRW_MText>(*o.mtext) : nullptr), | |||
| 11433 | m_dxfDouble40Count(o.m_dxfDouble40Count), | |||
| 11434 | m_dxfBool290Count(o.m_dxfBool290Count) {} | |||
| 11435 | DRW_GeoPositionMarker& DRW_GeoPositionMarker::operator=( | |||
| 11436 | const DRW_GeoPositionMarker& o) { | |||
| 11437 | if (this != &o) { | |||
| 11438 | DRW_Entity::operator=(o); | |||
| 11439 | m_classVersion = o.m_classVersion; | |||
| 11440 | m_position = o.m_position; | |||
| 11441 | m_radius = o.m_radius; | |||
| 11442 | m_notes = o.m_notes; | |||
| 11443 | m_landingGap = o.m_landingGap; | |||
| 11444 | m_mtextVisible = o.m_mtextVisible; | |||
| 11445 | m_textAlignment = o.m_textAlignment; | |||
| 11446 | m_enableFrameText = o.m_enableFrameText; | |||
| 11447 | mtext = o.mtext ? std::make_unique<DRW_MText>(*o.mtext) : nullptr; | |||
| 11448 | m_dxfDouble40Count = o.m_dxfDouble40Count; | |||
| 11449 | m_dxfBool290Count = o.m_dxfBool290Count; | |||
| 11450 | } | |||
| 11451 | return *this; | |||
| 11452 | } | |||
| 11453 | DRW_GeoPositionMarker::DRW_GeoPositionMarker( | |||
| 11454 | DRW_GeoPositionMarker&&) noexcept = default; | |||
| 11455 | DRW_GeoPositionMarker& DRW_GeoPositionMarker::operator=( | |||
| 11456 | DRW_GeoPositionMarker&&) noexcept = default; | |||
| 11457 | ||||
| 11458 | namespace { | |||
| 11459 | static bool parseEmbeddedMTextEntityMode(DRW::Version version, dwgBuffer *buf, | |||
| 11460 | std::uint64_t bodyEndBit, | |||
| 11461 | EmbeddedMTextHandleInfo& info, | |||
| 11462 | DRW_MText& mtext) { | |||
| 11463 | std::uint8_t entmode = 0; | |||
| 11464 | if (!readBounded2Bits(*buf, bodyEndBit, entmode)) | |||
| 11465 | return false; | |||
| 11466 | info.m_ownerHandle = entmode == 0; | |||
| 11467 | if (!readBoundedBitLong(*buf, bodyEndBit, info.m_numReactors) | |||
| 11468 | || !dwgSafety::validReactorCount(info.m_numReactors)) | |||
| 11469 | return false; | |||
| 11470 | if (version > DRW::AC1015) { | |||
| 11471 | bool xDictFlag = false; | |||
| 11472 | if (!readBoundedBit(*buf, bodyEndBit, xDictFlag)) | |||
| 11473 | return false; | |||
| 11474 | info.m_xDictFlag = xDictFlag ? 1 : 0; | |||
| 11475 | } | |||
| 11476 | if (version > DRW::AC1024) { | |||
| 11477 | bool hasDataStorage = false; | |||
| 11478 | if (!readBoundedBit(*buf, bodyEndBit, hasDataStorage)) | |||
| 11479 | return false; | |||
| 11480 | mtext.setHasDataStorageBinaryData(hasDataStorage); | |||
| 11481 | } else if (version < DRW::AC1018) { | |||
| 11482 | bool noLinks = false; | |||
| 11483 | if (!readBoundedBit(*buf, bodyEndBit, noLinks)) | |||
| 11484 | return false; // nolinks / have-next-links | |||
| 11485 | } | |||
| 11486 | std::uint32_t color = 0; | |||
| 11487 | if (!readBoundedEnColor(*buf, bodyEndBit, version, color)) | |||
| 11488 | return false; | |||
| 11489 | mtext.color = static_cast<int>(color); | |||
| 11490 | info.m_hasAcDbColorHandle = buf->lastEnColorHadDbColorRef; | |||
| 11491 | mtext.color24 = buf->lastEnColorRgb; | |||
| 11492 | if (!buf->lastEnColorName.empty()) { | |||
| 11493 | mtext.colorName = buf->lastEnColorBookName.empty() | |||
| 11494 | ? buf->lastEnColorName | |||
| 11495 | : (buf->lastEnColorBookName + "$" + buf->lastEnColorName); | |||
| 11496 | } | |||
| 11497 | if (buf->lastEnColorAlphaRaw != 0) | |||
| 11498 | mtext.transparency = static_cast<int>(buf->lastEnColorAlphaRaw); | |||
| 11499 | if (!readBoundedBitDouble(*buf, bodyEndBit, mtext.ltypeScale)) | |||
| 11500 | return false; | |||
| 11501 | if (version > DRW::AC1014) { | |||
| 11502 | std::uint8_t ltFlags = 0; | |||
| 11503 | std::uint8_t plotFlags = 0; | |||
| 11504 | if (!readBounded2Bits(*buf, bodyEndBit, ltFlags) | |||
| 11505 | || !readBounded2Bits(*buf, bodyEndBit, plotFlags)) | |||
| 11506 | return false; | |||
| 11507 | info.m_ltFlags = ltFlags; | |||
| 11508 | info.m_plotFlags = plotFlags; | |||
| 11509 | switch (info.m_ltFlags) { | |||
| 11510 | case 0: | |||
| 11511 | mtext.lineType = "BYLAYER"; | |||
| 11512 | break; | |||
| 11513 | case 1: | |||
| 11514 | mtext.lineType = "BYBLOCK"; | |||
| 11515 | break; | |||
| 11516 | case 2: | |||
| 11517 | mtext.lineType = "CONTINUOUS"; | |||
| 11518 | break; | |||
| 11519 | default: | |||
| 11520 | mtext.lineType.clear(); | |||
| 11521 | break; | |||
| 11522 | } | |||
| 11523 | } | |||
| 11524 | if (version > DRW::AC1018) { | |||
| 11525 | std::uint8_t materialFlag = 0; | |||
| 11526 | std::uint8_t shadowFlag = 0; | |||
| 11527 | if (!readBounded2Bits(*buf, bodyEndBit, materialFlag) | |||
| 11528 | || !readBoundedRawChar8(*buf, bodyEndBit, shadowFlag)) | |||
| 11529 | return false; | |||
| 11530 | info.m_materialFlag = materialFlag; | |||
| 11531 | info.m_shadowFlag = shadowFlag; | |||
| 11532 | mtext.shadow = static_cast<DRW::ShadowMode>(info.m_shadowFlag & 0x3); | |||
| 11533 | } | |||
| 11534 | if (version > DRW::AC1021) { | |||
| 11535 | if (!readBoundedBit(*buf, bodyEndBit, info.m_hasFullVisualStyle) | |||
| 11536 | || !readBoundedBit(*buf, bodyEndBit, info.m_hasFaceVisualStyle) | |||
| 11537 | || !readBoundedBit(*buf, bodyEndBit, info.m_hasEdgeVisualStyle)) | |||
| 11538 | return false; | |||
| 11539 | } | |||
| 11540 | std::uint16_t invisibleFlag = 0; | |||
| 11541 | if (!readBoundedBitShort(*buf, bodyEndBit, invisibleFlag)) | |||
| 11542 | return false; | |||
| 11543 | mtext.visible = (invisibleFlag & 1) == 0; | |||
| 11544 | if (version > DRW::AC1014) { | |||
| 11545 | std::uint8_t lineWeight = 0; | |||
| 11546 | if (!readBoundedRawChar8(*buf, bodyEndBit, lineWeight)) | |||
| 11547 | return false; | |||
| 11548 | mtext.lWeight = DRW_LW_Conv::dwgInt2lineWidth(lineWeight); | |||
| 11549 | } | |||
| 11550 | return buf->isGood() && currentDwgBit(buf) <= bodyEndBit; | |||
| 11551 | } | |||
| 11552 | ||||
| 11553 | static bool parseEmbeddedMTextDwgFields( | |||
| 11554 | DRW::Version version, dwgBuffer *buf, dwgBuffer *sBuf, | |||
| 11555 | DRW_MText& mtext, EmbeddedMTextHandleInfo& info, | |||
| 11556 | std::uint64_t bodyEndBit, std::uint64_t stringEndBit) { | |||
| 11557 | if (!parseEmbeddedMTextEntityMode(version, buf, bodyEndBit, info, mtext)) | |||
| 11558 | return false; | |||
| 11559 | ||||
| 11560 | if (!readBoundedBitCoord(*buf, bodyEndBit, mtext.basePoint) | |||
| 11561 | || !readBoundedBitCoord(*buf, bodyEndBit, mtext.extPoint) | |||
| 11562 | || !readBoundedBitCoord(*buf, bodyEndBit, mtext.secPoint)) | |||
| 11563 | return false; | |||
| 11564 | mtext.angle = atan2(mtext.secPoint.y, mtext.secPoint.x) * ARAD57.29577951308232; | |||
| 11565 | if (!readBoundedBitDouble(*buf, bodyEndBit, mtext.widthscale)) | |||
| 11566 | return false; | |||
| 11567 | if (version > DRW::AC1018) { | |||
| 11568 | double ignoredRectangleHeight = 0.0; | |||
| 11569 | if (!readBoundedBitDouble(*buf, bodyEndBit, | |||
| 11570 | ignoredRectangleHeight)) | |||
| 11571 | return false; | |||
| 11572 | } | |||
| 11573 | if (!readBoundedBitDouble(*buf, bodyEndBit, mtext.height)) | |||
| 11574 | return false; | |||
| 11575 | std::uint16_t textgen = 0; | |||
| 11576 | std::uint16_t alignH = 0; | |||
| 11577 | double ignoredExtentsHeight = 0.0; | |||
| 11578 | double ignoredExtentsWidth = 0.0; | |||
| 11579 | if (!readBoundedBitShort(*buf, bodyEndBit, textgen) | |||
| 11580 | || !readBoundedBitShort(*buf, bodyEndBit, alignH) | |||
| 11581 | || !readBoundedBitDouble(*buf, bodyEndBit, ignoredExtentsHeight) | |||
| 11582 | || !readBoundedBitDouble(*buf, bodyEndBit, ignoredExtentsWidth)) | |||
| 11583 | return false; | |||
| 11584 | mtext.textgen = textgen; | |||
| 11585 | mtext.alignH = static_cast<DRW_Text::HAlign>(alignH); | |||
| 11586 | if (!readBoundedVariableText(*sBuf, stringEndBit, version, mtext.text)) | |||
| 11587 | return false; | |||
| 11588 | ||||
| 11589 | if (version > DRW::AC1014) { | |||
| 11590 | std::uint16_t ignoredLineSpacingStyle = 0; | |||
| 11591 | bool ignoredLineSpacingUnknown = false; | |||
| 11592 | if (!readBoundedBitShort(*buf, bodyEndBit, | |||
| 11593 | ignoredLineSpacingStyle) | |||
| 11594 | || !readBoundedBitDouble(*buf, bodyEndBit, mtext.interlin) | |||
| 11595 | || !readBoundedBit(*buf, bodyEndBit, | |||
| 11596 | ignoredLineSpacingUnknown)) | |||
| 11597 | return false; | |||
| 11598 | } | |||
| 11599 | if (version > DRW::AC1015) { | |||
| 11600 | if (!readBoundedBitLong(*buf, bodyEndBit, mtext.m_backgroundFlags)) | |||
| 11601 | return false; | |||
| 11602 | if ((mtext.m_backgroundFlags & 0x01) | |||
| 11603 | || (version >= DRW::AC1032 && (mtext.m_backgroundFlags & 0x10))) { | |||
| 11604 | std::uint32_t backgroundColor = 0; | |||
| 11605 | if (!readBoundedBitDouble(*buf, bodyEndBit, | |||
| 11606 | mtext.m_backgroundScale) | |||
| 11607 | || !readBoundedCmColor(*buf, sBuf, bodyEndBit, version, | |||
| 11608 | backgroundColor, nullptr, nullptr, | |||
| 11609 | nullptr, nullptr, stringEndBit) | |||
| 11610 | || !readBoundedBitLong(*buf, bodyEndBit, | |||
| 11611 | mtext.m_backgroundTransparency)) | |||
| 11612 | return false; | |||
| 11613 | mtext.m_backgroundColor = static_cast<int>(backgroundColor); | |||
| 11614 | } | |||
| 11615 | } | |||
| 11616 | ||||
| 11617 | if (version >= DRW::AC1032) { | |||
| 11618 | mtext.m_r2018ColumnHeights.clear(); | |||
| 11619 | if (!readBoundedBit(*buf, bodyEndBit, | |||
| 11620 | mtext.m_r2018IsNotAnnotative) | |||
| 11621 | || !readBoundedBit(*buf, bodyEndBit, | |||
| 11622 | mtext.m_r2018ReallyLocked)) | |||
| 11623 | return false; | |||
| 11624 | info.m_hasR2018AppIdHandle = mtext.m_r2018IsNotAnnotative; | |||
| 11625 | } | |||
| 11626 | ||||
| 11627 | std::uint16_t annotativeSize = 0; | |||
| 11628 | if (!readBoundedBitShort(*buf, bodyEndBit, annotativeSize)) | |||
| 11629 | return false; | |||
| 11630 | if (annotativeSize > 0) { | |||
| 11631 | std::vector<std::uint8_t> annotativeData; | |||
| 11632 | if (!DRW::reserve(annotativeData, annotativeSize)) | |||
| 11633 | return false; | |||
| 11634 | for (std::uint16_t i = 0; i < annotativeSize; ++i) { | |||
| 11635 | std::uint8_t value = 0; | |||
| 11636 | if (!readBoundedRawChar8(*buf, bodyEndBit, value)) | |||
| 11637 | return false; | |||
| 11638 | annotativeData.push_back(value); | |||
| 11639 | } | |||
| 11640 | mtext.m_r2018AnnotativeData = std::move(annotativeData); | |||
| 11641 | info.m_hasAnnotativeAppHandle = true; | |||
| 11642 | if (!readBoundedBitShort(*buf, bodyEndBit, | |||
| 11643 | mtext.m_r2018AnnotativeUnknown)) | |||
| 11644 | return false; | |||
| 11645 | } | |||
| 11646 | return buf->isGood() && sBuf->isGood() | |||
| 11647 | && currentDwgBit(buf) <= bodyEndBit | |||
| 11648 | && currentDwgBit(sBuf) <= stringEndBit; | |||
| 11649 | } | |||
| 11650 | ||||
| 11651 | static bool parseEmbeddedMTextDwg( | |||
| 11652 | DRW::Version version, dwgBuffer *buf, dwgBuffer *sBuf, | |||
| 11653 | DRW_MText& mtext, EmbeddedMTextHandleInfo& info, | |||
| 11654 | std::uint64_t bodyEndBit, std::uint64_t stringEndBit) { | |||
| 11655 | if (buf == nullptr || sBuf == nullptr || !buf->isGood() | |||
| 11656 | || !sBuf->isGood()) | |||
| 11657 | return false; | |||
| 11658 | ||||
| 11659 | const std::uint64_t bodyStartBit = currentDwgBit(buf); | |||
| 11660 | const std::uint64_t stringStartBit = currentDwgBit(sBuf); | |||
| 11661 | const auto totalBits = [](const dwgBuffer& buffer) { | |||
| 11662 | std::uint64_t bits = 0; | |||
| 11663 | return dwgSafety::multiply(buffer.size(), 8, bits) ? bits : 0; | |||
| 11664 | }; | |||
| 11665 | if (bodyEndBit == std::numeric_limits<std::uint64_t>::max()) | |||
| 11666 | bodyEndBit = totalBits(*buf); | |||
| 11667 | if (stringEndBit == std::numeric_limits<std::uint64_t>::max()) | |||
| 11668 | stringEndBit = totalBits(*sBuf); | |||
| 11669 | if (bodyStartBit > bodyEndBit || stringStartBit > stringEndBit) | |||
| 11670 | return false; | |||
| 11671 | ||||
| 11672 | dwgBuffer bodyProbe = buf->forkIndependent(); | |||
| 11673 | std::unique_ptr<dwgBuffer> separateStringProbe; | |||
| 11674 | dwgBuffer *stringProbe = &bodyProbe; | |||
| 11675 | if (sBuf != buf) { | |||
| 11676 | separateStringProbe = std::make_unique<dwgBuffer>( | |||
| 11677 | sBuf->forkIndependent()); | |||
| 11678 | stringProbe = separateStringProbe.get(); | |||
| 11679 | } | |||
| 11680 | if (!parseEmbeddedMTextDwgFields(version, &bodyProbe, stringProbe, | |||
| 11681 | mtext, info, bodyEndBit, | |||
| 11682 | stringEndBit)) | |||
| 11683 | return false; | |||
| 11684 | ||||
| 11685 | const std::uint64_t bodyConsumed = currentDwgBit(&bodyProbe); | |||
| 11686 | const std::uint64_t stringConsumed = currentDwgBit(stringProbe); | |||
| 11687 | if (bodyConsumed < bodyStartBit || stringConsumed < stringStartBit | |||
| 11688 | || bodyConsumed > bodyEndBit || stringConsumed > stringEndBit) | |||
| 11689 | return false; | |||
| 11690 | ||||
| 11691 | const auto seekBits = [](dwgBuffer& buffer, std::uint64_t bit) { | |||
| 11692 | if (!buffer.setPosition(bit >> 3)) | |||
| 11693 | return false; | |||
| 11694 | buffer.setBitPos(static_cast<std::uint8_t>(bit & 7u)); | |||
| 11695 | return buffer.isGood() && currentDwgBit(&buffer) == bit; | |||
| 11696 | }; | |||
| 11697 | if (!seekBits(*buf, bodyConsumed)) | |||
| 11698 | return false; | |||
| 11699 | if (sBuf != buf && !seekBits(*sBuf, stringConsumed)) | |||
| 11700 | return false; | |||
| 11701 | return true; | |||
| 11702 | } | |||
| 11703 | ||||
| 11704 | static bool consumeEmbeddedMTextHandles( | |||
| 11705 | DRW::Version version, dwgBuffer *buf, | |||
| 11706 | const EmbeddedMTextHandleInfo& info, DRW_MText *mtext, | |||
| 11707 | std::uint64_t handleEndBit) { | |||
| 11708 | if (buf == nullptr || !buf->isGood()) | |||
| 11709 | return false; | |||
| 11710 | ||||
| 11711 | if (handleEndBit == std::numeric_limits<std::uint64_t>::max()) { | |||
| 11712 | if (!dwgSafety::multiply(buf->size(), 8, handleEndBit)) | |||
| 11713 | return false; | |||
| 11714 | } | |||
| 11715 | dwgBuffer probe = buf->forkIndependent(); | |||
| 11716 | auto readHandle = [&](bool offset, dwgHandle& value) { | |||
| 11717 | return readBoundedDwgHandle(probe, handleEndBit, 0, offset, value); | |||
| 11718 | }; | |||
| 11719 | ||||
| 11720 | dwgHandle owner; | |||
| 11721 | if (info.m_ownerHandle && !readHandle(false, owner)) | |||
| 11722 | return false; | |||
| 11723 | ||||
| 11724 | std::vector<std::uint32_t> reactors; | |||
| 11725 | if (info.m_numReactors < 0 | |||
| 11726 | || !dwgSafety::validReactorCount(info.m_numReactors)) | |||
| 11727 | return false; | |||
| 11728 | if (!DRW::reserve(reactors, info.m_numReactors)) | |||
| 11729 | return false; | |||
| 11730 | for (int i = 0; i < info.m_numReactors; ++i) { | |||
| 11731 | dwgHandle reactor; | |||
| 11732 | if (!readHandle(false, reactor)) | |||
| 11733 | return false; | |||
| 11734 | if (reactor.ref != 0) | |||
| 11735 | reactors.push_back(reactor.ref); | |||
| 11736 | } | |||
| 11737 | ||||
| 11738 | dwgHandle xDict; | |||
| 11739 | const bool hasXDict = version <= DRW::AC1015 || info.m_xDictFlag != 1; | |||
| 11740 | if (hasXDict && !readHandle(false, xDict)) | |||
| 11741 | return false; | |||
| 11742 | ||||
| 11743 | dwgHandle color; | |||
| 11744 | if (info.m_hasAcDbColorHandle && !readHandle(false, color)) | |||
| 11745 | return false; | |||
| 11746 | ||||
| 11747 | dwgHandle layer; | |||
| 11748 | const bool hasLayer = version > DRW::AC1014; | |||
| 11749 | if (hasLayer && !readHandle(false, layer)) | |||
| 11750 | return false; | |||
| 11751 | ||||
| 11752 | dwgHandle lineType; | |||
| 11753 | const bool hasLineType = version > DRW::AC1014 && info.m_ltFlags == 3; | |||
| 11754 | if (hasLineType && !readHandle(false, lineType)) | |||
| 11755 | return false; | |||
| 11756 | ||||
| 11757 | dwgHandle material; | |||
| 11758 | const bool hasMaterial = version > DRW::AC1018 && info.m_materialFlag == 3; | |||
| 11759 | if (hasMaterial && !readHandle(false, material)) | |||
| 11760 | return false; | |||
| 11761 | ||||
| 11762 | dwgHandle shadow; | |||
| 11763 | const bool hasShadow = version > DRW::AC1018 && info.m_shadowFlag == 3; | |||
| 11764 | if (hasShadow && !readHandle(false, shadow)) | |||
| 11765 | return false; | |||
| 11766 | ||||
| 11767 | dwgHandle plotStyle; | |||
| 11768 | const bool hasPlotStyle = info.m_plotFlags == 3; | |||
| 11769 | if (hasPlotStyle && !readHandle(false, plotStyle)) | |||
| 11770 | return false; | |||
| 11771 | ||||
| 11772 | dwgHandle fullVisualStyle; | |||
| 11773 | const bool hasFullVisualStyle = version > DRW::AC1021 | |||
| 11774 | && info.m_hasFullVisualStyle; | |||
| 11775 | if (hasFullVisualStyle && !readHandle(false, fullVisualStyle)) | |||
| 11776 | return false; | |||
| 11777 | ||||
| 11778 | dwgHandle faceVisualStyle; | |||
| 11779 | const bool hasFaceVisualStyle = version > DRW::AC1021 | |||
| 11780 | && info.m_hasFaceVisualStyle; | |||
| 11781 | if (hasFaceVisualStyle && !readHandle(false, faceVisualStyle)) | |||
| 11782 | return false; | |||
| 11783 | ||||
| 11784 | dwgHandle edgeVisualStyle; | |||
| 11785 | const bool hasEdgeVisualStyle = version > DRW::AC1021 | |||
| 11786 | && info.m_hasEdgeVisualStyle; | |||
| 11787 | if (hasEdgeVisualStyle && !readHandle(false, edgeVisualStyle)) | |||
| 11788 | return false; | |||
| 11789 | ||||
| 11790 | dwgHandle style; | |||
| 11791 | if (info.m_hasStyleHandle && !readHandle(false, style)) | |||
| 11792 | return false; | |||
| 11793 | ||||
| 11794 | dwgHandle appId; | |||
| 11795 | if (info.m_hasR2018AppIdHandle && !readHandle(false, appId)) | |||
| 11796 | return false; | |||
| 11797 | ||||
| 11798 | dwgHandle annotativeApp; | |||
| 11799 | if (info.m_hasAnnotativeAppHandle && !readHandle(false, annotativeApp)) | |||
| 11800 | return false; | |||
| 11801 | ||||
| 11802 | if (mtext != nullptr) { | |||
| 11803 | if (info.m_ownerHandle) | |||
| 11804 | mtext->parentHandle = owner.ref; | |||
| 11805 | mtext->reactorHandles = std::move(reactors); | |||
| 11806 | if (hasXDict) | |||
| 11807 | mtext->xDictHandle = xDict.ref; | |||
| 11808 | if (info.m_hasAcDbColorHandle) | |||
| 11809 | mtext->setDwgAcDbColorHandle(true, color.ref); | |||
| 11810 | if (hasLayer) | |||
| 11811 | mtext->setDwgLayerHandle(layer.ref); | |||
| 11812 | if (hasLineType) | |||
| 11813 | mtext->setDwgLinetypeHandle(lineType.ref); | |||
| 11814 | if (hasMaterial) | |||
| 11815 | mtext->material = material.ref; | |||
| 11816 | if (hasShadow) | |||
| 11817 | mtext->shadowHandle = shadow.ref; | |||
| 11818 | if (hasPlotStyle) | |||
| 11819 | mtext->plotStyle = static_cast<int>(plotStyle.ref); | |||
| 11820 | if (hasFullVisualStyle) | |||
| 11821 | mtext->fullVisualStyleHandle = fullVisualStyle.ref; | |||
| 11822 | if (hasFaceVisualStyle) | |||
| 11823 | mtext->faceVisualStyleHandle = faceVisualStyle.ref; | |||
| 11824 | if (hasEdgeVisualStyle) | |||
| 11825 | mtext->edgeVisualStyleHandle = edgeVisualStyle.ref; | |||
| 11826 | if (info.m_hasStyleHandle) | |||
| 11827 | mtext->styleH = style; | |||
| 11828 | if (info.m_hasR2018AppIdHandle) | |||
| 11829 | mtext->m_r2018AppIdHandle = appId.ref; | |||
| 11830 | if (info.m_hasAnnotativeAppHandle) | |||
| 11831 | mtext->m_r2018AnnotativeAppHandle = annotativeApp.ref; | |||
| 11832 | } | |||
| 11833 | *buf = probe; | |||
| 11834 | return true; | |||
| 11835 | } | |||
| 11836 | ||||
| 11837 | static bool encodeEmbeddedMTextEntityMode(DRW::Version version, dwgBufferW *buf, | |||
| 11838 | const DRW_MText& mtext) { | |||
| 11839 | if (version < DRW::AC1032) | |||
| 11840 | return false; | |||
| 11841 | ||||
| 11842 | // Embedded MTEXT begins at AcDbEntity mode, not with an object type, | |||
| 11843 | // object size, own handle, EED, or graphics data. | |||
| 11844 | if (mtext.reactorHandles.size() | |||
| 11845 | > static_cast<std::size_t>(std::numeric_limits<std::int32_t>::max())) | |||
| 11846 | return false; | |||
| 11847 | buf->put2Bits(mtext.parentHandle == DRW::NoHandle ? 2 : 0); | |||
| 11848 | buf->putBitLong(static_cast<std::int32_t>(mtext.reactorHandles.size())); | |||
| 11849 | buf->putBit(mtext.xDictHandle == 0 ? 1 : 0); | |||
| 11850 | buf->putBit(mtext.hasDataStorageBinaryData() ? 1 : 0); | |||
| 11851 | UTF8STRINGstd::string colorName = mtext.colorName; | |||
| 11852 | UTF8STRINGstd::string bookName; | |||
| 11853 | const std::string::size_type separator = colorName.find('$'); | |||
| 11854 | if (separator != std::string::npos) { | |||
| 11855 | bookName = colorName.substr(0, separator); | |||
| 11856 | colorName.erase(0, separator + 1); | |||
| 11857 | } | |||
| 11858 | buf->putEnColor(version, static_cast<std::uint16_t>(mtext.color), | |||
| 11859 | mtext.color24, colorName, bookName, | |||
| 11860 | static_cast<std::uint32_t>(mtext.transparency), | |||
| 11861 | mtext.hasDwgAcDbColorHandle()); | |||
| 11862 | buf->putBitDouble(mtext.ltypeScale); | |||
| 11863 | std::uint8_t ltFlags = 0; | |||
| 11864 | if (mtext.dwgLinetypeHandle() != 0 || mtext.lineType.empty()) | |||
| 11865 | ltFlags = 3; | |||
| 11866 | else if (mtext.lineType == "BYBLOCK") | |||
| 11867 | ltFlags = 1; | |||
| 11868 | else if (mtext.lineType == "CONTINUOUS") | |||
| 11869 | ltFlags = 2; | |||
| 11870 | buf->put2Bits(ltFlags); | |||
| 11871 | buf->put2Bits(mtext.plotStyle == DRW::DefaultPlotStyle ? 0 : 3); | |||
| 11872 | buf->put2Bits(mtext.material == DRW::MaterialByLayer ? 0 : 3); | |||
| 11873 | buf->putRawChar8(static_cast<std::uint8_t>(mtext.shadow)); | |||
| 11874 | buf->putBit(mtext.fullVisualStyleHandle != 0); | |||
| 11875 | buf->putBit(mtext.faceVisualStyleHandle != 0); | |||
| 11876 | buf->putBit(mtext.edgeVisualStyleHandle != 0); | |||
| 11877 | buf->putBitShort(mtext.visible ? 0 : 1); | |||
| 11878 | buf->putRawChar8(static_cast<std::uint8_t>(mtext.lWeight)); | |||
| 11879 | return true; | |||
| 11880 | } | |||
| 11881 | ||||
| 11882 | static bool encodeEmbeddedMTextDwg(DRW::Version version, dwgBufferW *buf, | |||
| 11883 | dwgBufferW *strBuf, dwgBufferW *handleBuf, | |||
| 11884 | const DRW_MText& mtext) { | |||
| 11885 | if (!encodeEmbeddedMTextEntityMode(version, buf, mtext)) | |||
| 11886 | return false; | |||
| 11887 | ||||
| 11888 | buf->put3BitDouble(mtext.basePoint); | |||
| 11889 | buf->put3BitDouble(mtext.extPoint); | |||
| 11890 | buf->put3BitDouble(mtext.secPoint); | |||
| 11891 | buf->putBitDouble(mtext.widthscale); | |||
| 11892 | buf->putBitDouble(mtext.m_r2018RectHeight); | |||
| 11893 | buf->putBitDouble(mtext.height); | |||
| 11894 | buf->putBitShort(static_cast<std::uint16_t>(mtext.textgen)); | |||
| 11895 | buf->putBitShort(static_cast<std::uint16_t>(mtext.alignH)); | |||
| 11896 | buf->putBitDouble(mtext.m_r2018ExtentsHeight); | |||
| 11897 | buf->putBitDouble(mtext.m_r2018ExtentsWidth); | |||
| 11898 | (strBuf ? strBuf : buf)->putVariableText(version, mtext.text); | |||
| 11899 | ||||
| 11900 | buf->putBitShort(0); // linespacing style | |||
| 11901 | buf->putBitDouble(mtext.interlin); | |||
| 11902 | buf->putBit(0); | |||
| 11903 | buf->putBitLong(mtext.m_backgroundFlags); | |||
| 11904 | if ((mtext.m_backgroundFlags & 0x01) | |||
| 11905 | || (mtext.m_backgroundFlags & 0x10)) { | |||
| 11906 | buf->putBitDouble(mtext.m_backgroundScale); // BitDouble, not BitLong | |||
| 11907 | buf->putCmColor(version, static_cast<std::uint16_t>(mtext.m_backgroundColor)); | |||
| 11908 | buf->putBitLong(mtext.m_backgroundTransparency); | |||
| 11909 | } | |||
| 11910 | ||||
| 11911 | buf->putBit(mtext.m_r2018IsNotAnnotative ? 1 : 0); | |||
| 11912 | buf->putBit(mtext.m_r2018ReallyLocked ? 1 : 0); | |||
| 11913 | ||||
| 11914 | if (mtext.m_r2018AnnotativeData.size() > std::numeric_limits<std::uint16_t>::max()) | |||
| 11915 | return false; | |||
| 11916 | buf->putBitShort(static_cast<std::uint16_t>(mtext.m_r2018AnnotativeData.size())); | |||
| 11917 | for (std::uint8_t byte : mtext.m_r2018AnnotativeData) | |||
| 11918 | buf->putRawChar8(byte); | |||
| 11919 | if (!mtext.m_r2018AnnotativeData.empty()) { | |||
| 11920 | buf->putBitShort(mtext.m_r2018AnnotativeUnknown); | |||
| 11921 | } | |||
| 11922 | ||||
| 11923 | dwgBufferW *hb = handleBuf ? handleBuf : buf; | |||
| 11924 | if (mtext.parentHandle != DRW::NoHandle) | |||
| 11925 | putHardPointerHandle(hb, mtext.parentHandle); | |||
| 11926 | for (const std::uint32_t reactor : mtext.reactorHandles) | |||
| 11927 | putHardPointerHandle(hb, reactor); | |||
| 11928 | if (mtext.xDictHandle != 0) | |||
| 11929 | putHardPointerHandle(hb, mtext.xDictHandle); | |||
| 11930 | if (mtext.hasDwgAcDbColorHandle()) | |||
| 11931 | putHardPointerHandle(hb, mtext.dwgAcDbColorHandle()); | |||
| 11932 | putHardPointerHandle(hb, mtext.dwgLayerHandle() == 0 | |||
| 11933 | ? 0x12 : mtext.dwgLayerHandle()); | |||
| 11934 | if (mtext.dwgLinetypeHandle() != 0 || mtext.lineType.empty()) | |||
| 11935 | putHardPointerHandle(hb, mtext.dwgLinetypeHandle()); | |||
| 11936 | if (mtext.material != DRW::MaterialByLayer) | |||
| 11937 | putHardPointerHandle(hb, mtext.material); | |||
| 11938 | if (mtext.shadow == DRW::IgnoreShadows) | |||
| 11939 | putHardPointerHandle(hb, mtext.shadowHandle); | |||
| 11940 | if (mtext.plotStyle != DRW::DefaultPlotStyle) | |||
| 11941 | putHardPointerHandle(hb, static_cast<std::uint32_t>(mtext.plotStyle)); | |||
| 11942 | if (mtext.fullVisualStyleHandle != 0) | |||
| 11943 | putHardPointerHandle(hb, mtext.fullVisualStyleHandle); | |||
| 11944 | if (mtext.faceVisualStyleHandle != 0) | |||
| 11945 | putHardPointerHandle(hb, mtext.faceVisualStyleHandle); | |||
| 11946 | if (mtext.edgeVisualStyleHandle != 0) | |||
| 11947 | putHardPointerHandle(hb, mtext.edgeVisualStyleHandle); | |||
| 11948 | putHardPointerHandle(hb, (mtext.styleH.ref == 0) ? 0x13 : mtext.styleH.ref); | |||
| 11949 | if (mtext.m_r2018IsNotAnnotative) | |||
| 11950 | putHardPointerHandle(hb, (mtext.m_r2018AppIdHandle == 0) ? 0x14 : mtext.m_r2018AppIdHandle); | |||
| 11951 | if (!mtext.m_r2018AnnotativeData.empty()) | |||
| 11952 | putHardPointerHandle(hb, (mtext.m_r2018AnnotativeAppHandle == 0) | |||
| 11953 | ? 0x14 : mtext.m_r2018AnnotativeAppHandle); | |||
| 11954 | return true; | |||
| 11955 | } | |||
| 11956 | } | |||
| 11957 | ||||
| 11958 | bool DRW_GeoPositionMarker::encodeDwg(DRW::Version v, dwgBufferW *buf, | |||
| 11959 | std::uint32_t bs, dwgBufferW *strBuf, | |||
| 11960 | dwgBufferW *handleBuf) { | |||
| 11961 | (void)bs; | |||
| 11962 | if (v < DRW::AC1027 || buf == nullptr) | |||
| 11963 | return false; | |||
| 11964 | // The embedded AcDbMTextObjectEmbedded wire form was introduced with | |||
| 11965 | // AC1032. Reject an AC1027 framed marker rather than emitting a body that | |||
| 11966 | // a reader will interpret as the parent handle stream. | |||
| 11967 | if (m_enableFrameText && (v < DRW::AC1032 || mtext == nullptr)) | |||
| 11968 | return false; | |||
| 11969 | ||||
| 11970 | oType = kDwgType; | |||
| 11971 | if (!encodeDwgCommon(v, buf, strBuf)) | |||
| 11972 | return false; | |||
| 11973 | ||||
| 11974 | dwgBufferW *stringBuffer = strBuf ? strBuf : buf; | |||
| 11975 | buf->putBitLong(m_classVersion); | |||
| 11976 | buf->put3BitDouble(m_position); | |||
| 11977 | buf->putBitDouble(m_radius); | |||
| 11978 | stringBuffer->putVariableText(v, m_notes); | |||
| 11979 | buf->putBitDouble(m_landingGap); | |||
| 11980 | buf->putBit(m_mtextVisible ? 1 : 0); | |||
| 11981 | buf->putRawChar8(m_textAlignment); | |||
| 11982 | buf->putBit(m_enableFrameText ? 1 : 0); | |||
| 11983 | ||||
| 11984 | dwgBufferW embeddedHandles; | |||
| 11985 | if (m_enableFrameText | |||
| 11986 | && !encodeEmbeddedMTextDwg(v, buf, strBuf, &embeddedHandles, *mtext)) | |||
| 11987 | return false; | |||
| 11988 | if (!encodeDwgEntHandle(v, buf, handleBuf)) | |||
| 11989 | return false; | |||
| 11990 | ||||
| 11991 | dwgBufferW *resolvedHandles = handleBuf ? handleBuf : buf; | |||
| 11992 | appendBitBuffer(resolvedHandles, embeddedHandles); | |||
| 11993 | return true; | |||
| 11994 | } | |||
| 11995 | ||||
| 11996 | bool DRW_Attrib::parseCode(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 11997 | // Multi-line ATTRIB (R2018+, ODA spec §20.4.4): an embedded MTEXT object | |||
| 11998 | // is introduced by the DXF subclass marker `100 / Embedded Object` (NOT | |||
| 11999 | // `AcDbMText`). After the marker, the standard MTEXT group codes follow | |||
| 12000 | // (10/20/30 insertion, 11/21/31 X-axis, 40 height, 41 rect width, 71 | |||
| 12001 | // attachment point, 72 drawing direction, 1 formatted text, etc.), then | |||
| 12002 | // the ATTRIB-specific tail (tag=2, prompt=3 for ATTDEF, flags=70, | |||
| 12003 | // lock-position=280) which we must NOT route into the embedded MText. | |||
| 12004 | if (code == 100) { | |||
| 12005 | const std::string sub = reader->getString(); | |||
| 12006 | if (sub == "Embedded Object" && !mtext) { | |||
| 12007 | mtext = std::make_unique<DRW_MText>(); | |||
| 12008 | if (attVersion == 0) attVersion = 1; | |||
| 12009 | } | |||
| 12010 | dxfInAttributeSubclass = sub == "AcDbAttribute" | |||
| 12011 | || sub == "AcDbAttributeDefinition"; | |||
| 12012 | return true; | |||
| 12013 | } | |||
| 12014 | if (dxfInAttributeSubclass && !mtext) { | |||
| 12015 | if (code == 71) { | |||
| 12016 | const int value = reader->getInt32(); | |||
| 12017 | if (value < 0 || value > std::numeric_limits<std::uint8_t>::max()) | |||
| 12018 | return false; | |||
| 12019 | m_attributeType = static_cast<std::uint8_t>(value); | |||
| 12020 | return true; | |||
| 12021 | } | |||
| 12022 | if (code == 72) { | |||
| 12023 | (void)reader->getInt32(); | |||
| 12024 | return true; | |||
| 12025 | } | |||
| 12026 | } | |||
| 12027 | // Inside the embedded MText scope, route MTEXT-owned codes to mtext but | |||
| 12028 | // keep ATTRIB-specific tail codes for ATTRIB / ATTDEF handling below. | |||
| 12029 | if (mtext) { | |||
| 12030 | switch (code) { | |||
| 12031 | case 2: // tag (ATTRIB-specific; group 1 in MText is text body) | |||
| 12032 | case 3: // prompt (ATTDEF-specific) | |||
| 12033 | case 70: // ATTRIB flags | |||
| 12034 | case 280: // ATTRIB lock-position | |||
| 12035 | break; // fall through to ATTRIB handling below | |||
| 12036 | default: | |||
| 12037 | return mtext->parseCode(code, reader); | |||
| 12038 | } | |||
| 12039 | } | |||
| 12040 | switch (code) { | |||
| 12041 | case 2: | |||
| 12042 | tag = reader->getUtf8String(); | |||
| 12043 | break; | |||
| 12044 | case 70: | |||
| 12045 | attribFlags = reader->getInt32(); | |||
| 12046 | break; | |||
| 12047 | case 73: | |||
| 12048 | // AcDbAttribute code 73 = field length (obsolete); NOT the vertical | |||
| 12049 | // alignment from AcDbText (which is code 73 in TEXT but 74 in ATTRIB). | |||
| 12050 | m_fieldLength = reader->getInt32(); | |||
| 12051 | break; | |||
| 12052 | case 74: | |||
| 12053 | // AcDbAttribute vertical alignment (code 74); TEXT uses code 73 for | |||
| 12054 | // this but ATTRIB moves it here to free code 73 for field length. | |||
| 12055 | alignV = (VAlign)reader->getInt32(); | |||
| 12056 | break; | |||
| 12057 | case 280: | |||
| 12058 | // Lock position flag (R2010+ DXF group code) | |||
| 12059 | lockPosition = reader->getInt32() != 0; | |||
| 12060 | break; | |||
| 12061 | default: | |||
| 12062 | return DRW_Text::parseCode(code, reader); | |||
| 12063 | } | |||
| 12064 | return true; | |||
| 12065 | } | |||
| 12066 | ||||
| 12067 | void DRW_Attrib::resetAttribDwgState() { | |||
| 12068 | resetDwgState(); | |||
| 12069 | tag.clear(); | |||
| 12070 | attribFlags = 0; | |||
| 12071 | m_fieldLength = 0; | |||
| 12072 | lockPosition = false; | |||
| 12073 | attVersion = 0; | |||
| 12074 | m_attributeType = 1; | |||
| 12075 | keepDuplicateRecords = 0; | |||
| 12076 | mtext.reset(); | |||
| 12077 | dxfInAttributeSubclass = false; | |||
| 12078 | } | |||
| 12079 | ||||
| 12080 | bool DRW_Attrib::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){ | |||
| 12081 | resetAttribDwgState(); | |||
| 12082 | dwgBuffer *sourceBuf = buf; | |||
| 12083 | auto fail = [this, sourceBuf]() { | |||
| 12084 | if (sourceBuf != nullptr) | |||
| 12085 | sourceBuf->invalidate(); | |||
| 12086 | resetAttribDwgState(); | |||
| 12087 | return false; | |||
| 12088 | }; | |||
| 12089 | if (sourceBuf == nullptr) | |||
| 12090 | return fail(); | |||
| 12091 | ||||
| 12092 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 12093 | buf = &bodyProbe; | |||
| 12094 | dwgBuffer sBuff = bodyProbe.forkIndependent(); | |||
| 12095 | dwgBuffer *sBuf = &bodyProbe; | |||
| 12096 | if (version > DRW::AC1018) {//2007+ | |||
| 12097 | sBuf = &sBuff; //separate buffer for strings | |||
| 12098 | } | |||
| 12099 | bool ret = DRW_Entity::parseDwg(version, buf, sBuf, bs); | |||
| 12100 | if (!ret) | |||
| 12101 | return fail(); | |||
| 12102 | DRW_DBG("\n***************************** parsing attrib *********************************************\n")DRW_dbg::dbg("\n***************************** parsing attrib *********************************************\n" ); | |||
| 12103 | ||||
| 12104 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 12105 | std::uint64_t stringStartBit = bodyEndBit; | |||
| 12106 | std::uint64_t stringEndBit = bodyEndBit; | |||
| 12107 | if (version > DRW::AC1018 | |||
| 12108 | && (!buf->getR2007StringStreamBounds(objSize, stringStartBit, | |||
| 12109 | stringEndBit) | |||
| 12110 | || currentDwgBit(sBuf) > stringEndBit)) | |||
| 12111 | return fail(); | |||
| 12112 | ||||
| 12113 | DwgTextBodyData parsedText; | |||
| 12114 | if (!readBoundedDwgTextBody(version, *buf, *sBuf, bodyEndBit, | |||
| 12115 | stringStartBit, stringEndBit, parsedText)) | |||
| 12116 | return fail(); | |||
| 12117 | ||||
| 12118 | // R2010+ ATTRIB version follows the common TEXT data. R2018 adds the | |||
| 12119 | // attribute type immediately after it. | |||
| 12120 | std::uint8_t parsedAttVersion = 0; | |||
| 12121 | std::uint8_t parsedAttributeType = 1; | |||
| 12122 | if (version >= DRW::AC1024) { | |||
| 12123 | if (!readBoundedRawChar8(*buf, bodyEndBit, parsedAttVersion)) | |||
| 12124 | return fail(); | |||
| 12125 | } | |||
| 12126 | if (version >= DRW::AC1032) { | |||
| 12127 | if (!readBoundedRawChar8(*buf, bodyEndBit, parsedAttributeType)) | |||
| 12128 | return fail(); | |||
| 12129 | } | |||
| 12130 | ||||
| 12131 | bool hasEmbeddedMText = false; | |||
| 12132 | EmbeddedMTextHandleInfo embeddedMTextHandles; | |||
| 12133 | std::unique_ptr<DRW_MText> parsedMText; | |||
| 12134 | if (version >= DRW::AC1032 | |||
| 12135 | && parsedAttributeType != 0 && parsedAttributeType != 1) { | |||
| 12136 | parsedMText = std::make_unique<DRW_MText>(); | |||
| 12137 | if (!parseEmbeddedMTextDwg(version, buf, sBuf, *parsedMText, | |||
| 12138 | embeddedMTextHandles, bodyEndBit, | |||
| 12139 | stringEndBit)) { | |||
| 12140 | DRW_DBG("R2018 multi-line ATTRIB payload failed\n")DRW_dbg::dbg("R2018 multi-line ATTRIB payload failed\n"); | |||
| 12141 | return fail(); | |||
| 12142 | } | |||
| 12143 | hasEmbeddedMText = true; | |||
| 12144 | } | |||
| 12145 | ||||
| 12146 | // ATTRIB-specific fields | |||
| 12147 | UTF8STRINGstd::string parsedTag; | |||
| 12148 | if (version <= DRW::AC1018 || stringStartBit < stringEndBit) { | |||
| 12149 | if (!readBoundedVariableText(*sBuf, stringEndBit, version, | |||
| 12150 | parsedTag)) | |||
| 12151 | return fail(); | |||
| 12152 | } | |||
| 12153 | ||||
| 12154 | std::uint16_t parsedFieldLength = 0; | |||
| 12155 | std::uint8_t parsedAttribFlags = 0; | |||
| 12156 | bool parsedLockPosition = false; | |||
| 12157 | if (!readBoundedBitShort(*buf, bodyEndBit, parsedFieldLength) | |||
| 12158 | || !readBoundedRawChar8(*buf, bodyEndBit, parsedAttribFlags)) | |||
| 12159 | return fail(); | |||
| 12160 | ||||
| 12161 | // lockPosition (DXF 280) appears since R2007 (AC1021) per ODA §20.4.x / | |||
| 12162 | // ACadSharp. Read gate lowered AC1024->AC1021 so R2007/8/9 imports keep | |||
| 12163 | // it. The writer emits the matching bit for AC1021 and later; | |||
| 12164 | // parseDwgEntHandle repositions to objSize for version>AC1018 before | |||
| 12165 | // consuming the handle stream. | |||
| 12166 | if (version >= DRW::AC1021) { | |||
| 12167 | if (!readBoundedBit(*buf, bodyEndBit, parsedLockPosition)) | |||
| 12168 | return fail(); | |||
| 12169 | } | |||
| 12170 | ||||
| 12171 | if (!buf->isGood() || !sBuf->isGood()) | |||
| 12172 | return fail(); | |||
| 12173 | ||||
| 12174 | /* Common Entity Handle Data */ | |||
| 12175 | // The parent ATTRIB handle stream starts at objSize. Embedded MTEXT | |||
| 12176 | // handles follow it, so parse the parent first and consume the embedded | |||
| 12177 | // stream from the resulting position. | |||
| 12178 | std::uint64_t handleEndBit = 0; | |||
| 12179 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, | |||
| 12180 | handleEndBit)) | |||
| 12181 | return fail(); | |||
| 12182 | dwgBuffer handleProbe = buf->forkIndependent(); | |||
| 12183 | ret = DRW_Entity::parseDwgEntHandle(version, &handleProbe, true, | |||
| 12184 | handleEndBit); | |||
| 12185 | if (!ret) | |||
| 12186 | return fail(); | |||
| 12187 | ||||
| 12188 | if (hasEmbeddedMText) { | |||
| 12189 | if (!consumeEmbeddedMTextHandles(version, &handleProbe, | |||
| 12190 | embeddedMTextHandles, | |||
| 12191 | parsedMText.get(), handleEndBit)) | |||
| 12192 | return fail(); | |||
| 12193 | } | |||
| 12194 | ||||
| 12195 | dwgHandle parsedStyleH; | |||
| 12196 | if (!readBoundedDwgHandle(handleProbe, handleEndBit, 0, false, parsedStyleH) | |||
| 12197 | || !handleProbe.isGood() || !sBuf->isGood() | |||
| 12198 | || currentDwgBit(buf) > bodyEndBit | |||
| 12199 | || currentDwgBit(sBuf) > stringEndBit) | |||
| 12200 | return fail(); | |||
| 12201 | ||||
| 12202 | *sourceBuf = handleProbe; | |||
| 12203 | basePoint = parsedText.basePoint; | |||
| 12204 | secPoint = parsedText.secPoint; | |||
| 12205 | extPoint = parsedText.extPoint; | |||
| 12206 | thickness = parsedText.thickness; | |||
| 12207 | oblique = parsedText.oblique; | |||
| 12208 | angle = parsedText.angle; | |||
| 12209 | height = parsedText.height; | |||
| 12210 | widthscale = parsedText.widthscale; | |||
| 12211 | text = std::move(parsedText.text); | |||
| 12212 | textgen = parsedText.textgen; | |||
| 12213 | alignH = parsedText.alignH; | |||
| 12214 | alignV = parsedText.alignV; | |||
| 12215 | attVersion = parsedAttVersion; | |||
| 12216 | m_attributeType = parsedAttributeType; | |||
| 12217 | mtext = std::move(parsedMText); | |||
| 12218 | tag = std::move(parsedTag); | |||
| 12219 | m_fieldLength = parsedFieldLength; | |||
| 12220 | attribFlags = parsedAttribFlags; | |||
| 12221 | lockPosition = parsedLockPosition; | |||
| 12222 | styleH = parsedStyleH; | |||
| 12223 | DRW_DBG("text style Handle: ")DRW_dbg::dbg("text style Handle: "); DRW_DBGHL(styleH.code, styleH.size, styleH.ref)DRW_dbg::dbgHL(styleH.code, styleH.size, styleH.ref); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 12224 | return true; | |||
| 12225 | } | |||
| 12226 | ||||
| 12227 | bool DRW_Attrib::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 12228 | (void)bs; | |||
| 12229 | if (version >= DRW::AC1024 && version < DRW::AC1032 && (attVersion != 0 || mtext)) | |||
| 12230 | return false; | |||
| 12231 | const std::uint8_t attributeType = (m_attributeType == 0) ? 1 : m_attributeType; | |||
| 12232 | const bool hasEmbeddedMText = version >= DRW::AC1032 && attributeType != 1; | |||
| 12233 | if (hasEmbeddedMText && !mtext) | |||
| 12234 | return false; | |||
| 12235 | ||||
| 12236 | oType = 2; // ATTRIB class id — see dwgreader.cpp:1148 | |||
| 12237 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 12238 | ||||
| 12239 | // TEXT-body section — mirrors DRW_Attrib::parseDwg. | |||
| 12240 | // data_flags=0: emit every optional field unconditionally (same | |||
| 12241 | // strategy as DRW_Text::encodeDwg — simpler encoder, ~30 bytes larger). | |||
| 12242 | buf->putRawChar8(0); // data_flags=0 | |||
| 12243 | buf->putRawDouble(basePoint.z); // elevation RD | |||
| 12244 | buf->putRawDouble(basePoint.x); // insertion 2RD | |||
| 12245 | buf->putRawDouble(basePoint.y); | |||
| 12246 | buf->putDefaultDouble(basePoint.x, secPoint.x); // alignment 2DD | |||
| 12247 | buf->putDefaultDouble(basePoint.y, secPoint.y); | |||
| 12248 | buf->putExtrusion(extPoint, /*b_R2000_style=*/true); | |||
| 12249 | buf->putThickness(thickness, /*b_R2000_style=*/true); | |||
| 12250 | buf->putRawDouble(oblique); // oblique angle RD | |||
| 12251 | buf->putRawDouble(angle / ARAD57.29577951308232); // angle in radians RD | |||
| 12252 | buf->putRawDouble(height); // text height RD | |||
| 12253 | buf->putRawDouble(widthscale); // width factor RD | |||
| 12254 | dwgBufferW *sb = strBuf ? strBuf : buf; | |||
| 12255 | sb->putVariableText(version, text); // text string TV | |||
| 12256 | buf->putBitShort(static_cast<std::uint16_t>(textgen)); // generation flags BS | |||
| 12257 | buf->putBitShort(static_cast<std::uint16_t>(alignH)); // horiz align BS | |||
| 12258 | buf->putBitShort(static_cast<std::uint16_t>(alignV)); // vert align BS | |||
| 12259 | ||||
| 12260 | if (version >= DRW::AC1024) { | |||
| 12261 | buf->putRawChar8(hasEmbeddedMText && attVersion == 0 ? 1 : attVersion); | |||
| 12262 | } | |||
| 12263 | if (version >= DRW::AC1032) { | |||
| 12264 | buf->putRawChar8(attributeType); | |||
| 12265 | } | |||
| 12266 | ||||
| 12267 | dwgBufferW embeddedHandles; | |||
| 12268 | if (hasEmbeddedMText) { | |||
| 12269 | if (!encodeEmbeddedMTextDwg(version, buf, strBuf, &embeddedHandles, *mtext)) | |||
| 12270 | return false; | |||
| 12271 | } | |||
| 12272 | ||||
| 12273 | // ATTRIB-specific tail | |||
| 12274 | sb->putVariableText(version, tag); // tag TV | |||
| 12275 | buf->putBitShort(static_cast<std::uint16_t>(m_fieldLength)); // fieldLen BS | |||
| 12276 | buf->putRawChar8(attribFlags); // flags RC | |||
| 12277 | if (version >= DRW::AC1021) { | |||
| 12278 | buf->putBit(lockPosition ? 1 : 0); // lock position B (R2007a+) | |||
| 12279 | } | |||
| 12280 | ||||
| 12281 | if (!encodeDwgEntHandle(version, buf, handleBuf)) return false; | |||
| 12282 | ||||
| 12283 | dwgHandle sH; | |||
| 12284 | std::uint32_t sref = (styleH.ref == 0) ? 0x13 : styleH.ref; | |||
| 12285 | sH.code = 5; | |||
| 12286 | sH.ref = sref; | |||
| 12287 | sH.size = 0; | |||
| 12288 | if (sref != 0) { std::uint32_t t = sref; while (t != 0) { t >>= 8; ++sH.size; } } | |||
| 12289 | dwgBufferW *hb = handleBuf ? handleBuf : buf; | |||
| 12290 | appendBitBuffer(hb, embeddedHandles); | |||
| 12291 | hb->putHandle(sH); | |||
| 12292 | return buf->isGood() && sb->isGood() && hb->isGood(); | |||
| 12293 | } | |||
| 12294 | ||||
| 12295 | bool DRW_Attdef::parseCode(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 12296 | switch (code) { | |||
| 12297 | case 3: | |||
| 12298 | prompt = reader->getUtf8String(); | |||
| 12299 | break; | |||
| 12300 | default: | |||
| 12301 | return DRW_Attrib::parseCode(code, reader); | |||
| 12302 | } | |||
| 12303 | return true; | |||
| 12304 | } | |||
| 12305 | ||||
| 12306 | bool DRW_Attdef::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){ | |||
| 12307 | // ATTDEF mirrors ATTRIB layout but adds a prompt string after the tag. | |||
| 12308 | // Implementation duplicates ATTRIB::parseDwg in order to inject the | |||
| 12309 | // prompt read at the correct offset; refactor opportunity if a third | |||
| 12310 | // sibling appears. | |||
| 12311 | resetAttribDwgState(); | |||
| 12312 | prompt.clear(); | |||
| 12313 | dwgBuffer *sourceBuf = buf; | |||
| 12314 | auto fail = [this, sourceBuf]() { | |||
| 12315 | if (sourceBuf != nullptr) | |||
| 12316 | sourceBuf->invalidate(); | |||
| 12317 | resetAttribDwgState(); | |||
| 12318 | prompt.clear(); | |||
| 12319 | return false; | |||
| 12320 | }; | |||
| 12321 | if (sourceBuf == nullptr) | |||
| 12322 | return fail(); | |||
| 12323 | ||||
| 12324 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 12325 | buf = &bodyProbe; | |||
| 12326 | dwgBuffer sBuff = bodyProbe.forkIndependent(); | |||
| 12327 | dwgBuffer *sBuf = &bodyProbe; | |||
| 12328 | if (version > DRW::AC1018) { | |||
| 12329 | sBuf = &sBuff; | |||
| 12330 | } | |||
| 12331 | bool ret = DRW_Entity::parseDwg(version, buf, sBuf, bs); | |||
| 12332 | if (!ret) | |||
| 12333 | return fail(); | |||
| 12334 | DRW_DBG("\n***************************** parsing attdef *********************************************\n")DRW_dbg::dbg("\n***************************** parsing attdef *********************************************\n" ); | |||
| 12335 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 12336 | std::uint64_t stringStartBit = bodyEndBit; | |||
| 12337 | std::uint64_t stringEndBit = bodyEndBit; | |||
| 12338 | if (version > DRW::AC1018 | |||
| 12339 | && (!buf->getR2007StringStreamBounds(objSize, stringStartBit, | |||
| 12340 | stringEndBit) | |||
| 12341 | || currentDwgBit(sBuf) > stringEndBit)) | |||
| 12342 | return fail(); | |||
| 12343 | ||||
| 12344 | DwgTextBodyData parsedText; | |||
| 12345 | if (!readBoundedDwgTextBody(version, *buf, *sBuf, bodyEndBit, | |||
| 12346 | stringStartBit, stringEndBit, parsedText)) | |||
| 12347 | return fail(); | |||
| 12348 | ||||
| 12349 | std::uint8_t parsedAttVersion = 0; | |||
| 12350 | std::uint8_t parsedAttributeType = 1; | |||
| 12351 | if (version >= DRW::AC1024) { | |||
| 12352 | if (!readBoundedRawChar8(*buf, bodyEndBit, parsedAttVersion)) | |||
| 12353 | return fail(); | |||
| 12354 | } | |||
| 12355 | if (version >= DRW::AC1032) { | |||
| 12356 | if (!readBoundedRawChar8(*buf, bodyEndBit, parsedAttributeType)) | |||
| 12357 | return fail(); | |||
| 12358 | } | |||
| 12359 | ||||
| 12360 | bool hasEmbeddedMText = false; | |||
| 12361 | EmbeddedMTextHandleInfo embeddedMTextHandles; | |||
| 12362 | std::unique_ptr<DRW_MText> parsedMText; | |||
| 12363 | if (version >= DRW::AC1032 | |||
| 12364 | && parsedAttributeType != 0 && parsedAttributeType != 1) { | |||
| 12365 | parsedMText = std::make_unique<DRW_MText>(); | |||
| 12366 | if (!parseEmbeddedMTextDwg(version, buf, sBuf, *parsedMText, | |||
| 12367 | embeddedMTextHandles, bodyEndBit, | |||
| 12368 | stringEndBit)) { | |||
| 12369 | DRW_DBG("R2018 multi-line ATTDEF payload failed\n")DRW_dbg::dbg("R2018 multi-line ATTDEF payload failed\n"); | |||
| 12370 | return fail(); | |||
| 12371 | } | |||
| 12372 | hasEmbeddedMText = true; | |||
| 12373 | } | |||
| 12374 | ||||
| 12375 | UTF8STRINGstd::string parsedTag; | |||
| 12376 | if (version <= DRW::AC1018 || stringStartBit < stringEndBit) { | |||
| 12377 | if (!readBoundedVariableText(*sBuf, stringEndBit, version, | |||
| 12378 | parsedTag)) | |||
| 12379 | return fail(); | |||
| 12380 | } | |||
| 12381 | ||||
| 12382 | std::uint16_t parsedFieldLength = 0; | |||
| 12383 | std::uint8_t parsedAttribFlags = 0; | |||
| 12384 | bool parsedLockPosition = false; | |||
| 12385 | if (!readBoundedBitShort(*buf, bodyEndBit, parsedFieldLength) | |||
| 12386 | || !readBoundedRawChar8(*buf, bodyEndBit, parsedAttribFlags)) | |||
| 12387 | return fail(); | |||
| 12388 | ||||
| 12389 | // lockPosition (DXF 280) is a bit in R2007+ DWG data. | |||
| 12390 | if (version >= DRW::AC1021) { | |||
| 12391 | if (!readBoundedBit(*buf, bodyEndBit, parsedLockPosition)) | |||
| 12392 | return fail(); | |||
| 12393 | } | |||
| 12394 | ||||
| 12395 | // ATTDEF prompt follows attrib body | |||
| 12396 | UTF8STRINGstd::string parsedPrompt; | |||
| 12397 | if (version <= DRW::AC1018 || stringStartBit < stringEndBit) { | |||
| 12398 | if (!readBoundedVariableText(*sBuf, stringEndBit, version, | |||
| 12399 | parsedPrompt)) | |||
| 12400 | return fail(); | |||
| 12401 | } | |||
| 12402 | ||||
| 12403 | if (!buf->isGood() || !sBuf->isGood()) | |||
| 12404 | return fail(); | |||
| 12405 | ||||
| 12406 | // The parent ATTDEF handle stream precedes the embedded MTEXT handles. | |||
| 12407 | std::uint64_t handleEndBit = 0; | |||
| 12408 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, | |||
| 12409 | handleEndBit)) | |||
| 12410 | return fail(); | |||
| 12411 | dwgBuffer handleProbe = buf->forkIndependent(); | |||
| 12412 | ret = DRW_Entity::parseDwgEntHandle(version, &handleProbe, true, | |||
| 12413 | handleEndBit); | |||
| 12414 | if (!ret) | |||
| 12415 | return fail(); | |||
| 12416 | ||||
| 12417 | if (hasEmbeddedMText) { | |||
| 12418 | if (!consumeEmbeddedMTextHandles(version, &handleProbe, | |||
| 12419 | embeddedMTextHandles, | |||
| 12420 | parsedMText.get(), handleEndBit)) | |||
| 12421 | return fail(); | |||
| 12422 | } | |||
| 12423 | ||||
| 12424 | dwgHandle parsedStyleH; | |||
| 12425 | if (!readBoundedDwgHandle(handleProbe, handleEndBit, 0, false, parsedStyleH) | |||
| 12426 | || !handleProbe.isGood() || !sBuf->isGood() | |||
| 12427 | || currentDwgBit(buf) > bodyEndBit | |||
| 12428 | || currentDwgBit(sBuf) > stringEndBit) | |||
| 12429 | return fail(); | |||
| 12430 | ||||
| 12431 | *sourceBuf = handleProbe; | |||
| 12432 | basePoint = parsedText.basePoint; | |||
| 12433 | secPoint = parsedText.secPoint; | |||
| 12434 | extPoint = parsedText.extPoint; | |||
| 12435 | thickness = parsedText.thickness; | |||
| 12436 | oblique = parsedText.oblique; | |||
| 12437 | angle = parsedText.angle; | |||
| 12438 | height = parsedText.height; | |||
| 12439 | widthscale = parsedText.widthscale; | |||
| 12440 | text = std::move(parsedText.text); | |||
| 12441 | textgen = parsedText.textgen; | |||
| 12442 | alignH = parsedText.alignH; | |||
| 12443 | alignV = parsedText.alignV; | |||
| 12444 | attVersion = parsedAttVersion; | |||
| 12445 | m_attributeType = parsedAttributeType; | |||
| 12446 | mtext = std::move(parsedMText); | |||
| 12447 | tag = std::move(parsedTag); | |||
| 12448 | m_fieldLength = parsedFieldLength; | |||
| 12449 | attribFlags = parsedAttribFlags; | |||
| 12450 | lockPosition = parsedLockPosition; | |||
| 12451 | prompt = std::move(parsedPrompt); | |||
| 12452 | styleH = parsedStyleH; | |||
| 12453 | return true; | |||
| 12454 | } | |||
| 12455 | ||||
| 12456 | bool DRW_Attdef::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 12457 | (void)bs; | |||
| 12458 | if (version >= DRW::AC1024 && version < DRW::AC1032 && (attVersion != 0 || mtext)) | |||
| 12459 | return false; | |||
| 12460 | const std::uint8_t attributeType = (m_attributeType == 0) ? 1 : m_attributeType; | |||
| 12461 | const bool hasEmbeddedMText = version >= DRW::AC1032 && attributeType != 1; | |||
| 12462 | if (hasEmbeddedMText && !mtext) | |||
| 12463 | return false; | |||
| 12464 | ||||
| 12465 | oType = 3; // ATTDEF class id — see dwgreader.cpp:1185 | |||
| 12466 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 12467 | ||||
| 12468 | // TEXT-body section — identical layout to DRW_Attrib::encodeDwg. | |||
| 12469 | buf->putRawChar8(0); | |||
| 12470 | buf->putRawDouble(basePoint.z); | |||
| 12471 | buf->putRawDouble(basePoint.x); | |||
| 12472 | buf->putRawDouble(basePoint.y); | |||
| 12473 | buf->putDefaultDouble(basePoint.x, secPoint.x); | |||
| 12474 | buf->putDefaultDouble(basePoint.y, secPoint.y); | |||
| 12475 | buf->putExtrusion(extPoint, /*b_R2000_style=*/true); | |||
| 12476 | buf->putThickness(thickness, /*b_R2000_style=*/true); | |||
| 12477 | buf->putRawDouble(oblique); | |||
| 12478 | buf->putRawDouble(angle / ARAD57.29577951308232); | |||
| 12479 | buf->putRawDouble(height); | |||
| 12480 | buf->putRawDouble(widthscale); | |||
| 12481 | dwgBufferW *sb = strBuf ? strBuf : buf; | |||
| 12482 | sb->putVariableText(version, text); | |||
| 12483 | buf->putBitShort(static_cast<std::uint16_t>(textgen)); | |||
| 12484 | buf->putBitShort(static_cast<std::uint16_t>(alignH)); | |||
| 12485 | buf->putBitShort(static_cast<std::uint16_t>(alignV)); | |||
| 12486 | ||||
| 12487 | if (version >= DRW::AC1024) { | |||
| 12488 | buf->putRawChar8(hasEmbeddedMText && attVersion == 0 ? 1 : attVersion); | |||
| 12489 | } | |||
| 12490 | if (version >= DRW::AC1032) { | |||
| 12491 | buf->putRawChar8(attributeType); | |||
| 12492 | } | |||
| 12493 | ||||
| 12494 | dwgBufferW embeddedHandles; | |||
| 12495 | if (hasEmbeddedMText) { | |||
| 12496 | if (!encodeEmbeddedMTextDwg(version, buf, strBuf, &embeddedHandles, *mtext)) | |||
| 12497 | return false; | |||
| 12498 | } | |||
| 12499 | ||||
| 12500 | sb->putVariableText(version, tag); | |||
| 12501 | buf->putBitShort(static_cast<std::uint16_t>(m_fieldLength)); // fieldLen BS | |||
| 12502 | buf->putRawChar8(attribFlags); | |||
| 12503 | if (version >= DRW::AC1021) { | |||
| 12504 | buf->putBit(lockPosition ? 1 : 0); | |||
| 12505 | } | |||
| 12506 | ||||
| 12507 | // ATTDEF adds prompt between flags and handle stream | |||
| 12508 | sb->putVariableText(version, prompt); | |||
| 12509 | ||||
| 12510 | if (!encodeDwgEntHandle(version, buf, handleBuf)) return false; | |||
| 12511 | ||||
| 12512 | dwgHandle sH; | |||
| 12513 | std::uint32_t sref = (styleH.ref == 0) ? 0x13 : styleH.ref; | |||
| 12514 | sH.code = 5; | |||
| 12515 | sH.ref = sref; | |||
| 12516 | sH.size = 0; | |||
| 12517 | if (sref != 0) { std::uint32_t t = sref; while (t != 0) { t >>= 8; ++sH.size; } } | |||
| 12518 | dwgBufferW *hb = handleBuf ? handleBuf : buf; | |||
| 12519 | appendBitBuffer(hb, embeddedHandles); | |||
| 12520 | hb->putHandle(sH); | |||
| 12521 | return buf->isGood() && sb->isGood() && hb->isGood(); | |||
| 12522 | } | |||
| 12523 | ||||
| 12524 | bool DRW_MText::parseCode(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 12525 | switch (code) { | |||
| 12526 | case 1: | |||
| 12527 | text += reader->getString(); | |||
| 12528 | text = reader->toUtf8String(text); | |||
| 12529 | break; | |||
| 12530 | case 11: | |||
| 12531 | hasXAxisVec = true; | |||
| 12532 | return DRW_Text::parseCode(code, reader); | |||
| 12533 | case 3: | |||
| 12534 | text += reader->getString(); | |||
| 12535 | break; | |||
| 12536 | case 44: | |||
| 12537 | interlin = reader->getDouble(); | |||
| 12538 | break; | |||
| 12539 | case 50: // djm: per dxf docs, last of code 11 or code 50 prevails | |||
| 12540 | hasXAxisVec = false; | |||
| 12541 | angle = reader->getDouble(); | |||
| 12542 | break; | |||
| 12543 | case 73: { | |||
| 12544 | const int value = reader->getInt32(); | |||
| 12545 | if (value < 0 || value > std::numeric_limits<std::uint16_t>::max()) | |||
| 12546 | return false; | |||
| 12547 | linespacingStyle = static_cast<std::uint16_t>(value); | |||
| 12548 | break; | |||
| 12549 | } | |||
| 12550 | case 42: | |||
| 12551 | m_r2018ExtentsWidth = reader->getDouble(); | |||
| 12552 | break; | |||
| 12553 | case 43: | |||
| 12554 | m_r2018ExtentsHeight = reader->getDouble(); | |||
| 12555 | break; | |||
| 12556 | case 45: | |||
| 12557 | m_backgroundScale = reader->getDouble(); | |||
| 12558 | break; | |||
| 12559 | case 63: | |||
| 12560 | m_backgroundColor = reader->getInt32(); | |||
| 12561 | break; | |||
| 12562 | case 90: | |||
| 12563 | m_backgroundFlags = reader->getInt32(); | |||
| 12564 | break; | |||
| 12565 | case 421: | |||
| 12566 | m_backgroundColor = reader->getInt32(); | |||
| 12567 | break; | |||
| 12568 | case 441: | |||
| 12569 | m_backgroundTransparency = reader->getInt32(); | |||
| 12570 | break; | |||
| 12571 | default: | |||
| 12572 | return DRW_Text::parseCode(code, reader); | |||
| 12573 | } | |||
| 12574 | ||||
| 12575 | return true; | |||
| 12576 | } | |||
| 12577 | ||||
| 12578 | void DRW_MText::resetDwgState() { | |||
| 12579 | DRW_Text::resetDwgState(); | |||
| 12580 | interlin = 1.0; | |||
| 12581 | linespacingStyle = 1; | |||
| 12582 | m_backgroundFlags = 0; | |||
| 12583 | m_backgroundScale = 0.0; | |||
| 12584 | m_backgroundColor = 0; | |||
| 12585 | m_backgroundTransparency = 0; | |||
| 12586 | hasXAxisVec = false; | |||
| 12587 | m_r2018IsNotAnnotative = false; | |||
| 12588 | m_r2018ReallyLocked = false; | |||
| 12589 | m_r2018Version = 0; | |||
| 12590 | m_r2018DefaultFlag = false; | |||
| 12591 | m_r2018AppIdHandle = 0; | |||
| 12592 | m_r2018Attachment = 0; | |||
| 12593 | m_r2018XAxisDir = {}; | |||
| 12594 | m_r2018InsertionPoint = {}; | |||
| 12595 | m_r2018RectWidth = 0.0; | |||
| 12596 | m_r2018RectHeight = 0.0; | |||
| 12597 | m_r2018ExtentsHeight = 0.0; | |||
| 12598 | m_r2018ExtentsWidth = 0.0; | |||
| 12599 | m_r2018ColumnType = 0; | |||
| 12600 | m_r2018ColumnCount = 0; | |||
| 12601 | m_r2018ColumnWidth = 0.0; | |||
| 12602 | m_r2018ColumnGutter = 0.0; | |||
| 12603 | m_r2018ColumnAutoHeight = false; | |||
| 12604 | m_r2018ColumnFlowReversed = false; | |||
| 12605 | m_r2018ColumnHeights.clear(); | |||
| 12606 | m_r2018AnnotativeData.clear(); | |||
| 12607 | m_r2018AnnotativeUnknown = 0; | |||
| 12608 | m_r2018AnnotativeAppHandle = 0; | |||
| 12609 | textgen = 1; | |||
| 12610 | alignV = static_cast<VAlign>(TopLeft); | |||
| 12611 | } | |||
| 12612 | ||||
| 12613 | bool DRW_MText::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){ | |||
| 12614 | // A reader may reuse an entity carrier while walking a compound stream. | |||
| 12615 | // R2018 context data is version-gated, so clear it before parsing an | |||
| 12616 | // older MTEXT or stale column/annotative state can leak into the result. | |||
| 12617 | resetDwgState(); | |||
| 12618 | dwgBuffer *sourceBuf = buf; | |||
| 12619 | auto fail = [this, sourceBuf]() { | |||
| 12620 | if (sourceBuf != nullptr) | |||
| 12621 | sourceBuf->invalidate(); | |||
| 12622 | resetDwgState(); | |||
| 12623 | return false; | |||
| 12624 | }; | |||
| 12625 | if (sourceBuf == nullptr) | |||
| 12626 | return fail(); | |||
| 12627 | ||||
| 12628 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 12629 | buf = &bodyProbe; | |||
| 12630 | ||||
| 12631 | dwgBuffer sBuff = buf->forkIndependent(); | |||
| 12632 | dwgBuffer *sBuf = buf; | |||
| 12633 | if (version > DRW::AC1018) {//2007+ | |||
| 12634 | sBuf = &sBuff; //separate buffer for strings | |||
| 12635 | } | |||
| 12636 | bool ret = DRW_Entity::parseDwg(version, buf, sBuf, bs); | |||
| 12637 | if (!ret) | |||
| 12638 | return fail(); | |||
| 12639 | DRW_DBG("\n***************************** parsing mtext *********************************************\n")DRW_dbg::dbg("\n***************************** parsing mtext *********************************************\n" ); | |||
| 12640 | ||||
| 12641 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 12642 | std::uint64_t stringStartBit = bodyEndBit; | |||
| 12643 | std::uint64_t stringEndBit = bodyEndBit; | |||
| 12644 | if (version > DRW::AC1018) { | |||
| 12645 | if (!buf->getR2007StringStreamBounds(objSize, stringStartBit, | |||
| 12646 | stringEndBit) | |||
| 12647 | || currentDwgBit(sBuf) > stringEndBit) | |||
| 12648 | return fail(); | |||
| 12649 | } | |||
| 12650 | ||||
| 12651 | const bool hasStringStream = stringStartBit < stringEndBit; | |||
| 12652 | const auto readText = [&](UTF8STRINGstd::string& value) { | |||
| 12653 | if (version > DRW::AC1018 && !hasStringStream) { | |||
| 12654 | value.clear(); | |||
| 12655 | return true; | |||
| 12656 | } | |||
| 12657 | const std::uint64_t endBit = version > DRW::AC1018 | |||
| 12658 | ? stringEndBit : bodyEndBit; | |||
| 12659 | return readBoundedVariableText(*sBuf, endBit, version, value); | |||
| 12660 | }; | |||
| 12661 | ||||
| 12662 | DRW_Coord parsedBasePoint; | |||
| 12663 | DRW_Coord parsedExtrusion; | |||
| 12664 | DRW_Coord parsedXAxisDirection; | |||
| 12665 | double parsedWidthScale = 0.0; | |||
| 12666 | double parsedRectangleHeight = 0.0; | |||
| 12667 | double parsedHeight = 0.0; | |||
| 12668 | std::uint16_t parsedAttachment = 1; | |||
| 12669 | std::uint16_t parsedDrawingDirection = 0; | |||
| 12670 | double ignoredExtentsHeight = 0.0; | |||
| 12671 | double ignoredExtentsWidth = 0.0; | |||
| 12672 | UTF8STRINGstd::string parsedText; | |||
| 12673 | std::uint16_t parsedLineSpacingStyle = 1; | |||
| 12674 | double parsedInterlin = 1.0; | |||
| 12675 | std::int32_t parsedBackgroundFlags = 0; | |||
| 12676 | double parsedBackgroundScale = 0.0; | |||
| 12677 | std::uint32_t parsedBackgroundColor = 0; | |||
| 12678 | std::int32_t parsedBackgroundTransparency = 0; | |||
| 12679 | bool parsedIsNotAnnotative = false; | |||
| 12680 | bool parsedReallyLocked = false; | |||
| 12681 | std::uint16_t parsedR2018Version = 0; | |||
| 12682 | bool parsedDefaultFlag = false; | |||
| 12683 | std::int32_t parsedR2018Attachment = 0; | |||
| 12684 | DRW_Coord parsedR2018XAxisDirection; | |||
| 12685 | DRW_Coord parsedR2018InsertionPoint; | |||
| 12686 | double parsedR2018RectangleWidth = 0.0; | |||
| 12687 | double parsedR2018RectangleHeight = 0.0; | |||
| 12688 | double parsedR2018ExtentsHeight = 0.0; | |||
| 12689 | double parsedR2018ExtentsWidth = 0.0; | |||
| 12690 | std::uint16_t parsedColumnType = 0; | |||
| 12691 | std::int32_t parsedColumnCount = 0; | |||
| 12692 | double parsedColumnWidth = 0.0; | |||
| 12693 | double parsedColumnGutter = 0.0; | |||
| 12694 | bool parsedColumnAutoHeight = false; | |||
| 12695 | bool parsedColumnFlowReversed = false; | |||
| 12696 | std::vector<double> parsedColumnHeights; | |||
| 12697 | ||||
| 12698 | if (!readBoundedBitCoord(*buf, bodyEndBit, parsedBasePoint) | |||
| 12699 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedExtrusion) | |||
| 12700 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedXAxisDirection) | |||
| 12701 | || !readBoundedBitDouble(*buf, bodyEndBit, parsedWidthScale) | |||
| 12702 | || (version > DRW::AC1018 | |||
| 12703 | && !readBoundedBitDouble(*buf, bodyEndBit, | |||
| 12704 | parsedRectangleHeight)) | |||
| 12705 | || !readBoundedBitDouble(*buf, bodyEndBit, parsedHeight) | |||
| 12706 | || !readBoundedBitShort(*buf, bodyEndBit, parsedAttachment) | |||
| 12707 | || !readBoundedBitShort(*buf, bodyEndBit, parsedDrawingDirection) | |||
| 12708 | || !readBoundedBitDouble(*buf, bodyEndBit, ignoredExtentsHeight) | |||
| 12709 | || !readBoundedBitDouble(*buf, bodyEndBit, ignoredExtentsWidth) | |||
| 12710 | || !readText(parsedText)) | |||
| 12711 | return fail(); | |||
| 12712 | ||||
| 12713 | if (version > DRW::AC1014 | |||
| 12714 | && (!readBoundedBitShort(*buf, bodyEndBit, parsedLineSpacingStyle) | |||
| 12715 | || !readBoundedBitDouble(*buf, bodyEndBit, parsedInterlin))) | |||
| 12716 | return fail(); | |||
| 12717 | bool ignoredBit = false; | |||
| 12718 | if (version > DRW::AC1014 && !readBoundedBit(*buf, bodyEndBit, | |||
| 12719 | ignoredBit)) | |||
| 12720 | return fail(); | |||
| 12721 | ||||
| 12722 | if (version > DRW::AC1015) { | |||
| 12723 | if (!readBoundedBitLong(*buf, bodyEndBit, parsedBackgroundFlags)) | |||
| 12724 | return fail(); | |||
| 12725 | const bool hasBackgroundDetails = (parsedBackgroundFlags & 0x01) != 0 | |||
| 12726 | || (version >= DRW::AC1032 | |||
| 12727 | && (parsedBackgroundFlags & 0x10) != 0); | |||
| 12728 | if (hasBackgroundDetails | |||
| 12729 | && (!readBoundedBitDouble(*buf, bodyEndBit, | |||
| 12730 | parsedBackgroundScale) | |||
| 12731 | || !readBoundedCmColor(*buf, sBuf, bodyEndBit, version, | |||
| 12732 | parsedBackgroundColor, nullptr, | |||
| 12733 | nullptr, nullptr, nullptr, | |||
| 12734 | stringEndBit) | |||
| 12735 | || !readBoundedBitLong(*buf, bodyEndBit, | |||
| 12736 | parsedBackgroundTransparency))) | |||
| 12737 | return fail(); | |||
| 12738 | } | |||
| 12739 | ||||
| 12740 | bool hasR2018AppId = false; | |||
| 12741 | if (version >= DRW::AC1032) { | |||
| 12742 | if (!readBoundedBit(*buf, bodyEndBit, parsedIsNotAnnotative)) | |||
| 12743 | return fail(); | |||
| 12744 | if (parsedIsNotAnnotative) { | |||
| 12745 | hasR2018AppId = true; | |||
| 12746 | if (!readBoundedBitShort(*buf, bodyEndBit, parsedR2018Version) | |||
| 12747 | || !readBoundedBit(*buf, bodyEndBit, parsedDefaultFlag) | |||
| 12748 | || !readBoundedBitLong(*buf, bodyEndBit, | |||
| 12749 | parsedR2018Attachment) | |||
| 12750 | || !readBoundedBitCoord(*buf, bodyEndBit, | |||
| 12751 | parsedR2018XAxisDirection) | |||
| 12752 | || !readBoundedBitCoord(*buf, bodyEndBit, | |||
| 12753 | parsedR2018InsertionPoint) | |||
| 12754 | || !readBoundedBitDouble(*buf, bodyEndBit, | |||
| 12755 | parsedR2018RectangleWidth) | |||
| 12756 | || !readBoundedBitDouble(*buf, bodyEndBit, | |||
| 12757 | parsedR2018RectangleHeight) | |||
| 12758 | || !readBoundedBitDouble(*buf, bodyEndBit, | |||
| 12759 | parsedR2018ExtentsHeight) | |||
| 12760 | || !readBoundedBitDouble(*buf, bodyEndBit, | |||
| 12761 | parsedR2018ExtentsWidth) | |||
| 12762 | || !readBoundedBitShort(*buf, bodyEndBit, parsedColumnType) | |||
| 12763 | || parsedColumnType > 2) | |||
| 12764 | return fail(); | |||
| 12765 | if (parsedColumnType != 0) { | |||
| 12766 | if (!readBoundedBitLong(*buf, bodyEndBit, parsedColumnCount) | |||
| 12767 | || !isValidCount(parsedColumnCount, | |||
| 12768 | kMaxMTextColumnHeights) | |||
| 12769 | || !readBoundedBitDouble(*buf, bodyEndBit, | |||
| 12770 | parsedColumnWidth) | |||
| 12771 | || !readBoundedBitDouble(*buf, bodyEndBit, | |||
| 12772 | parsedColumnGutter) | |||
| 12773 | || !readBoundedBit(*buf, bodyEndBit, | |||
| 12774 | parsedColumnAutoHeight) | |||
| 12775 | || !readBoundedBit(*buf, bodyEndBit, | |||
| 12776 | parsedColumnFlowReversed)) | |||
| 12777 | return fail(); | |||
| 12778 | if (!parsedColumnAutoHeight && parsedColumnType == 2 | |||
| 12779 | && parsedColumnCount > 0) { | |||
| 12780 | if (!DRW::reserve(parsedColumnHeights, | |||
| 12781 | parsedColumnCount)) | |||
| 12782 | return fail(); | |||
| 12783 | for (std::int32_t i = 0; i < parsedColumnCount; ++i) { | |||
| 12784 | double columnHeight = 0.0; | |||
| 12785 | if (!readBoundedBitDouble(*buf, bodyEndBit, | |||
| 12786 | columnHeight) | |||
| 12787 | || !std::isfinite(columnHeight)) | |||
| 12788 | return fail(); | |||
| 12789 | parsedColumnHeights.push_back(columnHeight); | |||
| 12790 | } | |||
| 12791 | } | |||
| 12792 | } | |||
| 12793 | } | |||
| 12794 | } | |||
| 12795 | ||||
| 12796 | const auto finite = [](const DRW_Coord& point) { | |||
| 12797 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 12798 | && std::isfinite(point.z); | |||
| 12799 | }; | |||
| 12800 | if (!buf->isGood() || !sBuf->isGood() | |||
| 12801 | || !finite(parsedBasePoint) || !finite(parsedExtrusion) | |||
| 12802 | || !finite(parsedXAxisDirection) | |||
| 12803 | || !std::isfinite(parsedWidthScale) | |||
| 12804 | || !std::isfinite(parsedRectangleHeight) | |||
| 12805 | || !std::isfinite(parsedHeight) | |||
| 12806 | || !std::isfinite(ignoredExtentsHeight) | |||
| 12807 | || !std::isfinite(ignoredExtentsWidth) | |||
| 12808 | || !std::isfinite(parsedInterlin) | |||
| 12809 | || !finite(parsedR2018XAxisDirection) | |||
| 12810 | || !finite(parsedR2018InsertionPoint) | |||
| 12811 | || !std::isfinite(parsedR2018RectangleWidth) | |||
| 12812 | || !std::isfinite(parsedR2018RectangleHeight) | |||
| 12813 | || !std::isfinite(parsedR2018ExtentsHeight) | |||
| 12814 | || !std::isfinite(parsedR2018ExtentsWidth)) | |||
| 12815 | return fail(); | |||
| 12816 | ||||
| 12817 | std::uint64_t handleEndBit = 0; | |||
| 12818 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, | |||
| 12819 | handleEndBit)) | |||
| 12820 | return fail(); | |||
| 12821 | dwgBuffer handleProbe = buf->forkIndependent(); | |||
| 12822 | if (!DRW_Entity::parseDwgEntHandle(version, &handleProbe, true, | |||
| 12823 | handleEndBit)) | |||
| 12824 | return fail(); | |||
| 12825 | ||||
| 12826 | dwgHandle parsedStyleH; | |||
| 12827 | if (!readBoundedDwgHandle(handleProbe, handleEndBit, 0, false, | |||
| 12828 | parsedStyleH)) | |||
| 12829 | return fail(); | |||
| 12830 | dwgHandle parsedAppIdH; | |||
| 12831 | if (hasR2018AppId | |||
| 12832 | && !readBoundedDwgHandle(handleProbe, handleEndBit, 0, false, | |||
| 12833 | parsedAppIdH)) | |||
| 12834 | return fail(); | |||
| 12835 | if (!handleProbe.isGood() || !sBuf->isGood()) | |||
| 12836 | return fail(); | |||
| 12837 | ||||
| 12838 | *sourceBuf = handleProbe; | |||
| 12839 | basePoint = parsedBasePoint; | |||
| 12840 | extPoint = parsedExtrusion; | |||
| 12841 | secPoint = parsedXAxisDirection; | |||
| 12842 | hasXAxisVec = true; | |||
| 12843 | widthscale = parsedWidthScale; | |||
| 12844 | height = parsedHeight; | |||
| 12845 | angle = atan2(secPoint.y, secPoint.x) * ARAD57.29577951308232; | |||
| 12846 | textgen = parsedAttachment; | |||
| 12847 | alignH = static_cast<HAlign>(parsedDrawingDirection); | |||
| 12848 | text = std::move(parsedText); | |||
| 12849 | linespacingStyle = parsedLineSpacingStyle; | |||
| 12850 | interlin = parsedInterlin; | |||
| 12851 | m_backgroundFlags = parsedBackgroundFlags; | |||
| 12852 | m_backgroundScale = parsedBackgroundScale; | |||
| 12853 | m_backgroundColor = static_cast<int>(parsedBackgroundColor); | |||
| 12854 | m_backgroundTransparency = parsedBackgroundTransparency; | |||
| 12855 | m_r2018IsNotAnnotative = parsedIsNotAnnotative; | |||
| 12856 | m_r2018Version = parsedR2018Version; | |||
| 12857 | m_r2018DefaultFlag = parsedDefaultFlag; | |||
| 12858 | m_r2018AppIdHandle = hasR2018AppId ? parsedAppIdH.ref : 0; | |||
| 12859 | m_r2018Attachment = parsedR2018Attachment; | |||
| 12860 | m_r2018XAxisDir = parsedR2018XAxisDirection; | |||
| 12861 | m_r2018InsertionPoint = parsedR2018InsertionPoint; | |||
| 12862 | m_r2018RectWidth = parsedR2018RectangleWidth; | |||
| 12863 | m_r2018RectHeight = parsedR2018RectangleHeight; | |||
| 12864 | m_r2018ExtentsHeight = parsedR2018ExtentsHeight; | |||
| 12865 | m_r2018ExtentsWidth = parsedR2018ExtentsWidth; | |||
| 12866 | m_r2018ColumnType = parsedColumnType; | |||
| 12867 | m_r2018ColumnCount = parsedColumnCount; | |||
| 12868 | m_r2018ColumnWidth = parsedColumnWidth; | |||
| 12869 | m_r2018ColumnGutter = parsedColumnGutter; | |||
| 12870 | m_r2018ColumnAutoHeight = parsedColumnAutoHeight; | |||
| 12871 | m_r2018ColumnFlowReversed = parsedColumnFlowReversed; | |||
| 12872 | m_r2018ColumnHeights = std::move(parsedColumnHeights); | |||
| 12873 | styleH = parsedStyleH; | |||
| 12874 | DRW_DBG("text style Handle: ")DRW_dbg::dbg("text style Handle: "); DRW_DBG(styleH.code)DRW_dbg::dbg(styleH.code); DRW_DBG(".")DRW_dbg::dbg("."); | |||
| 12875 | DRW_DBG(styleH.size)DRW_dbg::dbg(styleH.size); DRW_DBG(".")DRW_dbg::dbg("."); DRW_DBG(styleH.ref)DRW_dbg::dbg(styleH.ref); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 12876 | return true; | |||
| 12877 | } | |||
| 12878 | ||||
| 12879 | void DRW_MText::updateAngle() { | |||
| 12880 | if (hasXAxisVec) { | |||
| 12881 | angle = atan2(secPoint.y, secPoint.x) * ARAD57.29577951308232; | |||
| 12882 | } | |||
| 12883 | } | |||
| 12884 | ||||
| 12885 | bool DRW_Polyline::parseCode(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 12886 | switch (code) { | |||
| 12887 | case 70: | |||
| 12888 | flags = reader->getInt32(); | |||
| 12889 | break; | |||
| 12890 | case 40: | |||
| 12891 | defstawidth = reader->getDouble(); | |||
| 12892 | break; | |||
| 12893 | case 41: | |||
| 12894 | defendwidth = reader->getDouble(); | |||
| 12895 | break; | |||
| 12896 | case 71: | |||
| 12897 | vertexcount = reader->getInt32(); | |||
| 12898 | break; | |||
| 12899 | case 72: | |||
| 12900 | facecount = reader->getInt32(); | |||
| 12901 | break; | |||
| 12902 | case 73: | |||
| 12903 | smoothM = reader->getInt32(); | |||
| 12904 | break; | |||
| 12905 | case 74: | |||
| 12906 | smoothN = reader->getInt32(); | |||
| 12907 | break; | |||
| 12908 | case 75: | |||
| 12909 | curvetype = reader->getInt32(); | |||
| 12910 | break; | |||
| 12911 | default: | |||
| 12912 | return DRW_Point::parseCode(code, reader); | |||
| 12913 | } | |||
| 12914 | ||||
| 12915 | return true; | |||
| 12916 | } | |||
| 12917 | ||||
| 12918 | //0x0F polyline 2D bit 4(8) & 5(16) NOT set | |||
| 12919 | //0x10 polyline 3D bit 4(8) set | |||
| 12920 | //0x1D PFACE bit 5(16) set | |||
| 12921 | void DRW_Polyline::resetDwgState() { | |||
| 12922 | DRW_Point::resetDwgState(); | |||
| 12923 | flags = 0; | |||
| 12924 | defstawidth = 0.0; | |||
| 12925 | defendwidth = 0.0; | |||
| 12926 | vertexcount = 0; | |||
| 12927 | facecount = 0; | |||
| 12928 | smoothM = 0; | |||
| 12929 | smoothN = 0; | |||
| 12930 | curvetype = 0; | |||
| 12931 | vertlist.clear(); | |||
| 12932 | hadlesList.clear(); | |||
| 12933 | firstEH = 0; | |||
| 12934 | lastEH = 0; | |||
| 12935 | seqEndH = dwgHandle{}; | |||
| 12936 | } | |||
| 12937 | ||||
| 12938 | bool DRW_Polyline::validatePayloadFields() const { | |||
| 12939 | const auto finite = [](const DRW_Coord& point) { | |||
| 12940 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 12941 | && std::isfinite(point.z); | |||
| 12942 | }; | |||
| 12943 | const auto validBitShort = [](int value) { | |||
| 12944 | return value >= 0 | |||
| 12945 | && value <= std::numeric_limits<std::uint16_t>::max(); | |||
| 12946 | }; | |||
| 12947 | return flags >= 0 && flags <= std::numeric_limits<std::uint8_t>::max() | |||
| 12948 | && validBitShort(curvetype) && validBitShort(vertexcount) | |||
| 12949 | && validBitShort(facecount) && validBitShort(smoothM) | |||
| 12950 | && validBitShort(smoothN) && finite(basePoint) | |||
| 12951 | && finite(extPoint) && std::isfinite(defstawidth) | |||
| 12952 | && std::isfinite(defendwidth) && std::isfinite(thickness) | |||
| 12953 | && vertlist.size() <= dwgSafety::MaxOwnedObjectCount | |||
| 12954 | && vertlist.size() | |||
| 12955 | <= static_cast<std::size_t>(std::numeric_limits<std::int32_t>::max()) | |||
| 12956 | && std::all_of(vertlist.cbegin(), vertlist.cend(), | |||
| 12957 | [](const auto& vertex) { return vertex != nullptr; }); | |||
| 12958 | } | |||
| 12959 | ||||
| 12960 | bool DRW_Polyline::isDwgVertexCompatible( | |||
| 12961 | const DRW_Vertex& vertex) const noexcept { | |||
| 12962 | if ((flags & 64) != 0) { | |||
| 12963 | return vertex.dwgSubtype() == DRW_Vertex::DwgSubtype::Polyface | |||
| 12964 | || vertex.dwgSubtype() == DRW_Vertex::DwgSubtype::PolyfaceFace; | |||
| 12965 | } | |||
| 12966 | if ((flags & 16) != 0) | |||
| 12967 | return vertex.dwgSubtype() == DRW_Vertex::DwgSubtype::Mesh; | |||
| 12968 | if ((flags & 8) != 0) | |||
| 12969 | return vertex.dwgSubtype() == DRW_Vertex::DwgSubtype::Vertex3D; | |||
| 12970 | return vertex.dwgSubtype() == DRW_Vertex::DwgSubtype::Vertex2D; | |||
| 12971 | } | |||
| 12972 | ||||
| 12973 | bool DRW_Polyline::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){ | |||
| 12974 | resetDwgState(); | |||
| 12975 | dwgBuffer *sourceBuf = buf; | |||
| 12976 | auto fail = [this, sourceBuf]() { | |||
| 12977 | if (sourceBuf != nullptr) | |||
| 12978 | sourceBuf->invalidate(); | |||
| 12979 | resetDwgState(); | |||
| 12980 | return false; | |||
| 12981 | }; | |||
| 12982 | ||||
| 12983 | if (sourceBuf == nullptr) | |||
| 12984 | return fail(); | |||
| 12985 | ||||
| 12986 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 12987 | if (!DRW_Entity::parseDwgCommon(version, &bodyProbe, bs) | |||
| 12988 | || !bodyProbe.isGood()) | |||
| 12989 | return fail(); | |||
| 12990 | DRW_DBG("\n***************************** parsing polyline *********************************************\n")DRW_dbg::dbg("\n***************************** parsing polyline *********************************************\n" ); | |||
| 12991 | ||||
| 12992 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 12993 | int parsedFlags = 0; | |||
| 12994 | double parsedDefStartWidth = 0.0; | |||
| 12995 | double parsedDefEndWidth = 0.0; | |||
| 12996 | int parsedVertexCount = 0; | |||
| 12997 | int parsedFaceCount = 0; | |||
| 12998 | int parsedSmoothM = 0; | |||
| 12999 | int parsedSmoothN = 0; | |||
| 13000 | int parsedCurveType = 0; | |||
| 13001 | double parsedThickness = 0.0; | |||
| 13002 | DRW_Coord parsedBasePoint; | |||
| 13003 | DRW_Coord parsedExtrusion; | |||
| 13004 | std::int32_t ooCount = 0; | |||
| 13005 | if (oType == 0x0F) { //pline 2D | |||
| 13006 | std::uint16_t value = 0; | |||
| 13007 | if (!readBoundedBitShort(bodyProbe, bodyEndBit, value)) | |||
| 13008 | return fail(); | |||
| 13009 | parsedFlags = value; | |||
| 13010 | DRW_DBG("flags value: ")DRW_dbg::dbg("flags value: "); DRW_DBG(parsedFlags)DRW_dbg::dbg(parsedFlags); | |||
| 13011 | if (!readBoundedBitShort(bodyProbe, bodyEndBit, value)) | |||
| 13012 | return fail(); | |||
| 13013 | parsedCurveType = value; | |||
| 13014 | if (!readBoundedBitDouble(bodyProbe, bodyEndBit, parsedDefStartWidth) | |||
| 13015 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, parsedDefEndWidth) | |||
| 13016 | || !readBoundedThickness(bodyProbe, bodyEndBit, | |||
| 13017 | version > DRW::AC1014, parsedThickness) | |||
| 13018 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, parsedBasePoint.z) | |||
| 13019 | || !readBoundedExtrusion(bodyProbe, bodyEndBit, | |||
| 13020 | version > DRW::AC1014, parsedExtrusion)) | |||
| 13021 | return fail(); | |||
| 13022 | } else if (oType == 0x10) { //pline 3D | |||
| 13023 | std::uint8_t tmpFlag = 0; | |||
| 13024 | if (!readBoundedRawChar8(bodyProbe, bodyEndBit, tmpFlag)) | |||
| 13025 | return fail(); | |||
| 13026 | DRW_DBG("flags 1 value: ")DRW_dbg::dbg("flags 1 value: "); DRW_DBG(tmpFlag)DRW_dbg::dbg(tmpFlag); | |||
| 13027 | if (tmpFlag & 1) | |||
| 13028 | parsedCurveType = 5; // quadratic B-spline | |||
| 13029 | else if (tmpFlag & 2) | |||
| 13030 | parsedCurveType = 6; // cubic B-spline | |||
| 13031 | if (tmpFlag & 3) | |||
| 13032 | parsedFlags |= 4; // splined (bit 2); do NOT overwrite curvetype to 8 | |||
| 13033 | if (!readBoundedRawChar8(bodyProbe, bodyEndBit, tmpFlag)) | |||
| 13034 | return fail(); | |||
| 13035 | if (tmpFlag & 1) | |||
| 13036 | parsedFlags |= 1; | |||
| 13037 | parsedFlags |= 8; //indicate 3DPOL | |||
| 13038 | DRW_DBG("flags 2 value: ")DRW_dbg::dbg("flags 2 value: "); DRW_DBG(tmpFlag)DRW_dbg::dbg(tmpFlag); | |||
| 13039 | } else if (oType == 0x1D) { //PFACE | |||
| 13040 | std::uint16_t vertexValue = 0; | |||
| 13041 | std::uint16_t faceValue = 0; | |||
| 13042 | if (!readBoundedBitShort(bodyProbe, bodyEndBit, vertexValue) | |||
| 13043 | || !readBoundedBitShort(bodyProbe, bodyEndBit, faceValue)) | |||
| 13044 | return fail(); | |||
| 13045 | parsedFlags = 64; | |||
| 13046 | parsedVertexCount = vertexValue; | |||
| 13047 | parsedFaceCount = faceValue; | |||
| 13048 | DRW_DBG("vertex count: ")DRW_dbg::dbg("vertex count: "); DRW_DBG(parsedVertexCount)DRW_dbg::dbg(parsedVertexCount); | |||
| 13049 | DRW_DBG("face count: ")DRW_dbg::dbg("face count: "); DRW_DBG(parsedFaceCount)DRW_dbg::dbg(parsedFaceCount); | |||
| 13050 | DRW_DBG("flags value: ")DRW_dbg::dbg("flags value: "); DRW_DBG(parsedFlags)DRW_dbg::dbg(parsedFlags); | |||
| 13051 | } else if (oType == 0x1E) { //POLYLINE_MESH per ODA spec sec 19.4.31 | |||
| 13052 | std::uint16_t value = 0; | |||
| 13053 | if (!readBoundedBitShort(bodyProbe, bodyEndBit, value)) | |||
| 13054 | return fail(); | |||
| 13055 | parsedFlags = value | 16; //bit 4 = 3D polygon mesh | |||
| 13056 | DRW_DBG("flags value: ")DRW_dbg::dbg("flags value: "); DRW_DBG(parsedFlags)DRW_dbg::dbg(parsedFlags); | |||
| 13057 | if (!readBoundedBitShort(bodyProbe, bodyEndBit, value)) | |||
| 13058 | return fail(); | |||
| 13059 | parsedCurveType = value; | |||
| 13060 | if (!readBoundedBitShort(bodyProbe, bodyEndBit, value)) | |||
| 13061 | return fail(); | |||
| 13062 | parsedVertexCount = value; //M-count | |||
| 13063 | DRW_DBG(" M count: ")DRW_dbg::dbg(" M count: "); DRW_DBG(parsedVertexCount)DRW_dbg::dbg(parsedVertexCount); | |||
| 13064 | if (!readBoundedBitShort(bodyProbe, bodyEndBit, value)) | |||
| 13065 | return fail(); | |||
| 13066 | parsedFaceCount = value; //N-count | |||
| 13067 | DRW_DBG(" N count: ")DRW_dbg::dbg(" N count: "); DRW_DBG(parsedFaceCount)DRW_dbg::dbg(parsedFaceCount); | |||
| 13068 | if (!readBoundedBitShort(bodyProbe, bodyEndBit, value)) | |||
| 13069 | return fail(); | |||
| 13070 | parsedSmoothM = value; //M smooth-surface density, DXF 73 | |||
| 13071 | if (!readBoundedBitShort(bodyProbe, bodyEndBit, value)) | |||
| 13072 | return fail(); | |||
| 13073 | parsedSmoothN = value; //N smooth-surface density, DXF 74 | |||
| 13074 | DRW_DBG(" M/N density: ")DRW_dbg::dbg(" M/N density: "); DRW_DBG(parsedSmoothM)DRW_dbg::dbg(parsedSmoothM); DRW_DBG("/")DRW_dbg::dbg("/"); DRW_DBG(parsedSmoothN)DRW_dbg::dbg(parsedSmoothN); | |||
| 13075 | } else { | |||
| 13076 | return fail(); | |||
| 13077 | } | |||
| 13078 | if (version > DRW::AC1015){ //2004+ | |||
| 13079 | if (!readBoundedBitLong(bodyProbe, bodyEndBit, ooCount) | |||
| 13080 | || !dwgSafety::validOwnedObjectCount( | |||
| 13081 | ooCount, bodyProbe.numRemainingBytes())) { | |||
| 13082 | DRW_DBG("\nWARNING: Invalid POLYLINE owned-object count\n")DRW_dbg::dbg("\nWARNING: Invalid POLYLINE owned-object count\n" ); | |||
| 13083 | return fail(); | |||
| 13084 | } | |||
| 13085 | } | |||
| 13086 | ||||
| 13087 | std::uint64_t handleEndBit = 0; | |||
| 13088 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, | |||
| 13089 | handleEndBit)) | |||
| 13090 | return fail(); | |||
| 13091 | dwgBuffer handleProbe = bodyProbe.forkIndependent(); | |||
| 13092 | if (!DRW_Entity::parseDwgEntHandle(version, &handleProbe, true, | |||
| 13093 | handleEndBit) | |||
| 13094 | || !handleProbe.isGood()) | |||
| 13095 | return fail(); | |||
| 13096 | ||||
| 13097 | std::list<std::uint32_t> parsedHandles; | |||
| 13098 | std::uint32_t parsedFirstEH = 0; | |||
| 13099 | std::uint32_t parsedLastEH = 0; | |||
| 13100 | ||||
| 13101 | if (version < DRW::AC1018){ //2000- | |||
| 13102 | dwgHandle objectH; | |||
| 13103 | if (!readBoundedDwgHandle(handleProbe, handleEndBit, handle, true, | |||
| 13104 | objectH)) | |||
| 13105 | return fail(); | |||
| 13106 | parsedFirstEH = objectH.ref; | |||
| 13107 | DRW_DBG(" first Vertex Handle: ")DRW_dbg::dbg(" first Vertex Handle: "); DRW_DBGHL(objectH.code, objectH.size, objectH.ref)DRW_dbg::dbgHL(objectH.code, objectH.size, objectH.ref); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 13108 | if (!readBoundedDwgHandle(handleProbe, handleEndBit, handle, true, | |||
| 13109 | objectH)) | |||
| 13110 | return fail(); | |||
| 13111 | parsedLastEH = objectH.ref; | |||
| 13112 | DRW_DBG(" last Vertex Handle: ")DRW_dbg::dbg(" last Vertex Handle: "); DRW_DBGHL(objectH.code, objectH.size, objectH.ref)DRW_dbg::dbgHL(objectH.code, objectH.size, objectH.ref); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 13113 | DRW_DBG("Remaining bytes: ")DRW_dbg::dbg("Remaining bytes: "); DRW_DBG(handleProbe.numRemainingBytes())DRW_dbg::dbg(handleProbe.numRemainingBytes()); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 13114 | } else { | |||
| 13115 | for (std::int32_t i = 0; i < ooCount; ++i){ | |||
| 13116 | dwgHandle objectH; | |||
| 13117 | if (!readBoundedDwgHandle(handleProbe, handleEndBit, handle, | |||
| 13118 | true, objectH)) | |||
| 13119 | return fail(); | |||
| 13120 | try { | |||
| 13121 | parsedHandles.push_back(objectH.ref); | |||
| 13122 | } catch (...) { | |||
| 13123 | return fail(); | |||
| 13124 | } | |||
| 13125 | DRW_DBG(" Vertex Handle: ")DRW_dbg::dbg(" Vertex Handle: "); DRW_DBGHL(objectH.code, objectH.size, objectH.ref)DRW_dbg::dbgHL(objectH.code, objectH.size, objectH.ref); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 13126 | DRW_DBG("Remaining bytes: ")DRW_dbg::dbg("Remaining bytes: "); DRW_DBG(handleProbe.numRemainingBytes())DRW_dbg::dbg(handleProbe.numRemainingBytes()); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 13127 | } | |||
| 13128 | } | |||
| 13129 | dwgHandle parsedSeqEndH; | |||
| 13130 | if (!readBoundedDwgHandle(handleProbe, handleEndBit, handle, true, | |||
| 13131 | parsedSeqEndH)) | |||
| 13132 | return fail(); | |||
| 13133 | if (!handleProbe.isGood()) | |||
| 13134 | return fail(); | |||
| 13135 | *sourceBuf = handleProbe; | |||
| 13136 | flags = parsedFlags; | |||
| 13137 | defstawidth = parsedDefStartWidth; | |||
| 13138 | defendwidth = parsedDefEndWidth; | |||
| 13139 | vertexcount = parsedVertexCount; | |||
| 13140 | facecount = parsedFaceCount; | |||
| 13141 | smoothM = parsedSmoothM; | |||
| 13142 | smoothN = parsedSmoothN; | |||
| 13143 | curvetype = parsedCurveType; | |||
| 13144 | thickness = parsedThickness; | |||
| 13145 | basePoint = parsedBasePoint; | |||
| 13146 | extPoint = parsedExtrusion; | |||
| 13147 | firstEH = parsedFirstEH; | |||
| 13148 | lastEH = parsedLastEH; | |||
| 13149 | seqEndH = parsedSeqEndH; | |||
| 13150 | hadlesList = std::move(parsedHandles); | |||
| 13151 | DRW_DBG(" SEQEND Handle: ")DRW_dbg::dbg(" SEQEND Handle: "); DRW_DBGHL(seqEndH.code, seqEndH.size, seqEndH.ref)DRW_dbg::dbgHL(seqEndH.code, seqEndH.size, seqEndH.ref); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 13152 | DRW_DBG("Remaining bytes: ")DRW_dbg::dbg("Remaining bytes: "); DRW_DBG(buf->numRemainingBytes())DRW_dbg::dbg(buf->numRemainingBytes()); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 13153 | ||||
| 13154 | // RS crc; //RS */ | |||
| 13155 | return buf->isGood(); | |||
| 13156 | } | |||
| 13157 | ||||
| 13158 | bool DRW_Vertex::parseCode(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 13159 | switch (code) { | |||
| 13160 | case 70: | |||
| 13161 | flags = reader->getInt32(); | |||
| 13162 | break; | |||
| 13163 | case 40: | |||
| 13164 | stawidth = reader->getDouble(); | |||
| 13165 | break; | |||
| 13166 | case 41: | |||
| 13167 | endwidth = reader->getDouble(); | |||
| 13168 | break; | |||
| 13169 | case 42: | |||
| 13170 | bulge = reader->getDouble(); | |||
| 13171 | break; | |||
| 13172 | case 50: | |||
| 13173 | tgdir = reader->getDouble(); | |||
| 13174 | break; | |||
| 13175 | case 71: | |||
| 13176 | vindex1 = reader->getInt32(); | |||
| 13177 | break; | |||
| 13178 | case 72: | |||
| 13179 | vindex2 = reader->getInt32(); | |||
| 13180 | break; | |||
| 13181 | case 73: | |||
| 13182 | vindex3 = reader->getInt32(); | |||
| 13183 | break; | |||
| 13184 | case 74: | |||
| 13185 | vindex4 = reader->getInt32(); | |||
| 13186 | break; | |||
| 13187 | case 91: | |||
| 13188 | identifier = reader->getInt32(); | |||
| 13189 | break; | |||
| 13190 | default: | |||
| 13191 | return DRW_Point::parseCode(code, reader); | |||
| 13192 | } | |||
| 13193 | ||||
| 13194 | return true; | |||
| 13195 | } | |||
| 13196 | ||||
| 13197 | //0x0A vertex 2D | |||
| 13198 | //0x0B vertex 3D | |||
| 13199 | //0x0C MESH | |||
| 13200 | //0x0D PFACE | |||
| 13201 | //0x0E PFACE FACE | |||
| 13202 | void DRW_Vertex::resetDwgState() { | |||
| 13203 | DRW_Point::resetDwgState(); | |||
| 13204 | stawidth = 0.0; | |||
| 13205 | endwidth = 0.0; | |||
| 13206 | bulge = 0.0; | |||
| 13207 | flags = 0; | |||
| 13208 | tgdir = 0.0; | |||
| 13209 | vindex1 = vindex2 = vindex3 = vindex4 = 0; | |||
| 13210 | identifier = 0; | |||
| 13211 | m_dwgSubtype = DwgSubtype::Auto; | |||
| 13212 | } | |||
| 13213 | ||||
| 13214 | bool DRW_Vertex::validatePayloadFields() const { | |||
| 13215 | const auto finite = [](const DRW_Coord& point) { | |||
| 13216 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 13217 | && std::isfinite(point.z); | |||
| 13218 | }; | |||
| 13219 | const auto validFaceIndex = [](int value) { | |||
| 13220 | return value >= std::numeric_limits<std::int16_t>::min() | |||
| 13221 | && value <= std::numeric_limits<std::int16_t>::max(); | |||
| 13222 | }; | |||
| 13223 | const auto validInt32 = [](int value) { | |||
| 13224 | return value >= std::numeric_limits<std::int32_t>::min() | |||
| 13225 | && value <= std::numeric_limits<std::int32_t>::max(); | |||
| 13226 | }; | |||
| 13227 | return flags >= 0 && flags <= std::numeric_limits<std::uint8_t>::max() | |||
| 13228 | && validFaceIndex(vindex1) && validFaceIndex(vindex2) | |||
| 13229 | && validFaceIndex(vindex3) && validFaceIndex(vindex4) | |||
| 13230 | && validInt32(identifier) && finite(basePoint) | |||
| 13231 | && std::isfinite(stawidth) && std::isfinite(endwidth) | |||
| 13232 | && std::isfinite(bulge) && std::isfinite(tgdir); | |||
| 13233 | } | |||
| 13234 | ||||
| 13235 | bool DRW_Vertex::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs, double el){ | |||
| 13236 | resetDwgState(); | |||
| 13237 | dwgBuffer *sourceBuf = buf; | |||
| 13238 | auto fail = [this, sourceBuf]() { | |||
| 13239 | if (sourceBuf != nullptr) | |||
| 13240 | sourceBuf->invalidate(); | |||
| 13241 | resetDwgState(); | |||
| 13242 | return false; | |||
| 13243 | }; | |||
| 13244 | ||||
| 13245 | if (sourceBuf == nullptr) | |||
| 13246 | return fail(); | |||
| 13247 | ||||
| 13248 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 13249 | if (!DRW_Entity::parseDwgCommon(version, &bodyProbe, bs) | |||
| 13250 | || !bodyProbe.isGood()) | |||
| 13251 | return fail(); | |||
| 13252 | DRW_DBG("\n***************************** parsing pline Vertex *********************************************\n")DRW_dbg::dbg("\n***************************** parsing pline Vertex *********************************************\n" ); | |||
| 13253 | ||||
| 13254 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 13255 | DRW_Vertex::DwgSubtype parsedSubtype = DRW_Vertex::DwgSubtype::Auto; | |||
| 13256 | std::uint8_t parsedFlags = 0; | |||
| 13257 | DRW_Coord parsedBasePoint; | |||
| 13258 | double parsedStartWidth = 0.0; | |||
| 13259 | double parsedEndWidth = 0.0; | |||
| 13260 | double parsedBulge = 0.0; | |||
| 13261 | double parsedTangentDirection = 0.0; | |||
| 13262 | int parsedIndex1 = 0; | |||
| 13263 | int parsedIndex2 = 0; | |||
| 13264 | int parsedIndex3 = 0; | |||
| 13265 | int parsedIndex4 = 0; | |||
| 13266 | int parsedIdentifier = 0; | |||
| 13267 | if (oType == 0x0A) { //pline 2D, needed example | |||
| 13268 | parsedSubtype = DwgSubtype::Vertex2D; | |||
| 13269 | if (!readBoundedRawChar8(bodyProbe, bodyEndBit, parsedFlags) | |||
| 13270 | || !readBoundedBitCoord(bodyProbe, bodyEndBit, parsedBasePoint) | |||
| 13271 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, parsedStartWidth)) | |||
| 13272 | return fail(); | |||
| 13273 | parsedBasePoint.z = el; | |||
| 13274 | DRW_DBG("flags value: ")DRW_dbg::dbg("flags value: "); DRW_DBG(parsedFlags)DRW_dbg::dbg(parsedFlags); | |||
| 13275 | DRW_DBG("basePoint: ")DRW_dbg::dbg("basePoint: "); DRW_DBGPT(parsedBasePoint.x, parsedBasePoint.y, parsedBasePoint.z)DRW_dbg::dbgPT(parsedBasePoint.x, parsedBasePoint.y, parsedBasePoint .z); | |||
| 13276 | if (parsedStartWidth < 0.0) { | |||
| 13277 | parsedEndWidth = parsedStartWidth = std::fabs(parsedStartWidth); | |||
| 13278 | } else if (!readBoundedBitDouble(bodyProbe, bodyEndBit, | |||
| 13279 | parsedEndWidth)) { | |||
| 13280 | return fail(); | |||
| 13281 | } | |||
| 13282 | if (!readBoundedBitDouble(bodyProbe, bodyEndBit, parsedBulge)) | |||
| 13283 | return fail(); | |||
| 13284 | if (version > DRW::AC1021) { //2010+ | |||
| 13285 | if (!readBoundedBitLong(bodyProbe, bodyEndBit, parsedIdentifier)) | |||
| 13286 | return fail(); | |||
| 13287 | DRW_DBG("Vertex ID: ")DRW_dbg::dbg("Vertex ID: "); DRW_DBG(parsedIdentifier)DRW_dbg::dbg(parsedIdentifier); | |||
| 13288 | } | |||
| 13289 | if (!readBoundedBitDouble(bodyProbe, bodyEndBit, | |||
| 13290 | parsedTangentDirection)) | |||
| 13291 | return fail(); | |||
| 13292 | } else if (oType == 0x0B || oType == 0x0C || oType == 0x0D) { //PFACE | |||
| 13293 | if (oType == 0x0B) | |||
| 13294 | parsedSubtype = DwgSubtype::Vertex3D; | |||
| 13295 | else if (oType == 0x0C) | |||
| 13296 | parsedSubtype = DwgSubtype::Mesh; | |||
| 13297 | else | |||
| 13298 | parsedSubtype = DwgSubtype::Polyface; | |||
| 13299 | if (!readBoundedRawChar8(bodyProbe, bodyEndBit, parsedFlags) | |||
| 13300 | || !readBoundedBitCoord(bodyProbe, bodyEndBit, parsedBasePoint)) | |||
| 13301 | return fail(); | |||
| 13302 | DRW_DBG("flags value: ")DRW_dbg::dbg("flags value: "); DRW_DBG(parsedFlags)DRW_dbg::dbg(parsedFlags); | |||
| 13303 | DRW_DBG("basePoint: ")DRW_dbg::dbg("basePoint: "); DRW_DBGPT(parsedBasePoint.x, parsedBasePoint.y, parsedBasePoint.z)DRW_dbg::dbgPT(parsedBasePoint.x, parsedBasePoint.y, parsedBasePoint .z); | |||
| 13304 | } else if (oType == 0x0E) { //PFACE FACE | |||
| 13305 | parsedSubtype = DwgSubtype::PolyfaceFace; | |||
| 13306 | auto signedIndex = [](std::uint16_t value) { | |||
| 13307 | return value > 32767 ? value - 65536 : value; | |||
| 13308 | }; | |||
| 13309 | std::uint16_t value = 0; | |||
| 13310 | if (!readBoundedBitShort(bodyProbe, bodyEndBit, value)) | |||
| 13311 | return fail(); | |||
| 13312 | parsedIndex1 = signedIndex(value); | |||
| 13313 | if (!readBoundedBitShort(bodyProbe, bodyEndBit, value)) | |||
| 13314 | return fail(); | |||
| 13315 | parsedIndex2 = signedIndex(value); | |||
| 13316 | if (!readBoundedBitShort(bodyProbe, bodyEndBit, value)) | |||
| 13317 | return fail(); | |||
| 13318 | parsedIndex3 = signedIndex(value); | |||
| 13319 | if (!readBoundedBitShort(bodyProbe, bodyEndBit, value)) | |||
| 13320 | return fail(); | |||
| 13321 | parsedIndex4 = signedIndex(value); | |||
| 13322 | } else { | |||
| 13323 | return fail(); | |||
| 13324 | } | |||
| 13325 | ||||
| 13326 | const auto finite = [](const DRW_Coord& point) { | |||
| 13327 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 13328 | && std::isfinite(point.z); | |||
| 13329 | }; | |||
| 13330 | if (!finite(parsedBasePoint) || !std::isfinite(parsedStartWidth) | |||
| 13331 | || !std::isfinite(parsedEndWidth) || !std::isfinite(parsedBulge) | |||
| 13332 | || !std::isfinite(parsedTangentDirection) | |||
| 13333 | || !std::isfinite(el)) | |||
| 13334 | return fail(); | |||
| 13335 | ||||
| 13336 | std::uint64_t handleEndBit = 0; | |||
| 13337 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, | |||
| 13338 | handleEndBit)) | |||
| 13339 | return fail(); | |||
| 13340 | dwgBuffer handleProbe = bodyProbe.forkIndependent(); | |||
| 13341 | if (!DRW_Entity::parseDwgEntHandle(version, &handleProbe, true, | |||
| 13342 | handleEndBit) | |||
| 13343 | || !handleProbe.isGood()) | |||
| 13344 | return fail(); | |||
| 13345 | // RS crc; //RS */ | |||
| 13346 | *sourceBuf = handleProbe; | |||
| 13347 | m_dwgSubtype = parsedSubtype; | |||
| 13348 | flags = parsedFlags; | |||
| 13349 | basePoint = parsedBasePoint; | |||
| 13350 | stawidth = parsedStartWidth; | |||
| 13351 | endwidth = parsedEndWidth; | |||
| 13352 | bulge = parsedBulge; | |||
| 13353 | tgdir = parsedTangentDirection; | |||
| 13354 | vindex1 = parsedIndex1; | |||
| 13355 | vindex2 = parsedIndex2; | |||
| 13356 | vindex3 = parsedIndex3; | |||
| 13357 | vindex4 = parsedIndex4; | |||
| 13358 | identifier = parsedIdentifier; | |||
| 13359 | return true; | |||
| 13360 | } | |||
| 13361 | ||||
| 13362 | bool DRW_Hatch::parseCode(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 13363 | try { | |||
| 13364 | switch (code) { | |||
| 13365 | case 2: | |||
| 13366 | name = reader->getUtf8String(); | |||
| 13367 | break; | |||
| 13368 | case 70: | |||
| 13369 | solid = reader->getInt32(); | |||
| 13370 | break; | |||
| 13371 | case 71: | |||
| 13372 | associative = reader->getInt32(); | |||
| 13373 | break; | |||
| 13374 | case 72: { /*edge type*/ | |||
| 13375 | if (ispol){ // polyline path: 72 is the has-bulge flag. Do NOT fold it | |||
| 13376 | // into pline->flags — bit 0 there is the *closed* flag (set by code | |||
| 13377 | // 73), and the per-vertex bulges arrive via code 42 regardless. Some | |||
| 13378 | // writers (e.g. ezdxf MPOLYGON) emit 73 before 72; the old code let | |||
| 13379 | // 72 clear the closed bit 73 had just set, leaving the boundary open | |||
| 13380 | // so RS_Hatch::validate() rejected the area. | |||
| 13381 | break; | |||
| 13382 | } | |||
| 13383 | if (spline && !validateCurrentSplineDxf()) | |||
| 13384 | return false; | |||
| 13385 | if (!loop | |||
| 13386 | || loop->objlist.size() >= static_cast<std::size_t>(kMaxHatchItems) | |||
| 13387 | || (m_dxfLoopEdgeCountExpected >= 0 | |||
| 13388 | && loop->objlist.size() | |||
| 13389 | >= static_cast<std::size_t>(m_dxfLoopEdgeCountExpected))) | |||
| 13390 | return false; | |||
| 13391 | const int edgeType = reader->getInt32(); | |||
| 13392 | if (edgeType == 1){ //line | |||
| 13393 | addLine(); | |||
| 13394 | } else if (edgeType == 2){ //arc | |||
| 13395 | addArc(); | |||
| 13396 | } else if (edgeType == 3){ //elliptic arc | |||
| 13397 | addEllipse(); | |||
| 13398 | } else if (edgeType == 4){ //spline | |||
| 13399 | addSpline(); | |||
| 13400 | } else { | |||
| 13401 | return false; | |||
| 13402 | } | |||
| 13403 | break; | |||
| 13404 | } | |||
| 13405 | case 10: | |||
| 13406 | // Spline edge: 10 is a control-point x-coord. | |||
| 13407 | if (spline) { | |||
| 13408 | if (spline->controllist.size() >= static_cast<std::size_t>(kMaxHatchItems) | |||
| 13409 | || (m_dxfSplineControlCountExpected >= 0 | |||
| 13410 | && spline->controllist.size() | |||
| 13411 | >= static_cast<std::size_t>(m_dxfSplineControlCountExpected))) | |||
| 13412 | return false; | |||
| 13413 | spline->controllist.push_back(std::make_shared<DRW_Coord>(reader->getDouble(), 0.0, 0.0)); | |||
| 13414 | break; | |||
| 13415 | } | |||
| 13416 | if (pt) pt->basePoint.x = reader->getDouble(); | |||
| 13417 | else if (pline) { | |||
| 13418 | if (pline->vertlist.size() >= static_cast<std::size_t>(kMaxHatchItems) | |||
| 13419 | || (m_dxfPolylineVertexCountExpected >= 0 | |||
| 13420 | && pline->vertlist.size() | |||
| 13421 | >= static_cast<std::size_t>(m_dxfPolylineVertexCountExpected))) | |||
| 13422 | return false; | |||
| 13423 | plvert = pline->addVertex(); | |||
| 13424 | plvert->x = reader->getDouble(); | |||
| 13425 | } else if (m_dxfSeedPointsExpected < 0) { | |||
| 13426 | return DRW_Point::parseCode(code, reader); | |||
| 13427 | } else { | |||
| 13428 | // After group 98 the boundary path is closed; seed-point | |||
| 13429 | // coords arrive as group-10/20 pairs. | |||
| 13430 | if (seedPoints.size() >= static_cast<std::size_t>(m_dxfSeedPointsExpected)) | |||
| 13431 | return false; | |||
| 13432 | DRW_Coord seed; | |||
| 13433 | seed.x = reader->getDouble(); | |||
| 13434 | seedPoints.push_back(seed); | |||
| 13435 | } | |||
| 13436 | break; | |||
| 13437 | case 20: | |||
| 13438 | if (spline && !spline->controllist.empty()) { | |||
| 13439 | spline->controllist.back()->y = reader->getDouble(); | |||
| 13440 | break; | |||
| 13441 | } | |||
| 13442 | if (pt) pt->basePoint.y = reader->getDouble(); | |||
| 13443 | else if (plvert) plvert ->y = reader->getDouble(); | |||
| 13444 | else if (m_dxfSeedPointsExpected >= 0) { | |||
| 13445 | if (seedPoints.empty()) | |||
| 13446 | return false; | |||
| 13447 | seedPoints.back().y = reader->getDouble(); | |||
| 13448 | } else { | |||
| 13449 | return DRW_Point::parseCode(code, reader); | |||
| 13450 | } | |||
| 13451 | break; | |||
| 13452 | case 11: | |||
| 13453 | // Spline edge: 11 is a fit-point x-coord. | |||
| 13454 | if (spline) { | |||
| 13455 | if (spline->fitlist.size() >= static_cast<std::size_t>(kMaxHatchItems) | |||
| 13456 | || (m_dxfSplineFitCountExpected >= 0 | |||
| 13457 | && spline->fitlist.size() | |||
| 13458 | >= static_cast<std::size_t>(m_dxfSplineFitCountExpected))) | |||
| 13459 | return false; | |||
| 13460 | spline->fitlist.push_back(std::make_shared<DRW_Coord>(reader->getDouble(), 0.0, 0.0)); | |||
| 13461 | break; | |||
| 13462 | } | |||
| 13463 | if (line) line->secPoint.x = reader->getDouble(); | |||
| 13464 | else if (ellipse) ellipse->secPoint.x = reader->getDouble(); | |||
| 13465 | break; | |||
| 13466 | case 21: | |||
| 13467 | if (spline && !spline->fitlist.empty()) { | |||
| 13468 | spline->fitlist.back()->y = reader->getDouble(); | |||
| 13469 | break; | |||
| 13470 | } | |||
| 13471 | if (line) line->secPoint.y = reader->getDouble(); | |||
| 13472 | else if (ellipse) ellipse->secPoint.y = reader->getDouble(); | |||
| 13473 | break; | |||
| 13474 | case 12: | |||
| 13475 | if (spline) { spline->tgStart.x = reader->getDouble(); break; } | |||
| 13476 | break; | |||
| 13477 | case 22: | |||
| 13478 | if (spline) { spline->tgStart.y = reader->getDouble(); break; } | |||
| 13479 | break; | |||
| 13480 | case 13: | |||
| 13481 | if (spline) { spline->tgEnd.x = reader->getDouble(); break; } | |||
| 13482 | break; | |||
| 13483 | case 23: | |||
| 13484 | if (spline) { spline->tgEnd.y = reader->getDouble(); break; } | |||
| 13485 | break; | |||
| 13486 | case 40: | |||
| 13487 | // Spline edge: 40 is a knot value (occurs nknots times). | |||
| 13488 | if (spline) { | |||
| 13489 | if (spline->knotslist.size() >= static_cast<std::size_t>(kMaxHatchItems) | |||
| 13490 | || (m_dxfSplineKnotCountExpected >= 0 | |||
| 13491 | && spline->knotslist.size() | |||
| 13492 | >= static_cast<std::size_t>(m_dxfSplineKnotCountExpected))) | |||
| 13493 | return false; | |||
| 13494 | spline->knotslist.push_back(reader->getDouble()); | |||
| 13495 | break; | |||
| 13496 | } | |||
| 13497 | if (arc) arc->radious = reader->getDouble(); | |||
| 13498 | else if (ellipse) ellipse->ratio = reader->getDouble(); | |||
| 13499 | break; | |||
| 13500 | case 41: | |||
| 13501 | scale = reader->getDouble(); | |||
| 13502 | break; | |||
| 13503 | case 42: | |||
| 13504 | // Spline edge: 42 is a per-control-point weight. | |||
| 13505 | if (spline) { | |||
| 13506 | if (spline->weightlist.size() >= static_cast<std::size_t>(kMaxHatchItems) | |||
| 13507 | || (m_dxfSplineControlCountExpected >= 0 | |||
| 13508 | && spline->weightlist.size() | |||
| 13509 | >= static_cast<std::size_t>(m_dxfSplineControlCountExpected))) | |||
| 13510 | return false; | |||
| 13511 | spline->weightlist.push_back(reader->getDouble()); | |||
| 13512 | break; | |||
| 13513 | } | |||
| 13514 | if (plvert) plvert ->bulge = reader->getDouble(); | |||
| 13515 | break; | |||
| 13516 | case 50: | |||
| 13517 | if (arc) arc->staangle = reader->getDouble()/ARAD57.29577951308232; | |||
| 13518 | else if (ellipse) ellipse->staparam = reader->getDouble()/ARAD57.29577951308232; | |||
| 13519 | break; | |||
| 13520 | case 51: | |||
| 13521 | if (arc) arc->endangle = reader->getDouble()/ARAD57.29577951308232; | |||
| 13522 | else if (ellipse) ellipse->endparam = reader->getDouble()/ARAD57.29577951308232; | |||
| 13523 | break; | |||
| 13524 | case 47: | |||
| 13525 | pixelSize = reader->getDouble(); | |||
| 13526 | break; | |||
| 13527 | case 52: | |||
| 13528 | angle = reader->getDouble(); | |||
| 13529 | break; | |||
| 13530 | case 53: // pattern line angle — starts a new PatternLine record | |||
| 13531 | if (!validateCurrentPatternLineDxf()) | |||
| 13532 | return false; | |||
| 13533 | if (m_dxfPatternLineCountExpected >= 0 | |||
| 13534 | && patternLines.size() >= static_cast<std::size_t>(m_dxfPatternLineCountExpected)) | |||
| 13535 | return false; | |||
| 13536 | if (patternLines.size() >= static_cast<std::size_t>(kMaxHatchItems)) | |||
| 13537 | return false; | |||
| 13538 | patternLines.push_back(PatternLine()); | |||
| 13539 | patternLines.back().angle = reader->getDouble(); | |||
| 13540 | m_dxfPatternDashCountExpected = -1; | |||
| 13541 | m_dxfPatternDashCountSeen = false; | |||
| 13542 | break; | |||
| 13543 | case 43: | |||
| 13544 | if (!patternLines.empty()) patternLines.back().baseX = reader->getDouble(); | |||
| 13545 | break; | |||
| 13546 | case 44: | |||
| 13547 | if (!patternLines.empty()) patternLines.back().baseY = reader->getDouble(); | |||
| 13548 | break; | |||
| 13549 | case 45: | |||
| 13550 | if (!patternLines.empty()) patternLines.back().offsetX = reader->getDouble(); | |||
| 13551 | break; | |||
| 13552 | case 46: | |||
| 13553 | if (!patternLines.empty()) patternLines.back().offsetY = reader->getDouble(); | |||
| 13554 | break; | |||
| 13555 | case 79: // dash count — the 49s that follow will accumulate | |||
| 13556 | if (patternLines.empty() || m_dxfPatternDashCountSeen) | |||
| 13557 | return false; | |||
| 13558 | m_dxfPatternDashCountExpected = reader->getInt32(); | |||
| 13559 | if (!isValidCount(m_dxfPatternDashCountExpected, kMaxHatchItems)) | |||
| 13560 | return false; | |||
| 13561 | m_dxfPatternDashCountSeen = true; | |||
| 13562 | return DRW::reserve(patternLines.back().dashList, m_dxfPatternDashCountExpected); | |||
| 13563 | case 49: | |||
| 13564 | if (patternLines.empty() | |||
| 13565 | || patternLines.back().dashList.size() >= static_cast<std::size_t>(kMaxHatchItems) | |||
| 13566 | || (m_dxfPatternDashCountExpected >= 0 | |||
| 13567 | && patternLines.back().dashList.size() | |||
| 13568 | >= static_cast<std::size_t>(m_dxfPatternDashCountExpected))) | |||
| 13569 | return false; | |||
| 13570 | patternLines.back().dashList.push_back(reader->getDouble()); | |||
| 13571 | break; | |||
| 13572 | case 73: | |||
| 13573 | // Spline edge: 73 is the rational flag (1 = rational). | |||
| 13574 | if (spline) { | |||
| 13575 | if (reader->getInt32()) spline->flags |= 0x4; | |||
| 13576 | break; | |||
| 13577 | } | |||
| 13578 | if (arc) arc->isccw = reader->getInt32(); | |||
| 13579 | // polyline path: 73 is the is-closed flag -> set bit 0 only, leaving the | |||
| 13580 | // rest of pline->flags untouched (order-independent vs code 72). | |||
| 13581 | else if (pline) pline->flags = (pline->flags & ~1) | (reader->getInt32() ? 1 : 0); | |||
| 13582 | break; | |||
| 13583 | case 74: | |||
| 13584 | // Spline edge: 74 is the periodic flag (1 = periodic/closed). | |||
| 13585 | if (spline) { | |||
| 13586 | if (reader->getInt32()) spline->flags |= 0x2; | |||
| 13587 | } | |||
| 13588 | break; | |||
| 13589 | case 94: | |||
| 13590 | // Spline edge degree. | |||
| 13591 | if (spline) { | |||
| 13592 | spline->degree = reader->getInt32(); | |||
| 13593 | return isValidCount(spline->degree, kMaxSplineDegree) | |||
| 13594 | && spline->degree != 0; | |||
| 13595 | } | |||
| 13596 | break; | |||
| 13597 | case 95: | |||
| 13598 | // Spline edge number of knots. | |||
| 13599 | if (spline) { | |||
| 13600 | if (m_dxfSplineKnotCountExpected >= 0) | |||
| 13601 | return false; | |||
| 13602 | spline->nknots = reader->getInt32(); | |||
| 13603 | if (!isValidCount(spline->nknots, kMaxHatchItems)) | |||
| 13604 | return false; | |||
| 13605 | m_dxfSplineKnotCountExpected = spline->nknots; | |||
| 13606 | return DRW::reserve(spline->knotslist, spline->nknots); | |||
| 13607 | } | |||
| 13608 | break; | |||
| 13609 | case 96: | |||
| 13610 | // Spline edge number of control points. | |||
| 13611 | if (spline) { | |||
| 13612 | if (m_dxfSplineControlCountExpected >= 0) | |||
| 13613 | return false; | |||
| 13614 | spline->ncontrol = reader->getInt32(); | |||
| 13615 | if (!isValidCount(spline->ncontrol, kMaxHatchItems)) | |||
| 13616 | return false; | |||
| 13617 | m_dxfSplineControlCountExpected = spline->ncontrol; | |||
| 13618 | return DRW::reserve(spline->controllist, spline->ncontrol); | |||
| 13619 | } | |||
| 13620 | break; | |||
| 13621 | case 97: | |||
| 13622 | if (spline) { | |||
| 13623 | if (!m_splineNfitSet) { | |||
| 13624 | // First 97 in this spline edge = fit-point count (nfit). | |||
| 13625 | spline->nfit = reader->getInt32(); | |||
| 13626 | if (!isValidCount(spline->nfit, kMaxHatchItems)) | |||
| 13627 | return false; | |||
| 13628 | if (m_dxfSplineFitCountExpected >= 0) | |||
| 13629 | return false; | |||
| 13630 | m_dxfSplineFitCountExpected = spline->nfit; | |||
| 13631 | if (!DRW::reserve(spline->fitlist, spline->nfit)) | |||
| 13632 | return false; | |||
| 13633 | if (spline->nfit == 0) { | |||
| 13634 | if (!validateCurrentSplineDxf()) | |||
| 13635 | return false; | |||
| 13636 | // No fit points or tangents follow; safe to clear spline | |||
| 13637 | // so the next code-97 (loop boundary count) is not | |||
| 13638 | // misinterpreted as another nfit. | |||
| 13639 | spline.reset(); | |||
| 13640 | } else { | |||
| 13641 | m_splineNfitSet = true; | |||
| 13642 | } | |||
| 13643 | } else { | |||
| 13644 | // Second 97 while spline is active = loop boundary handle count. | |||
| 13645 | if (!validateCurrentSplineDxf()) | |||
| 13646 | return false; | |||
| 13647 | spline.reset(); | |||
| 13648 | m_splineNfitSet = false; | |||
| 13649 | m_boundaryHandleCount = reader->getInt32(); | |||
| 13650 | if (!isValidCount(m_boundaryHandleCount, kMaxHatchItems)) | |||
| 13651 | return false; | |||
| 13652 | if (m_dxfBoundaryHandleCountSeen) | |||
| 13653 | return false; | |||
| 13654 | m_dxfBoundaryHandleCountSeen = true; | |||
| 13655 | if (m_boundaryHandleCount > 0 && loop | |||
| 13656 | && !DRW::reserve(loop->m_boundaryHandles, m_boundaryHandleCount)) | |||
| 13657 | return false; | |||
| 13658 | } | |||
| 13659 | break; | |||
| 13660 | } | |||
| 13661 | // No active spline: this is the loop boundary handle count. | |||
| 13662 | m_splineNfitSet = false; | |||
| 13663 | if (m_dxfBoundaryHandleCountSeen) | |||
| 13664 | return false; | |||
| 13665 | m_boundaryHandleCount = reader->getInt32(); | |||
| 13666 | if (!isValidCount(m_boundaryHandleCount, kMaxHatchItems)) | |||
| 13667 | return false; | |||
| 13668 | m_dxfBoundaryHandleCountSeen = true; | |||
| 13669 | if (m_boundaryHandleCount > 0 && loop | |||
| 13670 | && !DRW::reserve(loop->m_boundaryHandles, m_boundaryHandleCount)) | |||
| 13671 | return false; | |||
| 13672 | break; | |||
| 13673 | case 330: | |||
| 13674 | if (m_boundaryHandleCount > 0 && loop) { | |||
| 13675 | // getHandleString() converts the hex string to int for us. | |||
| 13676 | loop->m_boundaryHandles.push_back( | |||
| 13677 | static_cast<std::uint32_t>(reader->getHandleString())); | |||
| 13678 | --m_boundaryHandleCount; | |||
| 13679 | break; | |||
| 13680 | } | |||
| 13681 | if (m_dxfBoundaryHandleCountSeen) | |||
| 13682 | return false; | |||
| 13683 | return DRW_Point::parseCode(code, reader); | |||
| 13684 | case 75: | |||
| 13685 | hstyle = reader->getInt32(); | |||
| 13686 | break; | |||
| 13687 | case 76: | |||
| 13688 | hpattern = reader->getInt32(); | |||
| 13689 | break; | |||
| 13690 | case 77: | |||
| 13691 | doubleflag = reader->getInt32(); | |||
| 13692 | break; | |||
| 13693 | case 78: | |||
| 13694 | if (m_dxfPatternLineCountSeen) | |||
| 13695 | return false; | |||
| 13696 | deflines = reader->getInt32(); | |||
| 13697 | if (!isValidCount(deflines, kMaxHatchItems)) | |||
| 13698 | return false; | |||
| 13699 | m_dxfPatternLineCountExpected = deflines; | |||
| 13700 | m_dxfPatternLineCountSeen = true; | |||
| 13701 | if (patternLines.size() > static_cast<std::size_t>(deflines)) | |||
| 13702 | return false; | |||
| 13703 | break; | |||
| 13704 | case 91: | |||
| 13705 | if (m_dxfLoopCountSeen) | |||
| 13706 | return false; | |||
| 13707 | loopsnum = reader->getInt32(); | |||
| 13708 | if (!isValidCount(loopsnum, kMaxHatchItems)) | |||
| 13709 | return false; | |||
| 13710 | m_dxfLoopCountExpected = loopsnum; | |||
| 13711 | m_dxfLoopCountSeen = true; | |||
| 13712 | return DRW::reserve( looplist, loopsnum); | |||
| 13713 | case 92: { | |||
| 13714 | if (!validateCurrentBoundaryPathDxf()) | |||
| 13715 | return false; | |||
| 13716 | if (m_dxfLoopCountExpected >= 0 | |||
| 13717 | && looplist.size() >= static_cast<std::size_t>(m_dxfLoopCountExpected)) | |||
| 13718 | return false; | |||
| 13719 | clearEntities(); | |||
| 13720 | m_dxfLoopEdgeCountExpected = -1; | |||
| 13721 | m_dxfLoopEdgeCountSeen = false; | |||
| 13722 | m_dxfPolylineVertexCountExpected = -1; | |||
| 13723 | m_dxfPolylineVertexCountSeen = false; | |||
| 13724 | m_dxfBoundaryHandleCountSeen = false; | |||
| 13725 | m_boundaryHandleCount = 0; | |||
| 13726 | loop = std::make_shared<DRW_HatchLoop>(reader->getInt32()); | |||
| 13727 | looplist.push_back(loop); | |||
| 13728 | if (reader->getInt32() & 2) { | |||
| 13729 | ispol = true; | |||
| 13730 | clearEntities(); | |||
| 13731 | pline = std::make_shared<DRW_LWPolyline>(); | |||
| 13732 | loop->objlist.push_back(pline); | |||
| 13733 | } else ispol = false; | |||
| 13734 | break; | |||
| 13735 | } | |||
| 13736 | case 93: | |||
| 13737 | if (pline) { | |||
| 13738 | if (m_dxfPolylineVertexCountSeen) | |||
| 13739 | return false; | |||
| 13740 | pline->vertexnum = reader->getInt32(); | |||
| 13741 | if (!isValidCount(pline->vertexnum, kMaxHatchItems)) | |||
| 13742 | return false; | |||
| 13743 | m_dxfPolylineVertexCountExpected = pline->vertexnum; | |||
| 13744 | m_dxfPolylineVertexCountSeen = true; | |||
| 13745 | } else if (loop) { | |||
| 13746 | if (m_dxfLoopEdgeCountSeen) | |||
| 13747 | return false; | |||
| 13748 | loop->numedges = reader->getInt32();//aqui reserve | |||
| 13749 | if (!isValidCount(loop->numedges, kMaxHatchItems)) | |||
| 13750 | return false; | |||
| 13751 | if (loop->objlist.size() > static_cast<std::size_t>(loop->numedges)) | |||
| 13752 | return false; | |||
| 13753 | m_dxfLoopEdgeCountExpected = loop->numedges; | |||
| 13754 | m_dxfLoopEdgeCountSeen = true; | |||
| 13755 | } | |||
| 13756 | break; | |||
| 13757 | case 98: { // seed-point count; coords follow as group-10/20 pairs | |||
| 13758 | if (!validateCurrentBoundaryPathDxf() || !validateCurrentPatternLineDxf()) | |||
| 13759 | return false; | |||
| 13760 | if (m_dxfSeedPointCountSeen) | |||
| 13761 | return false; | |||
| 13762 | clearEntities(); | |||
| 13763 | const int count = reader->getInt32(); | |||
| 13764 | if (!isValidCount(count, kMaxHatchItems) | |||
| 13765 | || !DRW::reserve(seedPoints, count)) | |||
| 13766 | return false; | |||
| 13767 | m_dxfSeedPointsExpected = count; | |||
| 13768 | m_dxfSeedPointCountSeen = true; | |||
| 13769 | break; | |||
| 13770 | } | |||
| 13771 | case 450: | |||
| 13772 | isGradient = reader->getInt32(); | |||
| 13773 | break; | |||
| 13774 | case 451: | |||
| 13775 | gradReserved = reader->getInt32(); | |||
| 13776 | break; | |||
| 13777 | case 452: | |||
| 13778 | singleColor = reader->getInt32(); | |||
| 13779 | break; | |||
| 13780 | case 453: { | |||
| 13781 | if (m_dxfGradientColorCountSeen) | |||
| 13782 | return false; | |||
| 13783 | const int n = reader->getInt32(); | |||
| 13784 | if (!isValidCount(n, kMaxHatchItems) | |||
| 13785 | || !DRW::reserve(gradColors, n)) | |||
| 13786 | return false; | |||
| 13787 | m_dxfGradientColorCountExpected = n; | |||
| 13788 | m_dxfGradientColorCountSeen = true; | |||
| 13789 | break; | |||
| 13790 | } | |||
| 13791 | case 460: | |||
| 13792 | gradAngle = reader->getDouble(); | |||
| 13793 | break; | |||
| 13794 | case 461: | |||
| 13795 | gradShift = reader->getDouble(); | |||
| 13796 | break; | |||
| 13797 | case 462: | |||
| 13798 | gradTint = reader->getDouble(); | |||
| 13799 | break; | |||
| 13800 | case 463: { | |||
| 13801 | if (m_dxfGradientColorCountExpected >= 0 | |||
| 13802 | && gradColors.size() >= static_cast<std::size_t>(m_dxfGradientColorCountExpected)) | |||
| 13803 | return false; | |||
| 13804 | if (gradColors.size() >= static_cast<std::size_t>(kMaxHatchItems)) | |||
| 13805 | return false; | |||
| 13806 | DRW_Hatch::GradientStop stop; | |||
| 13807 | stop.value = reader->getDouble(); | |||
| 13808 | gradColors.push_back(stop); | |||
| 13809 | break; | |||
| 13810 | } | |||
| 13811 | case 421: | |||
| 13812 | if (!gradColors.empty()) | |||
| 13813 | gradColors.back().rgb = reader->getInt32(); | |||
| 13814 | break; | |||
| 13815 | case 63: | |||
| 13816 | if (!gradColors.empty()) | |||
| 13817 | gradColors.back().aciColor = reader->getInt32(); | |||
| 13818 | else | |||
| 13819 | return DRW_Point::parseCode(code, reader); | |||
| 13820 | break; | |||
| 13821 | case 431: | |||
| 13822 | if (!gradColors.empty()) | |||
| 13823 | gradColors.back().colorMethod = reader->getInt32(); | |||
| 13824 | break; | |||
| 13825 | case 432: | |||
| 13826 | if (!gradColors.empty()) | |||
| 13827 | gradColors.back().colorName = reader->getUtf8String(); | |||
| 13828 | break; | |||
| 13829 | case 433: | |||
| 13830 | if (!gradColors.empty()) | |||
| 13831 | gradColors.back().colorBookName = reader->getUtf8String(); | |||
| 13832 | break; | |||
| 13833 | case 470: | |||
| 13834 | gradName = reader->getUtf8String(); | |||
| 13835 | break; | |||
| 13836 | default: | |||
| 13837 | return DRW_Point::parseCode(code, reader); | |||
| 13838 | } | |||
| 13839 | ||||
| 13840 | return true; | |||
| 13841 | } | |||
| 13842 | catch (...) { | |||
| 13843 | return false; | |||
| 13844 | } | |||
| 13845 | } | |||
| 13846 | ||||
| 13847 | bool DRW_Hatch::validateCurrentSplineDxf() const { | |||
| 13848 | if (!spline) | |||
| 13849 | return true; | |||
| 13850 | if (m_dxfSplineKnotCountExpected >= 0 | |||
| 13851 | && spline->knotslist.size() | |||
| 13852 | != static_cast<std::size_t>(m_dxfSplineKnotCountExpected)) | |||
| 13853 | return false; | |||
| 13854 | if (m_dxfSplineControlCountExpected >= 0 | |||
| 13855 | && spline->controllist.size() | |||
| 13856 | != static_cast<std::size_t>(m_dxfSplineControlCountExpected)) | |||
| 13857 | return false; | |||
| 13858 | if (m_dxfSplineFitCountExpected >= 0 | |||
| 13859 | && spline->fitlist.size() | |||
| 13860 | != static_cast<std::size_t>(m_dxfSplineFitCountExpected)) | |||
| 13861 | return false; | |||
| 13862 | if (spline->flags & 0x4) | |||
| 13863 | return m_dxfSplineControlCountExpected < 0 | |||
| 13864 | || spline->weightlist.size() | |||
| 13865 | == static_cast<std::size_t>(m_dxfSplineControlCountExpected); | |||
| 13866 | return spline->weightlist.empty(); | |||
| 13867 | } | |||
| 13868 | ||||
| 13869 | bool DRW_Hatch::validateCurrentPatternLineDxf() const { | |||
| 13870 | if (patternLines.empty() || m_dxfPatternDashCountExpected < 0) | |||
| 13871 | return true; | |||
| 13872 | return patternLines.back().dashList.size() | |||
| 13873 | == static_cast<std::size_t>(m_dxfPatternDashCountExpected); | |||
| 13874 | } | |||
| 13875 | ||||
| 13876 | bool DRW_Hatch::validateCurrentBoundaryPathDxf() const { | |||
| 13877 | if (m_boundaryHandleCount != 0 || !validateCurrentSplineDxf()) | |||
| 13878 | return false; | |||
| 13879 | if (!loop) | |||
| 13880 | return true; | |||
| 13881 | if (ispol) { | |||
| 13882 | std::shared_ptr<DRW_LWPolyline> polyline = pline; | |||
| 13883 | if (!polyline && loop->objlist.size() == 1) | |||
| 13884 | polyline = std::dynamic_pointer_cast<DRW_LWPolyline>(loop->objlist.front()); | |||
| 13885 | if (!polyline) | |||
| 13886 | return false; | |||
| 13887 | return !m_dxfPolylineVertexCountSeen | |||
| 13888 | || polyline->vertlist.size() | |||
| 13889 | == static_cast<std::size_t>(m_dxfPolylineVertexCountExpected); | |||
| 13890 | } | |||
| 13891 | return !m_dxfLoopEdgeCountSeen | |||
| 13892 | || loop->objlist.size() | |||
| 13893 | == static_cast<std::size_t>(m_dxfLoopEdgeCountExpected); | |||
| 13894 | } | |||
| 13895 | ||||
| 13896 | bool DRW_Hatch::validateDxf() const { | |||
| 13897 | if (!validateCurrentBoundaryPathDxf() | |||
| 13898 | || !validateCurrentPatternLineDxf()) | |||
| 13899 | return false; | |||
| 13900 | if (m_dxfLoopCountExpected >= 0 | |||
| 13901 | && looplist.size() != static_cast<std::size_t>(m_dxfLoopCountExpected)) | |||
| 13902 | return false; | |||
| 13903 | if (m_dxfPatternLineCountExpected >= 0 | |||
| 13904 | && patternLines.size() | |||
| 13905 | != static_cast<std::size_t>(m_dxfPatternLineCountExpected)) | |||
| 13906 | return false; | |||
| 13907 | if (m_dxfGradientColorCountExpected >= 0 | |||
| 13908 | && gradColors.size() | |||
| 13909 | != static_cast<std::size_t>(m_dxfGradientColorCountExpected)) | |||
| 13910 | return false; | |||
| 13911 | return m_dxfSeedPointsExpected < 0 | |||
| 13912 | || seedPoints.size() == static_cast<std::size_t>(m_dxfSeedPointsExpected); | |||
| 13913 | } | |||
| 13914 | ||||
| 13915 | bool DRW_MPolygon::parseCode(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 13916 | // MPOLYGON shares HATCH's boundary/pattern/gradient codes, so delegate those | |||
| 13917 | // to DRW_Hatch::parseCode. It adds a trailer that plain HATCH never emits: | |||
| 13918 | // 63 / 421 / 430 fill color (ACI / RGB / book-name) — the filled area's | |||
| 13919 | // color, which may differ from the boundary outline color; | |||
| 13920 | // 11 / 21 boundary x-direction vector (no render impact; left to | |||
| 13921 | // the base, which ignores it outside an edge context); | |||
| 13922 | // 99 count of degenerate boundary paths. | |||
| 13923 | // 63/421 are also gradient sub-codes in HATCH, so only claim them here when no | |||
| 13924 | // gradient is being accumulated (gradColors empty) — otherwise defer to base. | |||
| 13925 | switch (code) { | |||
| 13926 | case 63: | |||
| 13927 | if (gradColors.empty()) { fillColorAci = reader->getInt32(); return true; } | |||
| 13928 | break; | |||
| 13929 | case 421: | |||
| 13930 | if (gradColors.empty()) { fillColorRgb = reader->getInt32(); return true; } | |||
| 13931 | break; | |||
| 13932 | case 430: | |||
| 13933 | fillColorName = reader->getUtf8String(); | |||
| 13934 | return true; | |||
| 13935 | case 99: | |||
| 13936 | degenerateLoops = reader->getInt32(); | |||
| 13937 | return true; | |||
| 13938 | default: | |||
| 13939 | break; | |||
| 13940 | } | |||
| 13941 | return DRW_Hatch::parseCode(code, reader); | |||
| 13942 | } | |||
| 13943 | ||||
| 13944 | // DRW_MPolygon::parseDwg — AcDbMPolygon DWG body. | |||
| 13945 | // Layout mirrors HATCH except (per ACadSharp MPolygon / libreDWG dwg.spec): | |||
| 13946 | // * a leading BS `style` (DXF group 75) precedes the gradient block, and | |||
| 13947 | // * the trailer is a fill CMC + boundary x-direction (2RD) + degenerate-path | |||
| 13948 | // count (BL) instead of HATCH's pixel-size + seed points. | |||
| 13949 | // The gradient/elevation/extrusion/name/solid/associative prologue and the whole | |||
| 13950 | // boundary-loop body are identical, so they reuse DRW_Hatch::parseDwgBoundaryData. | |||
| 13951 | // DWG runtime coverage uses testdata/mpolygon_solid.dwg, ODA-synthesized from | |||
| 13952 | // the ezdxf-verified inline DXF in mpolygon_tests.cpp and confirmed with the | |||
| 13953 | // dwg-parser oracle. | |||
| 13954 | bool DRW_MPolygon::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){ | |||
| 13955 | resetDwgState(); | |||
| 13956 | dwgBuffer *sourceBuf = buf; | |||
| 13957 | auto fail = [this, sourceBuf]() { | |||
| 13958 | if (sourceBuf != nullptr) | |||
| 13959 | sourceBuf->invalidate(); | |||
| 13960 | resetDwgState(); | |||
| 13961 | return false; | |||
| 13962 | }; | |||
| 13963 | if (sourceBuf == nullptr) | |||
| 13964 | return fail(); | |||
| 13965 | ||||
| 13966 | fillColorAci = 0; | |||
| 13967 | fillColorRgb = -1; | |||
| 13968 | fillColorName.clear(); | |||
| 13969 | xDirX = 0.0; | |||
| 13970 | xDirY = 0.0; | |||
| 13971 | degenerateLoops = 0; | |||
| 13972 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 13973 | dwgBuffer stringProbe = sourceBuf->forkIndependent(); | |||
| 13974 | buf = &bodyProbe; | |||
| 13975 | dwgBuffer *sBuf = version > DRW::AC1018 ? &stringProbe : buf; | |||
| 13976 | std::uint32_t totalBoundItems = 0; | |||
| 13977 | bool havePixelSize = false; | |||
| 13978 | if (!DRW_Entity::parseDwg( | |||
| 13979 | version, buf, version > DRW::AC1018 ? &stringProbe : nullptr, bs) | |||
| 13980 | || !buf->isGood() || !sBuf->isGood()) | |||
| 13981 | return fail(); | |||
| 13982 | DRW_DBG("\n***************************** parsing mpolygon *********************************************\n")DRW_dbg::dbg("\n***************************** parsing mpolygon *********************************************\n" ); | |||
| 13983 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 13984 | std::uint64_t stringStartBit = bodyEndBit; | |||
| 13985 | std::uint64_t stringEndBit = bodyEndBit; | |||
| 13986 | if (version > DRW::AC1018) { | |||
| 13987 | stringStartBit = currentDwgBit(sBuf); | |||
| 13988 | if (version > DRW::AC1021) { | |||
| 13989 | std::uint64_t ignoredBodyEndBit = 0; | |||
| 13990 | if (!entityBodyDataEndBit(*sBuf, version, objSize, | |||
| 13991 | ignoredBodyEndBit, &stringEndBit)) | |||
| 13992 | return fail(); | |||
| 13993 | } | |||
| 13994 | } | |||
| 13995 | ||||
| 13996 | // Leading BS style (group 75) — read once here and again after the loops | |||
| 13997 | // below (HATCH has only the latter); matches the reference parser, which | |||
| 13998 | // discards this first read. | |||
| 13999 | std::uint16_t parsedLeadingStyle = 0; | |||
| 14000 | if (!readBoundedBitShort(*buf, bodyEndBit, parsedLeadingStyle)) | |||
| 14001 | return fail(); | |||
| 14002 | hstyle = parsedLeadingStyle; | |||
| 14003 | ||||
| 14004 | if (version > DRW::AC1015) { //2004+ gradient (same layout as HATCH) | |||
| 14005 | if (!readBoundedHatchGradient( | |||
| 14006 | *buf, sBuf, bodyEndBit, version, isGradient, gradReserved, | |||
| 14007 | gradAngle, gradShift, singleColor, gradTint, gradName, | |||
| 14008 | gradColors, stringEndBit)) | |||
| 14009 | return fail(); | |||
| 14010 | } | |||
| 14011 | if (!readBoundedBitDouble(*buf, bodyEndBit, basePoint.z) | |||
| 14012 | || !readBoundedBitCoord(*buf, bodyEndBit, extPoint) | |||
| 14013 | || !std::isfinite(basePoint.z) | |||
| 14014 | || !std::isfinite(extPoint.x) | |||
| 14015 | || !std::isfinite(extPoint.y) | |||
| 14016 | || !std::isfinite(extPoint.z)) | |||
| 14017 | return fail(); | |||
| 14018 | UTF8STRINGstd::string parsedName; | |||
| 14019 | if (version > DRW::AC1018 && stringStartBit >= stringEndBit) { | |||
| 14020 | parsedName.clear(); | |||
| 14021 | } else if (!readBoundedVariableText(*sBuf, stringEndBit, version, | |||
| 14022 | parsedName)) { | |||
| 14023 | return fail(); | |||
| 14024 | } | |||
| 14025 | bool parsedSolid = false; | |||
| 14026 | bool parsedAssociative = false; | |||
| 14027 | if (!sBuf->isGood() | |||
| 14028 | || currentDwgBit(sBuf) > stringEndBit | |||
| 14029 | || !readBoundedBit(*buf, bodyEndBit, parsedSolid) | |||
| 14030 | || !readBoundedBit(*buf, bodyEndBit, parsedAssociative)) | |||
| 14031 | return fail(); | |||
| 14032 | solid = parsedSolid; | |||
| 14033 | associative = parsedAssociative; | |||
| 14034 | name = std::move(parsedName); | |||
| 14035 | ||||
| 14036 | if (!parseDwgBoundaryData(version, buf, totalBoundItems, havePixelSize)) | |||
| 14037 | return fail(); | |||
| 14038 | ||||
| 14039 | std::uint16_t parsedStyle = 0; | |||
| 14040 | std::uint16_t parsedPattern = 0; | |||
| 14041 | if (!readBoundedBitShort(*buf, bodyEndBit, parsedStyle) | |||
| 14042 | || !readBoundedBitShort(*buf, bodyEndBit, parsedPattern)) | |||
| 14043 | return fail(); | |||
| 14044 | hstyle = parsedStyle; | |||
| 14045 | hpattern = parsedPattern; | |||
| 14046 | if (!solid){ | |||
| 14047 | double parsedAngle = 0.0; | |||
| 14048 | double parsedScale = 0.0; | |||
| 14049 | bool parsedDoubleFlag = false; | |||
| 14050 | if (!readBoundedBitDouble(*buf, bodyEndBit, parsedAngle) | |||
| 14051 | || !readBoundedBitDouble(*buf, bodyEndBit, parsedScale) | |||
| 14052 | || !readBoundedBit(*buf, bodyEndBit, parsedDoubleFlag) | |||
| 14053 | || !std::isfinite(parsedAngle) | |||
| 14054 | || !std::isfinite(parsedScale)) | |||
| 14055 | return fail(); | |||
| 14056 | angle = parsedAngle; | |||
| 14057 | scale = parsedScale; | |||
| 14058 | doubleflag = parsedDoubleFlag; | |||
| 14059 | std::uint32_t parsedDeflines = 0; | |||
| 14060 | if (!readTableBodyCount(version, buf, objSize, kMaxHatchItems, 12, | |||
| 14061 | parsedDeflines)) | |||
| 14062 | return fail(); | |||
| 14063 | if (!DRW::reserve(patternLines, parsedDeflines)) | |||
| 14064 | return fail(); | |||
| 14065 | deflines = static_cast<int>(parsedDeflines); | |||
| 14066 | for (std::uint32_t i = 0 ; i < parsedDeflines; ++i){ | |||
| 14067 | PatternLine patternLine; | |||
| 14068 | if (!readBoundedBitDouble(*buf, bodyEndBit, patternLine.angle) | |||
| 14069 | || !readBoundedBitDouble(*buf, bodyEndBit, patternLine.baseX) | |||
| 14070 | || !readBoundedBitDouble(*buf, bodyEndBit, patternLine.baseY) | |||
| 14071 | || !readBoundedBitDouble(*buf, bodyEndBit, patternLine.offsetX) | |||
| 14072 | || !readBoundedBitDouble(*buf, bodyEndBit, patternLine.offsetY) | |||
| 14073 | || !std::isfinite(patternLine.angle) | |||
| 14074 | || !std::isfinite(patternLine.baseX) | |||
| 14075 | || !std::isfinite(patternLine.baseY) | |||
| 14076 | || !std::isfinite(patternLine.offsetX) | |||
| 14077 | || !std::isfinite(patternLine.offsetY)) | |||
| 14078 | return fail(); | |||
| 14079 | std::uint32_t numDashL = 0; | |||
| 14080 | if (!readTableBodyCount(version, buf, objSize, kMaxHatchItems, 2, | |||
| 14081 | numDashL) | |||
| 14082 | || !proxyEntityHasBits( | |||
| 14083 | *buf, bodyEndBit, static_cast<std::uint64_t>(numDashL) * 2u) | |||
| 14084 | || !DRW::reserve(patternLine.dashList, numDashL)) | |||
| 14085 | return fail(); | |||
| 14086 | for (std::uint32_t d = 0 ; d < numDashL; ++d) { | |||
| 14087 | double dash = 0.0; | |||
| 14088 | if (!readBoundedBitDouble(*buf, bodyEndBit, dash) | |||
| 14089 | || !std::isfinite(dash)) | |||
| 14090 | return fail(); | |||
| 14091 | patternLine.dashList.push_back(dash); | |||
| 14092 | } | |||
| 14093 | patternLines.push_back(std::move(patternLine)); | |||
| 14094 | } | |||
| 14095 | } | |||
| 14096 | ||||
| 14097 | // MPOLYGON trailer (differs from HATCH): fill CMC + x-direction + degenerate | |||
| 14098 | // path count. No pixel size / seed points here. | |||
| 14099 | std::int32_t rgb = -1; | |||
| 14100 | UTF8STRINGstd::string colName; | |||
| 14101 | std::uint32_t parsedFillColor = 0; | |||
| 14102 | if (!readBoundedCmColor(*buf, sBuf, bodyEndBit, version, | |||
| 14103 | parsedFillColor, &rgb, nullptr, &colName)) | |||
| 14104 | return fail(); | |||
| 14105 | fillColorAci = static_cast<int>(parsedFillColor); | |||
| 14106 | fillColorRgb = rgb; | |||
| 14107 | fillColorName = colName; | |||
| 14108 | DRW_Coord xdir; | |||
| 14109 | if (!readBounded2RawDouble(*buf, bodyEndBit, xdir) | |||
| 14110 | || !std::isfinite(xdir.x) || !std::isfinite(xdir.y)) | |||
| 14111 | return fail(); | |||
| 14112 | xDirX = xdir.x; | |||
| 14113 | xDirY = xdir.y; | |||
| 14114 | std::uint32_t parsedDegenerateLoops = 0; | |||
| 14115 | if (!readTableBodyCount(version, buf, objSize, kMaxHatchItems, 0, | |||
| 14116 | parsedDegenerateLoops)) | |||
| 14117 | return fail(); | |||
| 14118 | degenerateLoops = static_cast<std::int32_t>(parsedDegenerateLoops); | |||
| 14119 | ||||
| 14120 | std::uint64_t handleEndBit = 0; | |||
| 14121 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, | |||
| 14122 | handleEndBit)) | |||
| 14123 | return fail(); | |||
| 14124 | dwgBuffer handleProbe = buf->forkIndependent(); | |||
| 14125 | if (!DRW_Entity::parseDwgEntHandle(version, &handleProbe, true, | |||
| 14126 | handleEndBit) | |||
| 14127 | || !handleProbe.isGood()) | |||
| 14128 | return fail(); | |||
| 14129 | for (std::uint32_t i = 0 ; i < totalBoundItems; ++i) { | |||
| 14130 | dwgHandle boundaryHandle; | |||
| 14131 | if (!readBoundedDwgHandle(handleProbe, handleEndBit, handle, false, | |||
| 14132 | boundaryHandle)) | |||
| 14133 | return fail(); | |||
| 14134 | } | |||
| 14135 | if (!handleProbe.isGood()) | |||
| 14136 | return fail(); | |||
| 14137 | ||||
| 14138 | *sourceBuf = handleProbe; | |||
| 14139 | return true; | |||
| 14140 | } | |||
| 14141 | ||||
| 14142 | // Shared DWG boundary-loop reader for HATCH and MPOLYGON (ODA §20.4.36). | |||
| 14143 | // Reads the loop count and, per loop, the derived-boundary flag plus its edge | |||
| 14144 | // list or polyline. Accumulates the running boundary-source-handle total and | |||
| 14145 | // whether any loop is derived (needs a trailing pixel size). Extracted from | |||
| 14146 | // DRW_Hatch::parseDwg so DRW_MPolygon::parseDwg reuses the identical body while | |||
| 14147 | // supplying its own differing leading (BS style) and trailing (fill CMC + | |||
| 14148 | // x-direction + degenerate count) field order. | |||
| 14149 | bool validateDwgHatchData(const DRW_Hatch& hatch) { | |||
| 14150 | if (hatch.looplist.size() > static_cast<std::size_t>(kMaxHatchItems) | |||
| 14151 | || hatch.patternLines.size() > static_cast<std::size_t>(kMaxHatchItems) | |||
| 14152 | || hatch.gradColors.size() > static_cast<std::size_t>(kMaxHatchItems) | |||
| 14153 | || hatch.seedPoints.size() > static_cast<std::size_t>(kMaxHatchItems)) | |||
| 14154 | return false; | |||
| 14155 | ||||
| 14156 | for (const auto& loop : hatch.looplist) { | |||
| 14157 | if (!loop | |||
| 14158 | || loop->objlist.size() > static_cast<std::size_t>(kMaxHatchItems) | |||
| 14159 | || loop->m_boundaryHandles.size() > static_cast<std::size_t>(kMaxHatchItems)) | |||
| 14160 | return false; | |||
| 14161 | ||||
| 14162 | if ((loop->type & 2) != 0) { | |||
| 14163 | if (loop->objlist.size() != 1) | |||
| 14164 | return false; | |||
| 14165 | const auto* polyline = | |||
| 14166 | dynamic_cast<const DRW_LWPolyline*>(loop->objlist.front().get()); | |||
| 14167 | if (!polyline || polyline->vertlist.size() > static_cast<std::size_t>(kMaxHatchItems)) | |||
| 14168 | return false; | |||
| 14169 | for (const auto& vertex : polyline->vertlist) { | |||
| 14170 | if (!vertex) | |||
| 14171 | return false; | |||
| 14172 | } | |||
| 14173 | continue; | |||
| 14174 | } | |||
| 14175 | ||||
| 14176 | for (const auto& entity : loop->objlist) { | |||
| 14177 | if (dynamic_cast<const DRW_Line*>(entity.get()) | |||
| 14178 | || dynamic_cast<const DRW_Arc*>(entity.get()) | |||
| 14179 | || dynamic_cast<const DRW_Ellipse*>(entity.get())) { | |||
| 14180 | continue; | |||
| 14181 | } | |||
| 14182 | const auto* spline = dynamic_cast<const DRW_Spline*>(entity.get()); | |||
| 14183 | if (!spline | |||
| 14184 | || spline->knotslist.size() > static_cast<std::size_t>(kMaxHatchItems) | |||
| 14185 | || spline->controllist.size() > static_cast<std::size_t>(kMaxHatchItems) | |||
| 14186 | || spline->fitlist.size() > static_cast<std::size_t>(kMaxHatchItems)) | |||
| 14187 | return false; | |||
| 14188 | for (const auto& point : spline->controllist) { | |||
| 14189 | if (!point) | |||
| 14190 | return false; | |||
| 14191 | } | |||
| 14192 | for (const auto& point : spline->fitlist) { | |||
| 14193 | if (!point) | |||
| 14194 | return false; | |||
| 14195 | } | |||
| 14196 | } | |||
| 14197 | } | |||
| 14198 | ||||
| 14199 | for (const auto& line : hatch.patternLines) { | |||
| 14200 | if (line.dashList.size() > static_cast<std::size_t>(kMaxHatchItems)) | |||
| 14201 | return false; | |||
| 14202 | } | |||
| 14203 | return true; | |||
| 14204 | } | |||
| 14205 | ||||
| 14206 | bool DRW_MPolygon::encodeDwg(DRW::Version version, dwgBufferW *buf, | |||
| 14207 | std::uint32_t bs, dwgBufferW *strBuf, | |||
| 14208 | dwgBufferW *handleBuf) { | |||
| 14209 | (void)bs; | |||
| 14210 | if (!validateDwgHatchData(*this) | |||
| 14211 | || !isValidCount(degenerateLoops, kMaxHatchItems)) | |||
| 14212 | return false; | |||
| 14213 | oType = kDwgClassNum; | |||
| 14214 | if (!encodeDwgCommon(version, buf, strBuf)) | |||
| 14215 | return false; | |||
| 14216 | ||||
| 14217 | dwgBufferW *sb = strBuf ? strBuf : buf; | |||
| 14218 | ||||
| 14219 | // AcDbMPolygon has a leading style field before the HATCH-like gradient | |||
| 14220 | // prologue. The same style is emitted again after the boundary data. | |||
| 14221 | buf->putBitShort(static_cast<std::uint16_t>(hstyle)); | |||
| 14222 | encodeDwgGradientData(version, buf, sb); | |||
| 14223 | ||||
| 14224 | buf->putBitDouble(basePoint.z); | |||
| 14225 | buf->put3BitDouble(extPoint); | |||
| 14226 | sb->putVariableText(version, name); | |||
| 14227 | buf->putBit(static_cast<std::uint8_t>(solid)); | |||
| 14228 | buf->putBit(static_cast<std::uint8_t>(associative)); | |||
| 14229 | if (!encodeDwgBoundaryData(version, buf)) return false; | |||
| 14230 | ||||
| 14231 | buf->putBitShort(static_cast<std::uint16_t>(hstyle)); | |||
| 14232 | buf->putBitShort(static_cast<std::uint16_t>(hpattern)); | |||
| 14233 | ||||
| 14234 | if (!solid) { | |||
| 14235 | buf->putBitDouble(angle); | |||
| 14236 | buf->putBitDouble(scale); | |||
| 14237 | buf->putBit(static_cast<std::uint8_t>(doubleflag)); | |||
| 14238 | buf->putBitShort(static_cast<std::uint16_t>(patternLines.size())); | |||
| 14239 | for (const PatternLine& pl : patternLines) { | |||
| 14240 | buf->putBitDouble(pl.angle); | |||
| 14241 | buf->putBitDouble(pl.baseX); | |||
| 14242 | buf->putBitDouble(pl.baseY); | |||
| 14243 | buf->putBitDouble(pl.offsetX); | |||
| 14244 | buf->putBitDouble(pl.offsetY); | |||
| 14245 | buf->putBitShort(static_cast<std::uint16_t>(pl.dashList.size())); | |||
| 14246 | for (double dash : pl.dashList) | |||
| 14247 | buf->putBitDouble(dash); | |||
| 14248 | } | |||
| 14249 | } | |||
| 14250 | ||||
| 14251 | buf->putCmColor(version, | |||
| 14252 | static_cast<std::uint16_t>(fillColorAci), | |||
| 14253 | fillColorRgb, | |||
| 14254 | fillColorName, | |||
| 14255 | {}, | |||
| 14256 | sb); | |||
| 14257 | buf->put2RawDouble(DRW_Coord{xDirX, xDirY, 0.0}); | |||
| 14258 | buf->putBitLong(degenerateLoops); | |||
| 14259 | ||||
| 14260 | return encodeDwgEntHandle(version, buf, handleBuf); | |||
| 14261 | } | |||
| 14262 | ||||
| 14263 | bool DRW_Hatch::parseDwgBoundaryData(DRW::Version version, dwgBuffer *buf, | |||
| 14264 | std::uint32_t &totalBoundItems, bool &havePixelSize) { | |||
| 14265 | try { | |||
| 14266 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 14267 | std::uint32_t parsedLoopCount = 0; | |||
| 14268 | if (!readTableBodyCount(version, buf, objSize, kMaxHatchItems, 4, | |||
| 14269 | parsedLoopCount)) | |||
| 14270 | return false; | |||
| 14271 | if (!DRW::reserve(looplist, parsedLoopCount)) | |||
| 14272 | return false; | |||
| 14273 | loopsnum = static_cast<std::int32_t>(parsedLoopCount); | |||
| 14274 | DRW_DBG("solid: ")DRW_dbg::dbg("solid: "); DRW_DBG(solid)DRW_dbg::dbg(solid); DRW_DBG(" associative: ")DRW_dbg::dbg(" associative: "); DRW_DBG(associative)DRW_dbg::dbg(associative); | |||
| 14275 | DRW_DBG(" loopsnum: ")DRW_dbg::dbg(" loopsnum: "); DRW_DBG(loopsnum)DRW_dbg::dbg(loopsnum); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 14276 | ||||
| 14277 | //read loops | |||
| 14278 | for (std::uint32_t i = 0 ; i < parsedLoopCount; ++i){ | |||
| 14279 | std::int32_t loopType = 0; | |||
| 14280 | if (!readBoundedBitLong(*buf, bodyEndBit, loopType) | |||
| 14281 | || loopType < 0) | |||
| 14282 | return false; | |||
| 14283 | loop = std::make_shared<DRW_HatchLoop>(loopType); | |||
| 14284 | havePixelSize = havePixelSize || ((loop->type & 4) != 0); | |||
| 14285 | DRW_DBG(" loop[")DRW_dbg::dbg(" loop["); DRW_DBG(i)DRW_dbg::dbg(i); DRW_DBG("] type: ")DRW_dbg::dbg("] type: "); DRW_DBG(loop->type)DRW_dbg::dbg(loop->type); | |||
| 14286 | if (!(loop->type & 2)){ //Not polyline | |||
| 14287 | std::uint32_t numPathSeg = 0; | |||
| 14288 | if (!readTableBodyCount(version, buf, objSize, kMaxHatchItems, 8, | |||
| 14289 | numPathSeg)) | |||
| 14290 | return false; | |||
| 14291 | if (!DRW::reserve(loop->objlist, numPathSeg)) | |||
| 14292 | return false; | |||
| 14293 | DRW_DBG(" numPathSeg: ")DRW_dbg::dbg(" numPathSeg: "); DRW_DBG(numPathSeg)DRW_dbg::dbg(numPathSeg); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 14294 | for (std::uint32_t j = 0; j<numPathSeg;++j){ | |||
| 14295 | std::uint8_t typePath = 0; | |||
| 14296 | if (!readBoundedRawChar8(*buf, bodyEndBit, typePath) | |||
| 14297 | || typePath < 1 || typePath > 4) | |||
| 14298 | return false; | |||
| 14299 | DRW_DBG(" seg[")DRW_dbg::dbg(" seg["); DRW_DBG(j)DRW_dbg::dbg(j); DRW_DBG("] typePath: ")DRW_dbg::dbg("] typePath: "); DRW_DBG(typePath)DRW_dbg::dbg(typePath); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 14300 | if (typePath == 1){ //line | |||
| 14301 | DRW_Coord basePoint; | |||
| 14302 | DRW_Coord secPoint; | |||
| 14303 | if (!readBounded2RawDouble(*buf, bodyEndBit, basePoint) | |||
| 14304 | || !readBounded2RawDouble(*buf, bodyEndBit, secPoint)) | |||
| 14305 | return false; | |||
| 14306 | addLine(); | |||
| 14307 | line->basePoint = basePoint; | |||
| 14308 | line->secPoint = secPoint; | |||
| 14309 | } else if (typePath == 2){ //circle arc | |||
| 14310 | DRW_Coord basePoint; | |||
| 14311 | double radius = 0.0; | |||
| 14312 | double startAngle = 0.0; | |||
| 14313 | double endAngle = 0.0; | |||
| 14314 | bool isCcw = false; | |||
| 14315 | if (!readBounded2RawDouble(*buf, bodyEndBit, basePoint) | |||
| 14316 | || !readBoundedBitDouble(*buf, bodyEndBit, radius) | |||
| 14317 | || !readBoundedBitDouble(*buf, bodyEndBit, startAngle) | |||
| 14318 | || !readBoundedBitDouble(*buf, bodyEndBit, endAngle) | |||
| 14319 | || !readBoundedBit(*buf, bodyEndBit, isCcw) | |||
| 14320 | || !std::isfinite(basePoint.x) | |||
| 14321 | || !std::isfinite(basePoint.y) | |||
| 14322 | || !std::isfinite(radius) | |||
| 14323 | || !std::isfinite(startAngle) | |||
| 14324 | || !std::isfinite(endAngle)) | |||
| 14325 | return false; | |||
| 14326 | addArc(); | |||
| 14327 | arc->basePoint = basePoint; | |||
| 14328 | arc->radious = radius; | |||
| 14329 | arc->staangle = startAngle; | |||
| 14330 | arc->endangle = endAngle; | |||
| 14331 | arc->isccw = isCcw; | |||
| 14332 | } else if (typePath == 3){ //ellipse arc | |||
| 14333 | DRW_Coord basePoint; | |||
| 14334 | DRW_Coord secPoint; | |||
| 14335 | double ratio = 0.0; | |||
| 14336 | double startParam = 0.0; | |||
| 14337 | double endParam = 0.0; | |||
| 14338 | bool isCcw = false; | |||
| 14339 | if (!readBounded2RawDouble(*buf, bodyEndBit, basePoint) | |||
| 14340 | || !readBounded2RawDouble(*buf, bodyEndBit, secPoint) | |||
| 14341 | || !readBoundedBitDouble(*buf, bodyEndBit, ratio) | |||
| 14342 | || !readBoundedBitDouble(*buf, bodyEndBit, startParam) | |||
| 14343 | || !readBoundedBitDouble(*buf, bodyEndBit, endParam) | |||
| 14344 | || !readBoundedBit(*buf, bodyEndBit, isCcw) | |||
| 14345 | || !std::isfinite(basePoint.x) | |||
| 14346 | || !std::isfinite(basePoint.y) | |||
| 14347 | || !std::isfinite(secPoint.x) | |||
| 14348 | || !std::isfinite(secPoint.y) | |||
| 14349 | || !std::isfinite(ratio) | |||
| 14350 | || !std::isfinite(startParam) | |||
| 14351 | || !std::isfinite(endParam)) | |||
| 14352 | return false; | |||
| 14353 | addEllipse(); | |||
| 14354 | ellipse->basePoint = basePoint; | |||
| 14355 | ellipse->secPoint = secPoint; | |||
| 14356 | ellipse->ratio = ratio; | |||
| 14357 | ellipse->staparam = startParam; | |||
| 14358 | ellipse->endparam = endParam; | |||
| 14359 | ellipse->isccw = isCcw; | |||
| 14360 | } else if (typePath == 4){ //spline | |||
| 14361 | std::int32_t degree = 0; | |||
| 14362 | bool isRational = false; | |||
| 14363 | bool isPeriodic = false; | |||
| 14364 | if (!readBoundedBitLong(*buf, bodyEndBit, degree) | |||
| 14365 | || !isValidSplineDegree(degree) | |||
| 14366 | || !readBoundedBit(*buf, bodyEndBit, isRational) | |||
| 14367 | || !readBoundedBit(*buf, bodyEndBit, isPeriodic)) | |||
| 14368 | return false; | |||
| 14369 | std::uint32_t knotCount = 0; | |||
| 14370 | if (!readTableBodyCount(version, buf, objSize, | |||
| 14371 | kMaxHatchItems, 2, knotCount)) { | |||
| 14372 | return false; | |||
| 14373 | } | |||
| 14374 | std::uint32_t controlCount = 0; | |||
| 14375 | if (!readTableBodyCount(version, buf, objSize, | |||
| 14376 | kMaxHatchItems, 128, controlCount)) { | |||
| 14377 | return false; | |||
| 14378 | } | |||
| 14379 | DRW_Spline parsedSpline; | |||
| 14380 | parsedSpline.degree = degree; | |||
| 14381 | parsedSpline.nknots = static_cast<std::int32_t>(knotCount); | |||
| 14382 | parsedSpline.ncontrol = static_cast<std::int32_t>(controlCount); | |||
| 14383 | parsedSpline.flags = (isRational ? 4 : 0) | |||
| 14384 | | (isPeriodic ? 2 : 0); | |||
| 14385 | if (!DRW::reserve(parsedSpline.knotslist, knotCount) | |||
| 14386 | || !DRW::reserve(parsedSpline.controllist, controlCount)) | |||
| 14387 | return false; | |||
| 14388 | for (std::uint32_t j = 0; j < knotCount;++j){ | |||
| 14389 | double knot = 0.0; | |||
| 14390 | if (!readBoundedBitDouble(*buf, bodyEndBit, knot) | |||
| 14391 | || !std::isfinite(knot)) | |||
| 14392 | return false; | |||
| 14393 | parsedSpline.knotslist.push_back(knot); | |||
| 14394 | } | |||
| 14395 | for (std::uint32_t j = 0; j < controlCount;++j){ | |||
| 14396 | DRW_Coord control; | |||
| 14397 | if (!readBounded2RawDouble(*buf, bodyEndBit, control) | |||
| 14398 | || !std::isfinite(control.x) | |||
| 14399 | || !std::isfinite(control.y)) | |||
| 14400 | return false; | |||
| 14401 | if (isRational) { | |||
| 14402 | if (!readBoundedBitDouble(*buf, bodyEndBit, control.z) | |||
| 14403 | || !std::isfinite(control.z)) | |||
| 14404 | return false; | |||
| 14405 | } | |||
| 14406 | parsedSpline.controllist.push_back( | |||
| 14407 | std::make_shared<DRW_Coord>(control)); | |||
| 14408 | } | |||
| 14409 | if (version > DRW::AC1021) { //2010+ | |||
| 14410 | std::uint32_t fitCount = 0; | |||
| 14411 | if (!readTableBodyCount(version, buf, objSize, | |||
| 14412 | kMaxHatchItems, 128, fitCount)) | |||
| 14413 | return false; | |||
| 14414 | parsedSpline.nfit = static_cast<std::int32_t>(fitCount); | |||
| 14415 | // Fit points AND the start/end tangents are present only | |||
| 14416 | // when nfit > 0 (matches ACadSharp's `if (nfitPoints > 0)`). | |||
| 14417 | // Reading the two tangents unconditionally on an nfit==0 | |||
| 14418 | // spline edge over-runs the entity body and fails the parse | |||
| 14419 | // (e.g. svg/export_sample.dwg: a degree-3 non-rational | |||
| 14420 | // spline boundary edge with 9 control points / 0 fit points). | |||
| 14421 | if (parsedSpline.nfit > 0) { | |||
| 14422 | if (!DRW::reserve(parsedSpline.fitlist, fitCount)) { | |||
| 14423 | return false; | |||
| 14424 | } | |||
| 14425 | for (std::uint32_t j = 0; j < fitCount;++j){ | |||
| 14426 | DRW_Coord fit; | |||
| 14427 | if (!readBounded2RawDouble(*buf, bodyEndBit, fit) | |||
| 14428 | || !std::isfinite(fit.x) | |||
| 14429 | || !std::isfinite(fit.y)) | |||
| 14430 | return false; | |||
| 14431 | parsedSpline.fitlist.push_back( | |||
| 14432 | std::make_shared<DRW_Coord>(fit)); | |||
| 14433 | } | |||
| 14434 | if (!readBounded2RawDouble(*buf, bodyEndBit, | |||
| 14435 | parsedSpline.tgStart) | |||
| 14436 | || !readBounded2RawDouble(*buf, bodyEndBit, | |||
| 14437 | parsedSpline.tgEnd) | |||
| 14438 | || !std::isfinite(parsedSpline.tgStart.x) | |||
| 14439 | || !std::isfinite(parsedSpline.tgStart.y) | |||
| 14440 | || !std::isfinite(parsedSpline.tgEnd.x) | |||
| 14441 | || !std::isfinite(parsedSpline.tgEnd.y)) | |||
| 14442 | return false; | |||
| 14443 | } | |||
| 14444 | } | |||
| 14445 | addSpline(); | |||
| 14446 | *spline = std::move(parsedSpline); | |||
| 14447 | } | |||
| 14448 | } | |||
| 14449 | } else { //end not pline, start polyline | |||
| 14450 | if (!proxyEntityHasBits(*buf, bodyEndBit, 2)) | |||
| 14451 | return false; | |||
| 14452 | bool asBulge = false; | |||
| 14453 | bool closed = false; | |||
| 14454 | if (!readBoundedBit(*buf, bodyEndBit, asBulge) | |||
| 14455 | || !readBoundedBit(*buf, bodyEndBit, closed)) | |||
| 14456 | return false; | |||
| 14457 | std::uint32_t numVert = 0; | |||
| 14458 | if (!readTableBodyCount(version, buf, objSize, kMaxHatchItems, | |||
| 14459 | 128, numVert)) | |||
| 14460 | return false; | |||
| 14461 | if (!DRW::reserve(loop->objlist, 1)) | |||
| 14462 | return false; | |||
| 14463 | DRW_DBG(" asBulge: ")DRW_dbg::dbg(" asBulge: "); DRW_DBG(asBulge)DRW_dbg::dbg(asBulge); DRW_DBG(" closed: ")DRW_dbg::dbg(" closed: "); DRW_DBG(closed)DRW_dbg::dbg(closed); | |||
| 14464 | DRW_DBG(" numVert: ")DRW_dbg::dbg(" numVert: "); DRW_DBG(numVert)DRW_dbg::dbg(numVert); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 14465 | std::vector<DRW_Vertex2D> vertices; | |||
| 14466 | if (!DRW::reserve(vertices, numVert)) | |||
| 14467 | return false; | |||
| 14468 | for (std::uint32_t j = 0; j<numVert;++j){ | |||
| 14469 | DRW_Vertex2D v; | |||
| 14470 | if (!readBoundedRawDouble(*buf, bodyEndBit, v.x) | |||
| 14471 | || !readBoundedRawDouble(*buf, bodyEndBit, v.y) | |||
| 14472 | || !std::isfinite(v.x) || !std::isfinite(v.y)) | |||
| 14473 | return false; | |||
| 14474 | if (asBulge | |||
| 14475 | && (!readBoundedBitDouble(*buf, bodyEndBit, v.bulge) | |||
| 14476 | || !std::isfinite(v.bulge))) | |||
| 14477 | return false; | |||
| 14478 | vertices.push_back(v); | |||
| 14479 | } | |||
| 14480 | pline = std::make_shared<DRW_LWPolyline>(); | |||
| 14481 | pline->flags = closed; | |||
| 14482 | for (const DRW_Vertex2D& vertex : vertices) | |||
| 14483 | pline->addVertex(vertex); | |||
| 14484 | loop->objlist.push_back(pline); | |||
| 14485 | }//end polyline | |||
| 14486 | loop->update(); | |||
| 14487 | std::uint32_t boundaryHandleCount = 0; | |||
| 14488 | if (!readTableBodyCount(version, buf, objSize, kMaxHatchItems, 0, | |||
| 14489 | boundaryHandleCount) | |||
| 14490 | || totalBoundItems > kMaxHatchItems - boundaryHandleCount) | |||
| 14491 | return false; | |||
| 14492 | looplist.push_back(loop); | |||
| 14493 | totalBoundItems += boundaryHandleCount; | |||
| 14494 | DRW_DBG(" totalBoundItems: ")DRW_dbg::dbg(" totalBoundItems: "); DRW_DBG(totalBoundItems)DRW_dbg::dbg(totalBoundItems); | |||
| 14495 | } //end read loops | |||
| 14496 | return buf->isGood(); | |||
| 14497 | } catch (...) { | |||
| 14498 | return false; | |||
| 14499 | } | |||
| 14500 | } | |||
| 14501 | ||||
| 14502 | bool DRW_Hatch::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){ | |||
| 14503 | resetDwgState(); | |||
| 14504 | dwgBuffer *sourceBuf = buf; | |||
| 14505 | auto fail = [this, sourceBuf]() { | |||
| 14506 | if (sourceBuf != nullptr) | |||
| 14507 | sourceBuf->invalidate(); | |||
| 14508 | resetDwgState(); | |||
| 14509 | return false; | |||
| 14510 | }; | |||
| 14511 | if (sourceBuf == nullptr) | |||
| 14512 | return fail(); | |||
| 14513 | ||||
| 14514 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 14515 | dwgBuffer stringProbe = sourceBuf->forkIndependent(); | |||
| 14516 | buf = &bodyProbe; | |||
| 14517 | dwgBuffer *sBuf = version > DRW::AC1018 ? &stringProbe : buf; | |||
| 14518 | std::uint32_t totalBoundItems = 0; | |||
| 14519 | bool havePixelSize = false; | |||
| 14520 | ||||
| 14521 | bool ret = DRW_Entity::parseDwg( | |||
| 14522 | version, buf, version > DRW::AC1018 ? &stringProbe : nullptr, bs); | |||
| 14523 | if (!ret || !buf->isGood() || !sBuf->isGood()) | |||
| 14524 | return fail(); | |||
| 14525 | DRW_DBG("\n***************************** parsing hatch *********************************************\n")DRW_dbg::dbg("\n***************************** parsing hatch *********************************************\n" ); | |||
| 14526 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 14527 | std::uint64_t stringStartBit = bodyEndBit; | |||
| 14528 | std::uint64_t stringEndBit = bodyEndBit; | |||
| 14529 | if (version > DRW::AC1018) { | |||
| 14530 | stringStartBit = currentDwgBit(sBuf); | |||
| 14531 | if (version > DRW::AC1021) { | |||
| 14532 | std::uint64_t ignoredBodyEndBit = 0; | |||
| 14533 | if (!entityBodyDataEndBit(*sBuf, version, objSize, | |||
| 14534 | ignoredBodyEndBit, &stringEndBit)) | |||
| 14535 | return fail(); | |||
| 14536 | } | |||
| 14537 | } | |||
| 14538 | ||||
| 14539 | if (version > DRW::AC1015) { //2004+ | |||
| 14540 | if (!readBoundedHatchGradient( | |||
| 14541 | *buf, sBuf, bodyEndBit, version, isGradient, gradReserved, | |||
| 14542 | gradAngle, gradShift, singleColor, gradTint, gradName, | |||
| 14543 | gradColors, stringEndBit)) | |||
| 14544 | return fail(); | |||
| 14545 | DRW_DBG("\ngradient name: ")DRW_dbg::dbg("\ngradient name: "); DRW_DBG(gradName.c_str())DRW_dbg::dbg(gradName.c_str()); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 14546 | } | |||
| 14547 | DRW_Coord parsedBasePoint = basePoint; | |||
| 14548 | DRW_Coord parsedExtPoint; | |||
| 14549 | UTF8STRINGstd::string parsedName; | |||
| 14550 | bool parsedSolid = false; | |||
| 14551 | bool parsedAssociative = false; | |||
| 14552 | if (!readBoundedBitDouble(*buf, bodyEndBit, parsedBasePoint.z) | |||
| 14553 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedExtPoint) | |||
| 14554 | || !std::isfinite(parsedBasePoint.z) | |||
| 14555 | || !std::isfinite(parsedExtPoint.x) | |||
| 14556 | || !std::isfinite(parsedExtPoint.y) | |||
| 14557 | || !std::isfinite(parsedExtPoint.z)) | |||
| 14558 | return fail(); | |||
| 14559 | DRW_DBG("base point: ")DRW_dbg::dbg("base point: "); DRW_DBGPT(parsedBasePoint.x, parsedBasePoint.y,DRW_dbg::dbgPT(parsedBasePoint.x, parsedBasePoint.y, parsedBasePoint .z) | |||
| 14560 | parsedBasePoint.z)DRW_dbg::dbgPT(parsedBasePoint.x, parsedBasePoint.y, parsedBasePoint .z); | |||
| 14561 | DRW_DBG("\nextrusion: ")DRW_dbg::dbg("\nextrusion: "); DRW_DBGPT(parsedExtPoint.x, parsedExtPoint.y,DRW_dbg::dbgPT(parsedExtPoint.x, parsedExtPoint.y, parsedExtPoint .z) | |||
| 14562 | parsedExtPoint.z)DRW_dbg::dbgPT(parsedExtPoint.x, parsedExtPoint.y, parsedExtPoint .z); | |||
| 14563 | if (version > DRW::AC1018 && stringStartBit >= stringEndBit) { | |||
| 14564 | parsedName.clear(); | |||
| 14565 | } else if (!readBoundedVariableText(*sBuf, stringEndBit, version, | |||
| 14566 | parsedName)) { | |||
| 14567 | return fail(); | |||
| 14568 | } | |||
| 14569 | if (!sBuf->isGood() | |||
| 14570 | || currentDwgBit(sBuf) > stringEndBit | |||
| 14571 | || !readBoundedBit(*buf, bodyEndBit, parsedSolid) | |||
| 14572 | || !readBoundedBit(*buf, bodyEndBit, parsedAssociative)) | |||
| 14573 | return fail(); | |||
| 14574 | basePoint = parsedBasePoint; | |||
| 14575 | extPoint = parsedExtPoint; | |||
| 14576 | name = std::move(parsedName); | |||
| 14577 | solid = parsedSolid; | |||
| 14578 | associative = parsedAssociative; | |||
| 14579 | DRW_DBG("\nhatch pattern name: ")DRW_dbg::dbg("\nhatch pattern name: "); DRW_DBG(name.c_str())DRW_dbg::dbg(name.c_str()); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 14580 | if (!parseDwgBoundaryData(version, buf, totalBoundItems, havePixelSize)) | |||
| 14581 | return fail(); | |||
| 14582 | ||||
| 14583 | std::uint16_t parsedStyle = 0; | |||
| 14584 | std::uint16_t parsedPattern = 0; | |||
| 14585 | if (!readBoundedBitShort(*buf, bodyEndBit, parsedStyle) | |||
| 14586 | || !readBoundedBitShort(*buf, bodyEndBit, parsedPattern)) | |||
| 14587 | return fail(); | |||
| 14588 | hstyle = parsedStyle; | |||
| 14589 | hpattern = parsedPattern; | |||
| 14590 | DRW_DBG("\nhatch style: ")DRW_dbg::dbg("\nhatch style: "); DRW_DBG(hstyle)DRW_dbg::dbg(hstyle); DRW_DBG(" pattern type")DRW_dbg::dbg(" pattern type"); DRW_DBG(hpattern)DRW_dbg::dbg(hpattern); | |||
| 14591 | if (!solid){ | |||
| 14592 | double parsedAngle = 0.0; | |||
| 14593 | double parsedScale = 0.0; | |||
| 14594 | bool parsedDoubleFlag = false; | |||
| 14595 | if (!readBoundedBitDouble(*buf, bodyEndBit, parsedAngle) | |||
| 14596 | || !readBoundedBitDouble(*buf, bodyEndBit, parsedScale) | |||
| 14597 | || !readBoundedBit(*buf, bodyEndBit, parsedDoubleFlag) | |||
| 14598 | || !std::isfinite(parsedAngle) | |||
| 14599 | || !std::isfinite(parsedScale)) | |||
| 14600 | return fail(); | |||
| 14601 | angle = parsedAngle; | |||
| 14602 | scale = parsedScale; | |||
| 14603 | doubleflag = parsedDoubleFlag; | |||
| 14604 | std::uint32_t parsedDeflines = 0; | |||
| 14605 | if (!readTableBodyCount(version, buf, objSize, kMaxHatchItems, 12, | |||
| 14606 | parsedDeflines)) | |||
| 14607 | return fail(); | |||
| 14608 | deflines = static_cast<int>(parsedDeflines); | |||
| 14609 | for (std::uint32_t i = 0 ; i < parsedDeflines; ++i){ | |||
| 14610 | PatternLine patternLine; | |||
| 14611 | if (!readBoundedBitDouble(*buf, bodyEndBit, patternLine.angle) | |||
| 14612 | || !readBoundedBitDouble(*buf, bodyEndBit, patternLine.baseX) | |||
| 14613 | || !readBoundedBitDouble(*buf, bodyEndBit, patternLine.baseY) | |||
| 14614 | || !readBoundedBitDouble(*buf, bodyEndBit, patternLine.offsetX) | |||
| 14615 | || !readBoundedBitDouble(*buf, bodyEndBit, patternLine.offsetY) | |||
| 14616 | || !std::isfinite(patternLine.angle) | |||
| 14617 | || !std::isfinite(patternLine.baseX) | |||
| 14618 | || !std::isfinite(patternLine.baseY) | |||
| 14619 | || !std::isfinite(patternLine.offsetX) | |||
| 14620 | || !std::isfinite(patternLine.offsetY)) | |||
| 14621 | return fail(); | |||
| 14622 | std::uint32_t numDashL = 0; | |||
| 14623 | if (!readTableBodyCount(version, buf, objSize, kMaxHatchItems, 2, | |||
| 14624 | numDashL) | |||
| 14625 | || !proxyEntityHasBits( | |||
| 14626 | *buf, bodyEndBit, static_cast<std::uint64_t>(numDashL) * 2u) | |||
| 14627 | || !DRW::reserve(patternLine.dashList, numDashL)) | |||
| 14628 | return fail(); | |||
| 14629 | DRW_DBG("\ndef line: ")DRW_dbg::dbg("\ndef line: "); DRW_DBG(patternLine.angle)DRW_dbg::dbg(patternLine.angle); DRW_DBG(",")DRW_dbg::dbg(","); | |||
| 14630 | DRW_DBG(patternLine.baseX)DRW_dbg::dbg(patternLine.baseX); DRW_DBG(",")DRW_dbg::dbg(","); DRW_DBG(patternLine.baseY)DRW_dbg::dbg(patternLine.baseY); | |||
| 14631 | DRW_DBG(",")DRW_dbg::dbg(","); DRW_DBG(patternLine.offsetX)DRW_dbg::dbg(patternLine.offsetX); DRW_DBG(",")DRW_dbg::dbg(","); | |||
| 14632 | DRW_DBG(patternLine.offsetY)DRW_dbg::dbg(patternLine.offsetY); | |||
| 14633 | for (std::uint32_t i = 0 ; i < numDashL; ++i){ | |||
| 14634 | double lengthL = 0.0; | |||
| 14635 | if (!readBoundedBitDouble(*buf, bodyEndBit, lengthL) | |||
| 14636 | || !std::isfinite(lengthL)) | |||
| 14637 | return fail(); | |||
| 14638 | patternLine.dashList.push_back(lengthL); | |||
| 14639 | DRW_DBG(",")DRW_dbg::dbg(","); DRW_DBG(lengthL)DRW_dbg::dbg(lengthL); | |||
| 14640 | } | |||
| 14641 | patternLines.push_back(std::move(patternLine)); | |||
| 14642 | }//end deflines | |||
| 14643 | } //end not solid | |||
| 14644 | ||||
| 14645 | if (havePixelSize){ | |||
| 14646 | if (!readBoundedBitDouble(*buf, bodyEndBit, pixelSize) | |||
| 14647 | || !std::isfinite(pixelSize)) | |||
| 14648 | return fail(); | |||
| 14649 | DRW_DBG("\npixel size: ")DRW_dbg::dbg("\npixel size: "); DRW_DBG(pixelSize)DRW_dbg::dbg(pixelSize); | |||
| 14650 | } | |||
| 14651 | std::uint32_t numSeedPoints = 0; | |||
| 14652 | if (!readTableBodyCount(version, buf, objSize, kMaxHatchItems, 128, | |||
| 14653 | numSeedPoints) | |||
| 14654 | || !proxyEntityHasBits( | |||
| 14655 | *buf, bodyEndBit, static_cast<std::uint64_t>(numSeedPoints) * 128u) | |||
| 14656 | || !DRW::reserve(seedPoints, numSeedPoints)) | |||
| 14657 | return fail(); | |||
| 14658 | DRW_DBG("\nnum Seed Points ")DRW_dbg::dbg("\nnum Seed Points "); DRW_DBG(numSeedPoints)DRW_dbg::dbg(numSeedPoints); | |||
| 14659 | for (std::uint32_t i = 0 ; i < numSeedPoints; ++i){ | |||
| 14660 | DRW_Coord seedPt; | |||
| 14661 | if (!readBounded2RawDouble(*buf, bodyEndBit, seedPt) | |||
| 14662 | || !std::isfinite(seedPt.x) | |||
| 14663 | || !std::isfinite(seedPt.y)) | |||
| 14664 | return fail(); | |||
| 14665 | DRW_DBG("\n ")DRW_dbg::dbg("\n "); DRW_DBG(seedPt.x)DRW_dbg::dbg(seedPt.x); DRW_DBG(",")DRW_dbg::dbg(","); DRW_DBG(seedPt.y)DRW_dbg::dbg(seedPt.y); | |||
| 14666 | seedPoints.push_back(seedPt); | |||
| 14667 | } | |||
| 14668 | ||||
| 14669 | DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 14670 | std::uint64_t handleEndBit = 0; | |||
| 14671 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, | |||
| 14672 | handleEndBit)) | |||
| 14673 | return fail(); | |||
| 14674 | dwgBuffer handleProbe = buf->forkIndependent(); | |||
| 14675 | ret = DRW_Entity::parseDwgEntHandle(version, &handleProbe, true, | |||
| 14676 | handleEndBit); | |||
| 14677 | if (!ret || !handleProbe.isGood()) | |||
| 14678 | return fail(); | |||
| 14679 | DRW_DBG("Remaining bytes: ")DRW_dbg::dbg("Remaining bytes: "); DRW_DBG(handleProbe.numRemainingBytes())DRW_dbg::dbg(handleProbe.numRemainingBytes()); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 14680 | ||||
| 14681 | for (std::uint32_t i = 0 ; i < totalBoundItems; ++i){ | |||
| 14682 | dwgHandle biH; | |||
| 14683 | if (!readBoundedDwgHandle(handleProbe, handleEndBit, handle, false, | |||
| 14684 | biH)) | |||
| 14685 | return fail(); | |||
| 14686 | DRW_DBG("Boundary Items Handle: ")DRW_dbg::dbg("Boundary Items Handle: "); DRW_DBGHL(biH.code, biH.size, biH.ref)DRW_dbg::dbgHL(biH.code, biH.size, biH.ref); | |||
| 14687 | } | |||
| 14688 | DRW_DBG("Remaining bytes: ")DRW_dbg::dbg("Remaining bytes: "); DRW_DBG(handleProbe.numRemainingBytes())DRW_dbg::dbg(handleProbe.numRemainingBytes()); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 14689 | // RS crc; //RS */ | |||
| 14690 | if (!handleProbe.isGood()) | |||
| 14691 | return fail(); | |||
| 14692 | *sourceBuf = handleProbe; | |||
| 14693 | return true; | |||
| 14694 | } | |||
| 14695 | ||||
| 14696 | void DRW_Hatch::encodeDwgGradientData(DRW::Version version, dwgBufferW *buf, | |||
| 14697 | dwgBufferW *strBuf) const { | |||
| 14698 | if (version <= DRW::AC1015) | |||
| 14699 | return; | |||
| 14700 | ||||
| 14701 | dwgBufferW *sb = strBuf ? strBuf : buf; | |||
| 14702 | buf->putBitLong(isGradient); | |||
| ||||
| 14703 | buf->putBitLong(gradReserved); | |||
| 14704 | buf->putBitDouble(gradAngle); | |||
| 14705 | buf->putBitDouble(gradShift); | |||
| 14706 | buf->putBitLong(singleColor); | |||
| 14707 | buf->putBitDouble(gradTint); | |||
| 14708 | buf->putBitLong(static_cast<std::int32_t>(gradColors.size())); | |||
| 14709 | for (const GradientStop& stop : gradColors) { | |||
| 14710 | buf->putBitDouble(stop.value); | |||
| 14711 | buf->putBitShort(static_cast<std::uint16_t>(stop.aciColor)); | |||
| 14712 | buf->putBitLong(static_cast<std::uint32_t>(stop.rgb)); | |||
| 14713 | buf->putRawChar8(0); | |||
| 14714 | } | |||
| 14715 | sb->putVariableText(version, gradName); | |||
| 14716 | } | |||
| 14717 | ||||
| 14718 | bool DRW_Hatch::encodeDwgBoundaryData(DRW::Version version, dwgBufferW *buf, | |||
| 14719 | bool includePixelSize) const { | |||
| 14720 | buf->putBitLong(static_cast<std::int32_t>(looplist.size())); | |||
| 14721 | ||||
| 14722 | for (const auto& lp : looplist) { | |||
| 14723 | buf->putBitLong(includePixelSize ? lp->type : lp->type & ~4); | |||
| 14724 | ||||
| 14725 | if (!(lp->type & 2)) { | |||
| 14726 | buf->putBitLong(static_cast<std::int32_t>(lp->objlist.size())); | |||
| 14727 | for (const auto& seg : lp->objlist) { | |||
| 14728 | if (const auto* ln = dynamic_cast<const DRW_Line*>(seg.get())) { | |||
| 14729 | buf->putRawChar8(1); // line | |||
| 14730 | buf->put2RawDouble(ln->basePoint); | |||
| 14731 | buf->put2RawDouble(ln->secPoint); | |||
| 14732 | } else if (const auto* arc = dynamic_cast<const DRW_Arc*>(seg.get())) { | |||
| 14733 | buf->putRawChar8(2); // circular arc | |||
| 14734 | buf->put2RawDouble(arc->basePoint); | |||
| 14735 | buf->putBitDouble(arc->radious); | |||
| 14736 | buf->putBitDouble(arc->staangle); | |||
| 14737 | buf->putBitDouble(arc->endangle); | |||
| 14738 | buf->putBit(static_cast<std::uint8_t>(arc->isccw)); | |||
| 14739 | } else if (const auto* el = dynamic_cast<const DRW_Ellipse*>(seg.get())) { | |||
| 14740 | buf->putRawChar8(3); // ellipse arc | |||
| 14741 | buf->put2RawDouble(el->basePoint); | |||
| 14742 | buf->put2RawDouble(el->secPoint); | |||
| 14743 | buf->putBitDouble(el->ratio); | |||
| 14744 | buf->putBitDouble(el->staparam); | |||
| 14745 | buf->putBitDouble(el->endparam); | |||
| 14746 | buf->putBit(static_cast<std::uint8_t>(el->isccw)); | |||
| 14747 | } else if (const auto* sp = dynamic_cast<const DRW_Spline*>(seg.get())) { | |||
| 14748 | buf->putRawChar8(4); // spline | |||
| 14749 | buf->putBitLong(sp->degree); | |||
| 14750 | bool isRational = (sp->flags & 4) != 0; | |||
| 14751 | bool isPeriodic = (sp->flags & 2) != 0; | |||
| 14752 | buf->putBit(static_cast<std::uint8_t>(isRational)); | |||
| 14753 | buf->putBit(static_cast<std::uint8_t>(isPeriodic)); | |||
| 14754 | buf->putBitLong(static_cast<std::int32_t>(sp->knotslist.size())); | |||
| 14755 | buf->putBitLong(static_cast<std::int32_t>(sp->controllist.size())); | |||
| 14756 | for (double k : sp->knotslist) | |||
| 14757 | buf->putBitDouble(k); | |||
| 14758 | for (const auto& cp : sp->controllist) { | |||
| 14759 | DRW_Coord c2{cp->x, cp->y, 0.0}; | |||
| 14760 | buf->put2RawDouble(c2); | |||
| 14761 | if (isRational) | |||
| 14762 | buf->putBitDouble(cp->z); | |||
| 14763 | } | |||
| 14764 | if (version > DRW::AC1021) { | |||
| 14765 | buf->putBitLong(static_cast<std::int32_t>(sp->fitlist.size())); | |||
| 14766 | for (const auto& fp : sp->fitlist) { | |||
| 14767 | DRW_Coord f2{fp->x, fp->y, 0.0}; | |||
| 14768 | buf->put2RawDouble(f2); | |||
| 14769 | } | |||
| 14770 | buf->put2RawDouble(sp->tgStart); | |||
| 14771 | buf->put2RawDouble(sp->tgEnd); | |||
| 14772 | } | |||
| 14773 | } else { | |||
| 14774 | return false; | |||
| 14775 | } | |||
| 14776 | } | |||
| 14777 | } else { | |||
| 14778 | const DRW_LWPolyline* pl = nullptr; | |||
| 14779 | if (!lp->objlist.empty()) | |||
| 14780 | pl = dynamic_cast<const DRW_LWPolyline*>(lp->objlist[0].get()); | |||
| 14781 | if (!pl) | |||
| 14782 | return false; | |||
| 14783 | ||||
| 14784 | bool asBulge = false; | |||
| 14785 | for (const auto& v : pl->vertlist) | |||
| 14786 | if (v->bulge != 0.0) { asBulge = true; break; } | |||
| 14787 | ||||
| 14788 | buf->putBit(static_cast<std::uint8_t>(asBulge)); | |||
| 14789 | buf->putBit(static_cast<std::uint8_t>(pl->flags & 1)); | |||
| 14790 | buf->putBitLong(static_cast<std::int32_t>(pl->vertlist.size())); | |||
| 14791 | for (const auto& v : pl->vertlist) { | |||
| 14792 | buf->putRawDouble(v->x); | |||
| 14793 | buf->putRawDouble(v->y); | |||
| 14794 | if (asBulge) | |||
| 14795 | buf->putBitDouble(v->bulge); | |||
| 14796 | } | |||
| 14797 | } | |||
| 14798 | ||||
| 14799 | buf->putBitLong(0); // numBoundHandles for this loop (0 = non-associative) | |||
| 14800 | } | |||
| 14801 | ||||
| 14802 | return true; | |||
| 14803 | } | |||
| 14804 | ||||
| 14805 | bool DRW_Hatch::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 14806 | (void)bs; | |||
| 14807 | if (!validateDwgHatchData(*this)) | |||
| ||||
| 14808 | return false; | |||
| 14809 | oType = 78; // HATCH class id — see dwgreader.cpp:1380 | |||
| 14810 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 14811 | ||||
| 14812 | dwgBufferW *sb = strBuf ? strBuf : buf; | |||
| 14813 | encodeDwgGradientData(version, buf, sb); | |||
| 14814 | ||||
| 14815 | buf->putBitDouble(basePoint.z); // BD: elevation | |||
| 14816 | buf->put3BitDouble(extPoint); // 3BD: extrusion (NOT BE-style for HATCH) | |||
| 14817 | sb->putVariableText(version, name); // TV: hatch pattern name | |||
| 14818 | buf->putBit(static_cast<std::uint8_t>(solid)); | |||
| 14819 | buf->putBit(static_cast<std::uint8_t>(associative)); | |||
| 14820 | if (!encodeDwgBoundaryData(version, buf, true)) return false; | |||
| 14821 | ||||
| 14822 | buf->putBitShort(static_cast<std::uint16_t>(hstyle)); | |||
| 14823 | buf->putBitShort(static_cast<std::uint16_t>(hpattern)); | |||
| 14824 | ||||
| 14825 | if (!solid) { | |||
| 14826 | buf->putBitDouble(angle); | |||
| 14827 | buf->putBitDouble(scale); | |||
| 14828 | buf->putBit(static_cast<std::uint8_t>(doubleflag)); | |||
| 14829 | buf->putBitShort(static_cast<std::uint16_t>(patternLines.size())); | |||
| 14830 | for (const PatternLine& patternLine : patternLines) { | |||
| 14831 | buf->putBitDouble(patternLine.angle); | |||
| 14832 | buf->putBitDouble(patternLine.baseX); | |||
| 14833 | buf->putBitDouble(patternLine.baseY); | |||
| 14834 | buf->putBitDouble(patternLine.offsetX); | |||
| 14835 | buf->putBitDouble(patternLine.offsetY); | |||
| 14836 | buf->putBitShort(static_cast<std::uint16_t>(patternLine.dashList.size())); | |||
| 14837 | for (double dash : patternLine.dashList) | |||
| 14838 | buf->putBitDouble(dash); | |||
| 14839 | } | |||
| 14840 | } | |||
| 14841 | ||||
| 14842 | bool havePixelSize = false; | |||
| 14843 | for (const auto& lp : looplist) | |||
| 14844 | havePixelSize = havePixelSize || (lp && ((lp->type & 4) != 0)); | |||
| 14845 | if (havePixelSize) | |||
| 14846 | buf->putBitDouble(pixelSize); | |||
| 14847 | ||||
| 14848 | buf->putBitLong(static_cast<std::int32_t>(seedPoints.size())); | |||
| 14849 | for (const auto& sp : seedPoints) { | |||
| 14850 | buf->putRawDouble(sp.x); | |||
| 14851 | buf->putRawDouble(sp.y); | |||
| 14852 | } | |||
| 14853 | ||||
| 14854 | if (!encodeDwgEntHandle(version, buf, handleBuf)) return false; | |||
| 14855 | return true; | |||
| 14856 | } | |||
| 14857 | ||||
| 14858 | bool DRW_Spline::parseCode(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 14859 | switch (code) { | |||
| 14860 | case 210: | |||
| 14861 | normalVec.x = reader->getDouble(); | |||
| 14862 | break; | |||
| 14863 | case 220: | |||
| 14864 | normalVec.y = reader->getDouble(); | |||
| 14865 | break; | |||
| 14866 | case 230: | |||
| 14867 | normalVec.z = reader->getDouble(); | |||
| 14868 | break; | |||
| 14869 | case 12: | |||
| 14870 | tgStart.x = reader->getDouble(); | |||
| 14871 | break; | |||
| 14872 | case 22: | |||
| 14873 | tgStart.y = reader->getDouble(); | |||
| 14874 | break; | |||
| 14875 | case 32: | |||
| 14876 | tgStart.z = reader->getDouble(); | |||
| 14877 | break; | |||
| 14878 | case 13: | |||
| 14879 | tgEnd.x = reader->getDouble(); | |||
| 14880 | break; | |||
| 14881 | case 23: | |||
| 14882 | tgEnd.y = reader->getDouble(); | |||
| 14883 | break; | |||
| 14884 | case 33: | |||
| 14885 | tgEnd.z = reader->getDouble(); | |||
| 14886 | break; | |||
| 14887 | case 70: | |||
| 14888 | flags = reader->getInt32(); | |||
| 14889 | break; | |||
| 14890 | case 71: | |||
| 14891 | degree = reader->getInt32(); | |||
| 14892 | if (!isValidCount(degree, kMaxDxfDegree) || degree == 0) | |||
| 14893 | return false; | |||
| 14894 | m_dxfDegreeSeen = true; | |||
| 14895 | break; | |||
| 14896 | case 72: | |||
| 14897 | if (m_dxfKnotCountSeen) | |||
| 14898 | return false; | |||
| 14899 | nknots = reader->getInt32(); | |||
| 14900 | if (!isValidCount(nknots, kMaxDxfItems)) | |||
| 14901 | return false; | |||
| 14902 | m_dxfKnotCountSeen = true; | |||
| 14903 | break; | |||
| 14904 | case 73: | |||
| 14905 | if (m_dxfControlCountSeen) | |||
| 14906 | return false; | |||
| 14907 | ncontrol = reader->getInt32(); | |||
| 14908 | if (!isValidCount(ncontrol, kMaxDxfItems)) | |||
| 14909 | return false; | |||
| 14910 | m_dxfControlCountSeen = true; | |||
| 14911 | break; | |||
| 14912 | case 74: | |||
| 14913 | if (m_dxfFitCountSeen) | |||
| 14914 | return false; | |||
| 14915 | nfit = reader->getInt32(); | |||
| 14916 | if (!isValidCount(nfit, kMaxDxfItems)) | |||
| 14917 | return false; | |||
| 14918 | m_dxfFitCountSeen = true; | |||
| 14919 | break; | |||
| 14920 | case 42: | |||
| 14921 | tolknot = reader->getDouble(); | |||
| 14922 | break; | |||
| 14923 | case 43: | |||
| 14924 | tolcontrol = reader->getDouble(); | |||
| 14925 | break; | |||
| 14926 | case 44: | |||
| 14927 | tolfit = reader->getDouble(); | |||
| 14928 | break; | |||
| 14929 | case 10: { | |||
| 14930 | if (controllist.size() >= static_cast<std::size_t>(kMaxDxfItems) | |||
| 14931 | || (m_dxfControlCountSeen | |||
| 14932 | && controllist.size() >= static_cast<std::size_t>(ncontrol))) | |||
| 14933 | return false; | |||
| 14934 | controlpoint = std::make_shared<DRW_Coord>(); | |||
| 14935 | controllist.push_back(controlpoint); | |||
| 14936 | controlpoint->x = reader->getDouble(); | |||
| 14937 | break; } | |||
| 14938 | case 20: | |||
| 14939 | if(controlpoint) | |||
| 14940 | controlpoint->y = reader->getDouble(); | |||
| 14941 | break; | |||
| 14942 | case 30: | |||
| 14943 | if(controlpoint) | |||
| 14944 | controlpoint->z = reader->getDouble(); | |||
| 14945 | break; | |||
| 14946 | case 11: { | |||
| 14947 | if (fitlist.size() >= static_cast<std::size_t>(kMaxDxfItems) | |||
| 14948 | || (m_dxfFitCountSeen | |||
| 14949 | && fitlist.size() >= static_cast<std::size_t>(nfit))) | |||
| 14950 | return false; | |||
| 14951 | fitpoint = std::make_shared<DRW_Coord>(); | |||
| 14952 | fitlist.push_back(fitpoint); | |||
| 14953 | fitpoint->x = reader->getDouble(); | |||
| 14954 | break; } | |||
| 14955 | case 21: | |||
| 14956 | if(fitpoint) | |||
| 14957 | fitpoint->y = reader->getDouble(); | |||
| 14958 | break; | |||
| 14959 | case 31: | |||
| 14960 | if(fitpoint) | |||
| 14961 | fitpoint->z = reader->getDouble(); | |||
| 14962 | break; | |||
| 14963 | case 40: | |||
| 14964 | if (knotslist.size() >= static_cast<std::size_t>(kMaxDxfItems) | |||
| 14965 | || (m_dxfKnotCountSeen | |||
| 14966 | && knotslist.size() >= static_cast<std::size_t>(nknots))) | |||
| 14967 | return false; | |||
| 14968 | knotslist.push_back(reader->getDouble()); | |||
| 14969 | break; | |||
| 14970 | case 41: | |||
| 14971 | if (weightlist.size() >= static_cast<std::size_t>(kMaxDxfItems) | |||
| 14972 | || (m_dxfControlCountSeen | |||
| 14973 | && weightlist.size() >= static_cast<std::size_t>(ncontrol))) | |||
| 14974 | return false; | |||
| 14975 | weightlist.push_back(reader->getDouble()); | |||
| 14976 | break; | |||
| 14977 | default: | |||
| 14978 | return DRW_Entity::parseCode(code, reader); | |||
| 14979 | } | |||
| 14980 | ||||
| 14981 | return true; | |||
| 14982 | } | |||
| 14983 | ||||
| 14984 | bool DRW_Spline::validateDxf() const { | |||
| 14985 | if (m_dxfKnotCountSeen | |||
| 14986 | && knotslist.size() != static_cast<std::size_t>(nknots)) | |||
| 14987 | return false; | |||
| 14988 | if (m_dxfControlCountSeen | |||
| 14989 | && controllist.size() != static_cast<std::size_t>(ncontrol)) | |||
| 14990 | return false; | |||
| 14991 | if (m_dxfFitCountSeen | |||
| 14992 | && fitlist.size() != static_cast<std::size_t>(nfit)) | |||
| 14993 | return false; | |||
| 14994 | return validatePayloadFields(/*allowMixedLists=*/true); | |||
| 14995 | } | |||
| 14996 | ||||
| 14997 | bool DRW_Spline::validatePayloadFields(bool allowMixedLists) const { | |||
| 14998 | const auto finite = [](double value) { return std::isfinite(value); }; | |||
| 14999 | const auto finiteCoord = [&finite](const DRW_Coord& point) { | |||
| 15000 | return finite(point.x) && finite(point.y) && finite(point.z); | |||
| 15001 | }; | |||
| 15002 | const auto validCount = [](std::size_t count) { | |||
| 15003 | return count <= static_cast<std::size_t>(kMaxSplineItems) | |||
| 15004 | && count <= static_cast<std::size_t>( | |||
| 15005 | std::numeric_limits<std::int32_t>::max()); | |||
| 15006 | }; | |||
| 15007 | const auto validPointList = [&finiteCoord, &validCount](const auto& points) { | |||
| 15008 | return validCount(points.size()) | |||
| 15009 | && std::all_of(points.cbegin(), points.cend(), | |||
| 15010 | [&finiteCoord](const auto& point) { | |||
| 15011 | return point != nullptr && finiteCoord(*point); | |||
| 15012 | }); | |||
| 15013 | }; | |||
| 15014 | ||||
| 15015 | if (!isValidSplineDegree(degree) | |||
| 15016 | // Bits above 16 (AutoCAD 2013+ sets 32 and 1024 on fit splines) are | |||
| 15017 | // not used, but a 16-bit value is accepted. | |||
| 15018 | || flags < 0 || flags > 0xFFFF | |||
| 15019 | || !finiteCoord(normalVec) || !finiteCoord(tgStart) | |||
| 15020 | || !finiteCoord(tgEnd) || !finite(tolknot) | |||
| 15021 | || !finite(tolcontrol) || !finite(tolfit) | |||
| 15022 | || !validCount(knotslist.size()) | |||
| 15023 | || !std::all_of(knotslist.cbegin(), knotslist.cend(), finite) | |||
| 15024 | || !validCount(weightlist.size()) | |||
| 15025 | || !std::all_of(weightlist.cbegin(), weightlist.cend(), finite) | |||
| 15026 | || !validPointList(controllist) || !validPointList(fitlist) | |||
| 15027 | || weightlist.size() > controllist.size()) | |||
| 15028 | return false; | |||
| 15029 | ||||
| 15030 | // The DWG body has disjoint control-point and fit-point scenarios. When | |||
| 15031 | // both lists are present, the encoder selects control points and would | |||
| 15032 | // silently discard the fit points, so reject that lossy representation. | |||
| 15033 | if (!allowMixedLists && !fitlist.empty() && !controllist.empty()) | |||
| 15034 | return false; | |||
| 15035 | if (!fitlist.empty() && !controllist.empty()) | |||
| 15036 | return isValidControlSplineLayout( | |||
| 15037 | degree, static_cast<std::int32_t>(knotslist.size()), | |||
| 15038 | static_cast<std::int32_t>(controllist.size())) | |||
| 15039 | && isValidFitSplineLayout( | |||
| 15040 | degree, static_cast<std::int32_t>(fitlist.size())); | |||
| 15041 | if (!fitlist.empty()) | |||
| 15042 | return isValidFitSplineLayout( | |||
| 15043 | degree, static_cast<std::int32_t>(fitlist.size())); | |||
| 15044 | return isValidControlSplineLayout( | |||
| 15045 | degree, static_cast<std::int32_t>(knotslist.size()), | |||
| 15046 | static_cast<std::int32_t>(controllist.size())); | |||
| 15047 | } | |||
| 15048 | ||||
| 15049 | bool DRW_Helix::validateDxf() const { | |||
| 15050 | const auto finite = [](const DRW_Coord& point) { | |||
| 15051 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 15052 | && std::isfinite(point.z); | |||
| 15053 | }; | |||
| 15054 | return DRW_Spline::validateDxf() | |||
| 15055 | && finite(axisBasePt) && finite(startPt) && finite(axisVector) | |||
| 15056 | && std::isfinite(radius) && std::isfinite(turns) | |||
| 15057 | && std::isfinite(turnHeight); | |||
| 15058 | } | |||
| 15059 | ||||
| 15060 | bool DRW_Helix::parseCode(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 15061 | if (code == 100) { | |||
| 15062 | const std::string subclass = reader->getString(); | |||
| 15063 | m_parsingHelixSubclass = (subclass == "AcDbHelix"); | |||
| 15064 | return true; | |||
| 15065 | } | |||
| 15066 | ||||
| 15067 | if (!m_parsingHelixSubclass) | |||
| 15068 | return DRW_Spline::parseCode(code, reader); | |||
| 15069 | ||||
| 15070 | switch (code) { | |||
| 15071 | case 90: | |||
| 15072 | m_majorVersion = reader->getInt32(); | |||
| 15073 | break; | |||
| 15074 | case 91: | |||
| 15075 | m_maintVersion = reader->getInt32(); | |||
| 15076 | break; | |||
| 15077 | case 10: | |||
| 15078 | axisBasePt.x = reader->getDouble(); | |||
| 15079 | break; | |||
| 15080 | case 20: | |||
| 15081 | axisBasePt.y = reader->getDouble(); | |||
| 15082 | break; | |||
| 15083 | case 30: | |||
| 15084 | axisBasePt.z = reader->getDouble(); | |||
| 15085 | break; | |||
| 15086 | case 11: | |||
| 15087 | startPt.x = reader->getDouble(); | |||
| 15088 | break; | |||
| 15089 | case 21: | |||
| 15090 | startPt.y = reader->getDouble(); | |||
| 15091 | break; | |||
| 15092 | case 31: | |||
| 15093 | startPt.z = reader->getDouble(); | |||
| 15094 | break; | |||
| 15095 | case 12: | |||
| 15096 | axisVector.x = reader->getDouble(); | |||
| 15097 | break; | |||
| 15098 | case 22: | |||
| 15099 | axisVector.y = reader->getDouble(); | |||
| 15100 | break; | |||
| 15101 | case 32: | |||
| 15102 | axisVector.z = reader->getDouble(); | |||
| 15103 | break; | |||
| 15104 | case 40: | |||
| 15105 | radius = reader->getDouble(); | |||
| 15106 | break; | |||
| 15107 | case 41: | |||
| 15108 | turns = reader->getDouble(); | |||
| 15109 | break; | |||
| 15110 | case 42: | |||
| 15111 | turnHeight = reader->getDouble(); | |||
| 15112 | break; | |||
| 15113 | case 290: | |||
| 15114 | { | |||
| 15115 | int value = 0; | |||
| 15116 | if (!readDxfIntInRange(reader, 0, 1, value)) | |||
| 15117 | return false; | |||
| 15118 | handedness = value != 0; | |||
| 15119 | } | |||
| 15120 | break; | |||
| 15121 | case 280: | |||
| 15122 | { | |||
| 15123 | int value = 0; | |||
| 15124 | if (!readDxfIntInRange(reader, 0, 0xFF, value)) | |||
| 15125 | return false; | |||
| 15126 | constraintType = static_cast<std::uint8_t>(value); | |||
| 15127 | } | |||
| 15128 | break; | |||
| 15129 | default: | |||
| 15130 | return DRW_Entity::parseCode(code, reader); | |||
| 15131 | } | |||
| 15132 | ||||
| 15133 | return true; | |||
| 15134 | } | |||
| 15135 | ||||
| 15136 | void DRW_Spline::resetDwgState() { | |||
| 15137 | DRW_Entity::reset(); | |||
| 15138 | normalVec = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 15139 | tgStart = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 15140 | tgEnd = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 15141 | flags = 0; | |||
| 15142 | degree = 0; | |||
| 15143 | m_scenario = 0; | |||
| 15144 | m_splineFlags1 = 0; | |||
| 15145 | m_knotParam = 15; | |||
| 15146 | nknots = 0; | |||
| 15147 | ncontrol = 0; | |||
| 15148 | nfit = 0; | |||
| 15149 | tolknot = 0.0000001; | |||
| 15150 | tolcontrol = 0.0000001; | |||
| 15151 | tolfit = 0.0000001; | |||
| 15152 | knotslist.clear(); | |||
| 15153 | weightlist.clear(); | |||
| 15154 | controllist.clear(); | |||
| 15155 | fitlist.clear(); | |||
| 15156 | controlpoint.reset(); | |||
| 15157 | fitpoint.reset(); | |||
| 15158 | m_dxfDegreeSeen = false; | |||
| 15159 | m_dxfKnotCountSeen = false; | |||
| 15160 | m_dxfControlCountSeen = false; | |||
| 15161 | m_dxfFitCountSeen = false; | |||
| 15162 | } | |||
| 15163 | ||||
| 15164 | bool DRW_Spline::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){ | |||
| 15165 | resetDwgState(); | |||
| 15166 | dwgBuffer *sourceBuf = buf; | |||
| 15167 | auto fail = [this, sourceBuf]() { | |||
| 15168 | if (sourceBuf != nullptr) | |||
| 15169 | sourceBuf->invalidate(); | |||
| 15170 | resetDwgState(); | |||
| 15171 | return false; | |||
| 15172 | }; | |||
| 15173 | if (sourceBuf == nullptr) | |||
| 15174 | return fail(); | |||
| 15175 | ||||
| 15176 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 15177 | buf = &bodyProbe; | |||
| 15178 | bool ret = DRW_Entity::parseDwg(version, buf, NULL__null, bs); | |||
| 15179 | if (!ret) | |||
| 15180 | return fail(); | |||
| 15181 | if (!parseDwgSplineBody(version, buf)) | |||
| 15182 | return fail(); | |||
| 15183 | ||||
| 15184 | std::uint64_t handleEndBit = 0; | |||
| 15185 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, | |||
| 15186 | handleEndBit)) | |||
| 15187 | return fail(); | |||
| 15188 | /* Common Entity Handle Data */ | |||
| 15189 | dwgBuffer handleProbe = buf->forkIndependent(); | |||
| 15190 | ret = DRW_Entity::parseDwgEntHandle(version, &handleProbe, true, | |||
| 15191 | handleEndBit); | |||
| 15192 | if (!ret || !handleProbe.isGood()) | |||
| 15193 | return fail(); | |||
| 15194 | // RS crc; //RS */ | |||
| 15195 | *sourceBuf = handleProbe; | |||
| 15196 | return true; | |||
| 15197 | } | |||
| 15198 | ||||
| 15199 | // Spline body decode: the scenario/degree/knots/ctrl/fit section, WITHOUT | |||
| 15200 | // the leading DRW_Entity::parseDwg(common) or the trailing parseDwgEntHandle. | |||
| 15201 | // Factored out so DRW_Helix can reuse the identical spline payload before its | |||
| 15202 | // AcDbHelix trailer (Phase 8a-1). | |||
| 15203 | bool DRW_Spline::parseDwgSplineBody(DRW::Version version, dwgBuffer *buf){ | |||
| 15204 | try { | |||
| 15205 | DRW_DBG("\n***************************** parsing spline *********************************************\n")DRW_dbg::dbg("\n***************************** parsing spline *********************************************\n" ); | |||
| 15206 | if (buf == nullptr || !buf->isGood()) | |||
| 15207 | return false; | |||
| 15208 | std::uint8_t weight = 0; // RLZ ??? flags, weight, code 70, bit 4 (16) | |||
| 15209 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 15210 | std::uint64_t controlBits = 0; | |||
| 15211 | ||||
| 15212 | std::int32_t scenario = 0; | |||
| 15213 | if (!readBoundedBitLong(*buf, bodyEndBit, scenario)) | |||
| 15214 | return false; | |||
| 15215 | m_scenario = scenario; | |||
| 15216 | DRW_DBG("scenario: ")DRW_dbg::dbg("scenario: "); DRW_DBG(scenario)DRW_dbg::dbg(scenario); | |||
| 15217 | if (version > DRW::AC1024) { | |||
| 15218 | std::int32_t splFlag1 = 0; | |||
| 15219 | std::int32_t knotParam = 0; | |||
| 15220 | if (!readBoundedBitLong(*buf, bodyEndBit, splFlag1) | |||
| 15221 | || !readBoundedBitLong(*buf, bodyEndBit, knotParam)) | |||
| 15222 | return false; | |||
| 15223 | m_splineFlags1 = splFlag1; | |||
| 15224 | m_knotParam = knotParam; | |||
| 15225 | if (knotParam == kSplineKnotParamCustom || !(splFlag1 & kSplineFlagUseKnotParameter)) { | |||
| 15226 | scenario = 1; | |||
| 15227 | } else if (splFlag1 & kSplineFlagMethodFitPoints) { | |||
| 15228 | scenario = 2; | |||
| 15229 | } | |||
| 15230 | m_scenario = scenario; | |||
| 15231 | DRW_DBG(" 2013 splFlag1: ")DRW_dbg::dbg(" 2013 splFlag1: "); DRW_DBG(splFlag1)DRW_dbg::dbg(splFlag1); | |||
| 15232 | DRW_DBG(" 2013 knotParam: ")DRW_dbg::dbg(" 2013 knotParam: "); DRW_DBG(knotParam)DRW_dbg::dbg(knotParam); | |||
| 15233 | // DRW_DBG("unk bit: "); DRW_DBG(buf->getBit()); | |||
| 15234 | } | |||
| 15235 | if (!readBoundedBitLong(*buf, bodyEndBit, degree)) | |||
| 15236 | return false; | |||
| 15237 | DRW_DBG(" degree: ")DRW_dbg::dbg(" degree: "); DRW_DBG(degree)DRW_dbg::dbg(degree); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 15238 | if (!isValidSplineDegree(degree)) { | |||
| 15239 | DRW_DBG("\ndwg Spline, invalid degree ")DRW_dbg::dbg("\ndwg Spline, invalid degree "); DRW_DBG(degree)DRW_dbg::dbg(degree); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 15240 | return false; | |||
| 15241 | } | |||
| 15242 | if (scenario == 2) { | |||
| 15243 | flags = 8;//scenario 2 = not rational & planar | |||
| 15244 | if (m_splineFlags1 & kSplineFlagClosed) | |||
| 15245 | flags |= 1; | |||
| 15246 | if (!readBoundedBitDouble(*buf, bodyEndBit, tolfit) | |||
| 15247 | || !readBoundedBitCoord(*buf, bodyEndBit, tgStart) | |||
| 15248 | || !readBoundedBitCoord(*buf, bodyEndBit, tgEnd)) | |||
| 15249 | return false; | |||
| 15250 | DRW_DBG("flags: ")DRW_dbg::dbg("flags: "); DRW_DBG(flags)DRW_dbg::dbg(flags); DRW_DBG(" tolfit: ")DRW_dbg::dbg(" tolfit: "); DRW_DBG(tolfit)DRW_dbg::dbg(tolfit); | |||
| 15251 | DRW_DBG(" Start Tangent: ")DRW_dbg::dbg(" Start Tangent: "); DRW_DBGPT(tgStart.x, tgStart.y, tgStart.z)DRW_dbg::dbgPT(tgStart.x, tgStart.y, tgStart.z); | |||
| 15252 | DRW_DBG("\nEnd Tangent: ")DRW_dbg::dbg("\nEnd Tangent: "); DRW_DBGPT(tgEnd.x, tgEnd.y, tgEnd.z)DRW_dbg::dbgPT(tgEnd.x, tgEnd.y, tgEnd.z); | |||
| 15253 | std::uint32_t parsedFitCount = 0; | |||
| 15254 | if (!readTableBodyCount(version, buf, objSize, kMaxSplineItems, 6, | |||
| 15255 | parsedFitCount)) { | |||
| 15256 | return false; | |||
| 15257 | } | |||
| 15258 | nfit = static_cast<std::int32_t>(parsedFitCount); | |||
| 15259 | if (!isValidFitSplineLayout(degree, nfit)) { | |||
| 15260 | DRW_DBG("\ndwg Spline, invalid fit layout degree/count: ")DRW_dbg::dbg("\ndwg Spline, invalid fit layout degree/count: " ); | |||
| 15261 | DRW_DBG(degree)DRW_dbg::dbg(degree); DRW_DBG("/")DRW_dbg::dbg("/"); DRW_DBG(nfit)DRW_dbg::dbg(nfit); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 15262 | return false; | |||
| 15263 | } | |||
| 15264 | DRW_DBG("\nnumber of fit points: ")DRW_dbg::dbg("\nnumber of fit points: "); DRW_DBG(nfit)DRW_dbg::dbg(nfit); | |||
| 15265 | } else if (scenario == 1) { | |||
| 15266 | flags = 8;//scenario 1 = rational & planar | |||
| 15267 | bool rational = false; | |||
| 15268 | bool closed = false; | |||
| 15269 | bool periodic = false; | |||
| 15270 | if (!readBoundedBit(*buf, bodyEndBit, rational) | |||
| 15271 | || !readBoundedBit(*buf, bodyEndBit, closed) | |||
| 15272 | || !readBoundedBit(*buf, bodyEndBit, periodic) | |||
| 15273 | || !readBoundedBitDouble(*buf, bodyEndBit, tolknot) | |||
| 15274 | || !readBoundedBitDouble(*buf, bodyEndBit, tolcontrol)) | |||
| 15275 | return false; | |||
| 15276 | flags |= rational ? 4 : 0; | |||
| 15277 | flags |= closed ? 1 : 0; | |||
| 15278 | flags |= periodic ? 2 : 0; | |||
| 15279 | DRW_DBG("flags: ")DRW_dbg::dbg("flags: "); DRW_DBG(flags)DRW_dbg::dbg(flags); DRW_DBG(" knot tolerance: ")DRW_dbg::dbg(" knot tolerance: "); DRW_DBG(tolknot)DRW_dbg::dbg(tolknot); | |||
| 15280 | DRW_DBG(" control point tolerance: ")DRW_dbg::dbg(" control point tolerance: "); DRW_DBG(tolcontrol)DRW_dbg::dbg(tolcontrol); | |||
| 15281 | std::uint32_t parsedKnotCount = 0; | |||
| 15282 | if (!readTableBodyCount(version, buf, objSize, kMaxSplineItems, 2, | |||
| 15283 | parsedKnotCount)) { | |||
| 15284 | return false; | |||
| 15285 | } | |||
| 15286 | nknots = static_cast<std::int32_t>(parsedKnotCount); | |||
| 15287 | std::uint32_t parsedControlCount = 0; | |||
| 15288 | if (!readTableBodyCount(version, buf, objSize, kMaxSplineItems, 6, | |||
| 15289 | parsedControlCount)) { | |||
| 15290 | return false; | |||
| 15291 | } | |||
| 15292 | ncontrol = static_cast<std::int32_t>(parsedControlCount); | |||
| 15293 | if (!isValidControlSplineLayout(degree, nknots, ncontrol)) { | |||
| 15294 | DRW_DBG("\ndwg Spline, invalid control layout degree/knots/control: ")DRW_dbg::dbg("\ndwg Spline, invalid control layout degree/knots/control: " ); | |||
| 15295 | DRW_DBG(degree)DRW_dbg::dbg(degree); DRW_DBG("/")DRW_dbg::dbg("/"); DRW_DBG(nknots)DRW_dbg::dbg(nknots); DRW_DBG("/")DRW_dbg::dbg("/"); | |||
| 15296 | DRW_DBG(ncontrol)DRW_dbg::dbg(ncontrol); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 15297 | return false; | |||
| 15298 | } | |||
| 15299 | bool hasWeights = false; | |||
| 15300 | if (!readBoundedBit(*buf, bodyEndBit, hasWeights)) | |||
| 15301 | return false; | |||
| 15302 | weight = hasWeights ? 1 : 0; // flags bit 4: weights present (code 70) | |||
| 15303 | if (weight) flags |= 0x10; | |||
| 15304 | if (!dwgSafety::multiply(static_cast<std::uint64_t>(ncontrol), | |||
| 15305 | weight ? 8u : 6u, controlBits)) | |||
| 15306 | return false; | |||
| 15307 | if (!proxyEntityHasBits(*buf, bodyEndBit, controlBits)) { | |||
| 15308 | return false; | |||
| 15309 | } | |||
| 15310 | DRW_DBG("\nnum of knots: ")DRW_dbg::dbg("\nnum of knots: "); DRW_DBG(nknots)DRW_dbg::dbg(nknots); DRW_DBG(" num of control pt: ")DRW_dbg::dbg(" num of control pt: "); | |||
| 15311 | DRW_DBG(ncontrol)DRW_dbg::dbg(ncontrol); DRW_DBG(" weight bit: ")DRW_dbg::dbg(" weight bit: "); DRW_DBG(weight)DRW_dbg::dbg(weight); | |||
| 15312 | } else { | |||
| 15313 | DRW_DBG("\ndwg Spline, unknown scenario ")DRW_dbg::dbg("\ndwg Spline, unknown scenario "); DRW_DBG(scenario)DRW_dbg::dbg(scenario); | |||
| 15314 | DRW_DBG(" (expected 1 or 2)\n")DRW_dbg::dbg(" (expected 1 or 2)\n"); | |||
| 15315 | return false; //RLZ: from doc only 1 or 2 are ok ? | |||
| 15316 | } | |||
| 15317 | ||||
| 15318 | std::vector<double> parsedKnots; | |||
| 15319 | std::vector<double> parsedWeights; | |||
| 15320 | std::vector<std::shared_ptr<DRW_Coord>> parsedControls; | |||
| 15321 | std::vector<std::shared_ptr<DRW_Coord>> parsedFits; | |||
| 15322 | std::uint64_t knotBits = 0; | |||
| 15323 | std::uint64_t fitBits = 0; | |||
| 15324 | std::uint64_t requiredBits = 0; | |||
| 15325 | if (!dwgSafety::multiply(static_cast<std::uint64_t>(nknots), 2, | |||
| 15326 | knotBits) | |||
| 15327 | || !dwgSafety::multiply(static_cast<std::uint64_t>(nfit), 6, | |||
| 15328 | fitBits) | |||
| 15329 | || !dwgSafety::add(knotBits, controlBits, requiredBits) | |||
| 15330 | || !dwgSafety::add(requiredBits, fitBits, requiredBits) | |||
| 15331 | || !proxyEntityHasBits(*buf, bodyEndBit, requiredBits)) { | |||
| 15332 | return false; | |||
| 15333 | } | |||
| 15334 | if (!DRW::reserve(parsedKnots, nknots)) { | |||
| 15335 | return false; | |||
| 15336 | } | |||
| 15337 | for (std::int32_t i= 0; i<nknots; ++i){ | |||
| 15338 | double knot = 0.0; | |||
| 15339 | if (!readBoundedBitDouble(*buf, bodyEndBit, knot) | |||
| 15340 | || !std::isfinite(knot)) | |||
| 15341 | return false; | |||
| 15342 | parsedKnots.push_back(knot); | |||
| 15343 | } | |||
| 15344 | if (!DRW::reserve(parsedControls, ncontrol)) { | |||
| 15345 | return false; | |||
| 15346 | } | |||
| 15347 | if (weight && !DRW::reserve(parsedWeights, ncontrol)) { | |||
| 15348 | return false; | |||
| 15349 | } | |||
| 15350 | for (std::int32_t i= 0; i<ncontrol; ++i){ | |||
| 15351 | DRW_Coord control; | |||
| 15352 | if (!readBoundedBitCoord(*buf, bodyEndBit, control) | |||
| 15353 | || !std::isfinite(control.x) | |||
| 15354 | || !std::isfinite(control.y) | |||
| 15355 | || !std::isfinite(control.z)) | |||
| 15356 | return false; | |||
| 15357 | parsedControls.push_back(std::make_shared<DRW_Coord>(control)); | |||
| 15358 | if (weight) { | |||
| 15359 | //per-control-point weight; required for hyperbola/parabola | |||
| 15360 | //conic detection in consumers (e.g. LibreCAD addSpline) | |||
| 15361 | double w = 0.0; //RLZ Warning: D (BD or RD) | |||
| 15362 | if (!readBoundedBitDouble(*buf, bodyEndBit, w) | |||
| 15363 | || !std::isfinite(w)) | |||
| 15364 | return false; | |||
| 15365 | parsedWeights.push_back(w); | |||
| 15366 | DRW_DBG("\n w: ")DRW_dbg::dbg("\n w: "); DRW_DBG(w)DRW_dbg::dbg(w); | |||
| 15367 | } | |||
| 15368 | } | |||
| 15369 | if (!DRW::reserve(parsedFits, nfit)) { | |||
| 15370 | return false; | |||
| 15371 | } | |||
| 15372 | for (std::int32_t i= 0; i<nfit; ++i) { | |||
| 15373 | DRW_Coord fit; | |||
| 15374 | if (!readBoundedBitCoord(*buf, bodyEndBit, fit) | |||
| 15375 | || !std::isfinite(fit.x) | |||
| 15376 | || !std::isfinite(fit.y) | |||
| 15377 | || !std::isfinite(fit.z)) | |||
| 15378 | return false; | |||
| 15379 | parsedFits.push_back(std::make_shared<DRW_Coord>(fit)); | |||
| 15380 | } | |||
| 15381 | ||||
| 15382 | if (DRW_DBGGLDRW_dbg::getInstance()->getLevel() == DRW_dbg::Level::Debug) { | |||
| 15383 | DRW_DBG("\nknots list: ")DRW_dbg::dbg("\nknots list: "); | |||
| 15384 | for (auto const& v: parsedKnots) { | |||
| 15385 | DRW_DBG("\n")DRW_dbg::dbg("\n"); DRW_DBG(v)DRW_dbg::dbg(v); | |||
| 15386 | } | |||
| 15387 | DRW_DBG("\ncontrol point list: ")DRW_dbg::dbg("\ncontrol point list: "); | |||
| 15388 | for (auto const& v: parsedControls) { | |||
| 15389 | DRW_DBG("\n")DRW_dbg::dbg("\n"); DRW_DBGPT(v->x, v->y, v->z)DRW_dbg::dbgPT(v->x, v->y, v->z); | |||
| 15390 | } | |||
| 15391 | DRW_DBG("\nfit point list: ")DRW_dbg::dbg("\nfit point list: "); | |||
| 15392 | for (auto const& v: parsedFits) { | |||
| 15393 | DRW_DBG("\n")DRW_dbg::dbg("\n"); DRW_DBGPT(v->x, v->y, v->z)DRW_dbg::dbgPT(v->x, v->y, v->z); | |||
| 15394 | } | |||
| 15395 | } | |||
| 15396 | ||||
| 15397 | if (!buf->isGood()) | |||
| 15398 | return false; | |||
| 15399 | knotslist = std::move(parsedKnots); | |||
| 15400 | weightlist = std::move(parsedWeights); | |||
| 15401 | controllist = std::move(parsedControls); | |||
| 15402 | fitlist = std::move(parsedFits); | |||
| 15403 | return true; | |||
| 15404 | } catch (...) { | |||
| 15405 | return false; | |||
| 15406 | } | |||
| 15407 | } | |||
| 15408 | ||||
| 15409 | // AcDbHelix trailer order (libreDWG dwg2.spec:2493-2503): | |||
| 15410 | // major_version BL, maint_version BL, axis_base_pt 3BD, start_pt 3BD, | |||
| 15411 | // axis_vector 3BD, radius BD, turns BD, turn_height BD, handedness B, | |||
| 15412 | // constraint_type RC. | |||
| 15413 | void DRW_Helix::resetDwgState() { | |||
| 15414 | DRW_Spline::resetDwgState(); | |||
| 15415 | m_majorVersion = 0; | |||
| 15416 | m_maintVersion = 0; | |||
| 15417 | axisBasePt = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 15418 | startPt = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 15419 | axisVector = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 15420 | radius = 0.0; | |||
| 15421 | turns = 0.0; | |||
| 15422 | turnHeight = 0.0; | |||
| 15423 | handedness = false; | |||
| 15424 | constraintType = 0; | |||
| 15425 | m_parsingHelixSubclass = false; | |||
| 15426 | } | |||
| 15427 | ||||
| 15428 | bool DRW_Helix::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){ | |||
| 15429 | resetDwgState(); | |||
| 15430 | dwgBuffer *sourceBuf = buf; | |||
| 15431 | auto fail = [this, sourceBuf]() { | |||
| 15432 | if (sourceBuf != nullptr) | |||
| 15433 | sourceBuf->invalidate(); | |||
| 15434 | resetDwgState(); | |||
| 15435 | return false; | |||
| 15436 | }; | |||
| 15437 | if (sourceBuf == nullptr) | |||
| 15438 | return fail(); | |||
| 15439 | ||||
| 15440 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 15441 | buf = &bodyProbe; | |||
| 15442 | bool ret = DRW_Entity::parseDwg(version, buf, NULL__null, bs); | |||
| 15443 | if (!ret) | |||
| 15444 | return fail(); | |||
| 15445 | DRW_DBG("\n***************************** parsing helix *********************************************\n")DRW_dbg::dbg("\n***************************** parsing helix *********************************************\n" ); | |||
| 15446 | if (!parseDwgSplineBody(version, buf)) | |||
| 15447 | return fail(); | |||
| 15448 | ||||
| 15449 | // AcDbHelix trailer (see field order above). | |||
| 15450 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 15451 | std::int32_t parsedMajorVersion = 0; | |||
| 15452 | std::int32_t parsedMaintVersion = 0; | |||
| 15453 | DRW_Coord parsedAxisBasePt; | |||
| 15454 | DRW_Coord parsedStartPt; | |||
| 15455 | DRW_Coord parsedAxisVector; | |||
| 15456 | double parsedRadius = 0.0; | |||
| 15457 | double parsedTurns = 0.0; | |||
| 15458 | double parsedTurnHeight = 0.0; | |||
| 15459 | bool parsedHandedness = false; | |||
| 15460 | std::uint8_t parsedConstraintType = 0; | |||
| 15461 | if (!readBoundedBitLong(*buf, bodyEndBit, parsedMajorVersion) | |||
| 15462 | || !readBoundedBitLong(*buf, bodyEndBit, parsedMaintVersion) | |||
| 15463 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedAxisBasePt) | |||
| 15464 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedStartPt) | |||
| 15465 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedAxisVector) | |||
| 15466 | || !readBoundedBitDouble(*buf, bodyEndBit, parsedRadius) | |||
| 15467 | || !readBoundedBitDouble(*buf, bodyEndBit, parsedTurns) | |||
| 15468 | || !readBoundedBitDouble(*buf, bodyEndBit, parsedTurnHeight) | |||
| 15469 | || !readBoundedBit(*buf, bodyEndBit, parsedHandedness) | |||
| 15470 | || !readBoundedRawChar8(*buf, bodyEndBit, parsedConstraintType) | |||
| 15471 | || !std::isfinite(parsedAxisBasePt.x) | |||
| 15472 | || !std::isfinite(parsedAxisBasePt.y) | |||
| 15473 | || !std::isfinite(parsedAxisBasePt.z) | |||
| 15474 | || !std::isfinite(parsedStartPt.x) | |||
| 15475 | || !std::isfinite(parsedStartPt.y) | |||
| 15476 | || !std::isfinite(parsedStartPt.z) | |||
| 15477 | || !std::isfinite(parsedAxisVector.x) | |||
| 15478 | || !std::isfinite(parsedAxisVector.y) | |||
| 15479 | || !std::isfinite(parsedAxisVector.z) | |||
| 15480 | || !std::isfinite(parsedRadius) | |||
| 15481 | || !std::isfinite(parsedTurns) | |||
| 15482 | || !std::isfinite(parsedTurnHeight)) | |||
| 15483 | return fail(); | |||
| 15484 | DRW_DBG("\nhelix radius: ")DRW_dbg::dbg("\nhelix radius: "); DRW_DBG(parsedRadius)DRW_dbg::dbg(parsedRadius); DRW_DBG(" turns: ")DRW_dbg::dbg(" turns: "); DRW_DBG(parsedTurns)DRW_dbg::dbg(parsedTurns); | |||
| 15485 | ||||
| 15486 | std::uint64_t handleEndBit = 0; | |||
| 15487 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, | |||
| 15488 | handleEndBit)) | |||
| 15489 | return fail(); | |||
| 15490 | /* Common Entity Handle Data */ | |||
| 15491 | dwgBuffer handleProbe = buf->forkIndependent(); | |||
| 15492 | ret = DRW_Entity::parseDwgEntHandle(version, &handleProbe, true, | |||
| 15493 | handleEndBit); | |||
| 15494 | if (!ret || !handleProbe.isGood()) | |||
| 15495 | return fail(); | |||
| 15496 | // RS crc; //RS */ | |||
| 15497 | m_majorVersion = parsedMajorVersion; | |||
| 15498 | m_maintVersion = parsedMaintVersion; | |||
| 15499 | axisBasePt = parsedAxisBasePt; | |||
| 15500 | startPt = parsedStartPt; | |||
| 15501 | axisVector = parsedAxisVector; | |||
| 15502 | radius = parsedRadius; | |||
| 15503 | turns = parsedTurns; | |||
| 15504 | turnHeight = parsedTurnHeight; | |||
| 15505 | handedness = parsedHandedness; | |||
| 15506 | constraintType = parsedConstraintType; | |||
| 15507 | *sourceBuf = handleProbe; | |||
| 15508 | return true; | |||
| 15509 | } | |||
| 15510 | ||||
| 15511 | bool DRW_Image::parseCode(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 15512 | switch (code) { | |||
| 15513 | case 12: | |||
| 15514 | vVector.x = reader->getDouble(); | |||
| 15515 | break; | |||
| 15516 | case 22: | |||
| 15517 | vVector.y = reader->getDouble(); | |||
| 15518 | break; | |||
| 15519 | case 32: | |||
| 15520 | vVector.z = reader->getDouble(); | |||
| 15521 | break; | |||
| 15522 | case 13: | |||
| 15523 | sizeu = reader->getDouble(); | |||
| 15524 | break; | |||
| 15525 | case 23: | |||
| 15526 | sizev = reader->getDouble(); | |||
| 15527 | break; | |||
| 15528 | case 70: | |||
| 15529 | { | |||
| 15530 | int value = 0; | |||
| 15531 | if (!readDxfIntInRange(reader, 0, 0xFFFF, value)) | |||
| 15532 | return false; | |||
| 15533 | m_displayProps = value; | |||
| 15534 | } | |||
| 15535 | break; | |||
| 15536 | case 90: { | |||
| 15537 | const std::int32_t value = reader->getInt32(); | |||
| 15538 | if (value < 0 || value > kMaxClassVersion) | |||
| 15539 | return false; | |||
| 15540 | m_classVersion = value; | |||
| 15541 | break; | |||
| 15542 | } | |||
| 15543 | case 340: | |||
| 15544 | ref = reader->getHandleString(); | |||
| 15545 | break; | |||
| 15546 | case 360: | |||
| 15547 | m_imageDefReactorHandle = reader->getHandleString(); | |||
| 15548 | break; | |||
| 15549 | case 280: | |||
| 15550 | { | |||
| 15551 | int value = 0; | |||
| 15552 | if (!readDxfIntInRange(reader, 0, 1, value)) | |||
| 15553 | return false; | |||
| 15554 | clip = value; | |||
| 15555 | } | |||
| 15556 | break; | |||
| 15557 | case 281: | |||
| 15558 | { | |||
| 15559 | int value = 0; | |||
| 15560 | if (!readDxfIntInRange(reader, 0, 100, value)) | |||
| 15561 | return false; | |||
| 15562 | brightness = value; | |||
| 15563 | } | |||
| 15564 | break; | |||
| 15565 | case 282: | |||
| 15566 | { | |||
| 15567 | int value = 0; | |||
| 15568 | if (!readDxfIntInRange(reader, 0, 100, value)) | |||
| 15569 | return false; | |||
| 15570 | contrast = value; | |||
| 15571 | } | |||
| 15572 | break; | |||
| 15573 | case 283: | |||
| 15574 | { | |||
| 15575 | int value = 0; | |||
| 15576 | if (!readDxfIntInRange(reader, 0, 100, value)) | |||
| 15577 | return false; | |||
| 15578 | fade = value; | |||
| 15579 | } | |||
| 15580 | break; | |||
| 15581 | case 71: | |||
| 15582 | { | |||
| 15583 | int value = 0; | |||
| 15584 | if (!readDxfIntInRange(reader, 0, 2, value)) | |||
| 15585 | return false; | |||
| 15586 | m_clipBoundaryType = value; | |||
| 15587 | } | |||
| 15588 | break; | |||
| 15589 | case 91: | |||
| 15590 | // The declared count is a structural invariant: reject negative or | |||
| 15591 | // implausibly large values before reserve() can allocate unboundedly. | |||
| 15592 | { | |||
| 15593 | const std::int32_t count = reader->getInt32(); | |||
| 15594 | if (count < 0 || count > static_cast<std::int32_t>(DRW_Image::kMaxClipVertices)) | |||
| 15595 | return false; | |||
| 15596 | clipPath.clear(); | |||
| 15597 | if (!DRW::reserve(clipPath, count)) | |||
| 15598 | return false; | |||
| 15599 | m_declaredClipVertexCount = count; | |||
| 15600 | m_clipPathHasOpenVertex = false; | |||
| 15601 | } | |||
| 15602 | break; | |||
| 15603 | case 14: | |||
| 15604 | // WIPEOUT polygon vertex x — start a new vertex. Group 24 (y) follows. | |||
| 15605 | if (m_clipPathHasOpenVertex) | |||
| 15606 | return false; | |||
| 15607 | clipPath.emplace_back(reader->getDouble(), 0.0); | |||
| 15608 | m_clipPathHasOpenVertex = true; | |||
| 15609 | break; | |||
| 15610 | case 24: | |||
| 15611 | // WIPEOUT polygon vertex y — complete the most recently started vertex. | |||
| 15612 | if (!m_clipPathHasOpenVertex || clipPath.empty()) | |||
| 15613 | return false; | |||
| 15614 | clipPath.back().y = reader->getDouble(); | |||
| 15615 | m_clipPathHasOpenVertex = false; | |||
| 15616 | break; | |||
| 15617 | case 290: | |||
| 15618 | // R2010+ Clip mode (IMAGE/WIPEOUT, ODA spec §20.4.80): | |||
| 15619 | // 0 = mask outside the polygon, 1 = mask inside. | |||
| 15620 | clipMode = reader->getBool(); | |||
| 15621 | break; | |||
| 15622 | default: | |||
| 15623 | return DRW_Line::parseCode(code, reader); | |||
| 15624 | } | |||
| 15625 | ||||
| 15626 | return true; | |||
| 15627 | } | |||
| 15628 | ||||
| 15629 | bool DRW_Image::hasValidClipBoundary() const { | |||
| 15630 | if (m_clipPathHasOpenVertex | |||
| 15631 | || (m_declaredClipVertexCount >= 0 | |||
| 15632 | && static_cast<std::size_t>(m_declaredClipVertexCount) != clipPath.size())) { | |||
| 15633 | return false; | |||
| 15634 | } | |||
| 15635 | switch (m_clipBoundaryType) { | |||
| 15636 | case 0: | |||
| 15637 | return clipPath.empty(); | |||
| 15638 | case 1: | |||
| 15639 | return clipPath.size() == 2; | |||
| 15640 | case 2: | |||
| 15641 | return clipPath.size() >= 3; | |||
| 15642 | default: | |||
| 15643 | return false; | |||
| 15644 | } | |||
| 15645 | } | |||
| 15646 | ||||
| 15647 | bool DRW_Image::validatePayloadFields() const { | |||
| 15648 | const auto finite = [](const DRW_Coord& point) { | |||
| 15649 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 15650 | && std::isfinite(point.z); | |||
| 15651 | }; | |||
| 15652 | return m_classVersion >= 0 && m_classVersion <= kMaxClassVersion | |||
| 15653 | && m_displayProps >= 0 && m_displayProps <= 0xffff | |||
| 15654 | && clip >= 0 && clip <= 1 | |||
| 15655 | && brightness >= 0 && brightness <= 0xff | |||
| 15656 | && contrast >= 0 && contrast <= 0xff | |||
| 15657 | && fade >= 0 && fade <= 0xff | |||
| 15658 | && std::isfinite(sizeu) && std::isfinite(sizev) | |||
| 15659 | && finite(basePoint) && finite(secPoint) && finite(vVector) | |||
| 15660 | && clipPath.size() <= kMaxClipVertices | |||
| 15661 | && std::all_of(clipPath.cbegin(), clipPath.cend(), | |||
| 15662 | [](const DRW_Coord& point) { | |||
| 15663 | return std::isfinite(point.x) | |||
| 15664 | && std::isfinite(point.y); | |||
| 15665 | }); | |||
| 15666 | } | |||
| 15667 | ||||
| 15668 | void DRW_Image::resetDwgState() { | |||
| 15669 | DRW_Line::resetDwgState(); | |||
| 15670 | m_classVersion = 0; | |||
| 15671 | ref = 0; | |||
| 15672 | m_imageDefReactorHandle = 0; | |||
| 15673 | m_displayProps = 0; | |||
| 15674 | vVector = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 15675 | sizeu = 0.0; | |||
| 15676 | sizev = 0.0; | |||
| 15677 | dz = 0.0; | |||
| 15678 | clip = 0; | |||
| 15679 | brightness = 50; | |||
| 15680 | contrast = 50; | |||
| 15681 | fade = 0; | |||
| 15682 | m_clipBoundaryType = 0; | |||
| 15683 | clipPath.clear(); | |||
| 15684 | clipMode = false; | |||
| 15685 | m_declaredClipVertexCount = -1; | |||
| 15686 | m_clipPathHasOpenVertex = false; | |||
| 15687 | } | |||
| 15688 | ||||
| 15689 | bool DRW_Image::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){ | |||
| 15690 | resetDwgState(); | |||
| 15691 | dwgBuffer *sourceBuf = buf; | |||
| 15692 | auto fail = [this, sourceBuf]() { | |||
| 15693 | if (sourceBuf != nullptr) | |||
| 15694 | sourceBuf->invalidate(); | |||
| 15695 | resetDwgState(); | |||
| 15696 | return false; | |||
| 15697 | }; | |||
| 15698 | if (sourceBuf == nullptr) | |||
| 15699 | return fail(); | |||
| 15700 | ||||
| 15701 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 15702 | buf = &bodyProbe; | |||
| 15703 | dwgBuffer sBuff = buf->forkIndependent(); | |||
| 15704 | dwgBuffer *sBuf = buf; | |||
| 15705 | if (version > DRW::AC1018) {//2007+ | |||
| 15706 | sBuf = &sBuff; //separate buffer for strings | |||
| 15707 | } | |||
| 15708 | bool ret = DRW_Entity::parseDwg(version, buf, sBuf, bs); | |||
| 15709 | if (!ret) | |||
| 15710 | return fail(); | |||
| 15711 | DRW_DBG("\n***************************** parsing image *********************************************\n")DRW_dbg::dbg("\n***************************** parsing image *********************************************\n" ); | |||
| 15712 | ||||
| 15713 | const auto finite = [](const DRW_Coord& point) { | |||
| 15714 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 15715 | && std::isfinite(point.z); | |||
| 15716 | }; | |||
| 15717 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 15718 | std::int32_t parsedClassVersion = 0; | |||
| 15719 | DRW_Coord parsedBasePoint; | |||
| 15720 | DRW_Coord parsedSecPoint; | |||
| 15721 | DRW_Coord parsedVVector; | |||
| 15722 | double parsedSizeU = 0.0; | |||
| 15723 | double parsedSizeV = 0.0; | |||
| 15724 | std::uint16_t parsedDisplayProps = 0; | |||
| 15725 | bool parsedClip = false; | |||
| 15726 | std::uint8_t parsedBrightness = 0; | |||
| 15727 | std::uint8_t parsedContrast = 0; | |||
| 15728 | std::uint8_t parsedFade = 0; | |||
| 15729 | bool parsedClipMode = false; | |||
| 15730 | if (!readBoundedBitLong(*buf, bodyEndBit, parsedClassVersion) | |||
| 15731 | || parsedClassVersion < 0 || parsedClassVersion > kMaxClassVersion | |||
| 15732 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedBasePoint) | |||
| 15733 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedSecPoint) | |||
| 15734 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedVVector) | |||
| 15735 | || !readBoundedRawDouble(*buf, bodyEndBit, parsedSizeU) | |||
| 15736 | || !readBoundedRawDouble(*buf, bodyEndBit, parsedSizeV) | |||
| 15737 | || !readBoundedBitShort(*buf, bodyEndBit, parsedDisplayProps) | |||
| 15738 | || !readBoundedBit(*buf, bodyEndBit, parsedClip) | |||
| 15739 | || !readBoundedRawChar8(*buf, bodyEndBit, parsedBrightness) | |||
| 15740 | || !readBoundedRawChar8(*buf, bodyEndBit, parsedContrast) | |||
| 15741 | || !readBoundedRawChar8(*buf, bodyEndBit, parsedFade) | |||
| 15742 | || (version > DRW::AC1021 | |||
| 15743 | && !readBoundedBit(*buf, bodyEndBit, parsedClipMode)) | |||
| 15744 | || !finite(parsedBasePoint) || !finite(parsedSecPoint) | |||
| 15745 | || !finite(parsedVVector) || !std::isfinite(parsedSizeU) | |||
| 15746 | || !std::isfinite(parsedSizeV)) | |||
| 15747 | return fail(); | |||
| 15748 | DRW_DBG("class Version: ")DRW_dbg::dbg("class Version: "); DRW_DBG(parsedClassVersion)DRW_dbg::dbg(parsedClassVersion); | |||
| 15749 | DRW_DBG("\nbase point: ")DRW_dbg::dbg("\nbase point: "); DRW_DBGPT(parsedBasePoint.x, parsedBasePoint.y, parsedBasePoint.z)DRW_dbg::dbgPT(parsedBasePoint.x, parsedBasePoint.y, parsedBasePoint .z); | |||
| 15750 | DRW_DBG("\nU vector: ")DRW_dbg::dbg("\nU vector: "); DRW_DBGPT(parsedSecPoint.x, parsedSecPoint.y, parsedSecPoint.z)DRW_dbg::dbgPT(parsedSecPoint.x, parsedSecPoint.y, parsedSecPoint .z); | |||
| 15751 | DRW_DBG("\nV vector: ")DRW_dbg::dbg("\nV vector: "); DRW_DBGPT(parsedVVector.x, parsedVVector.y, parsedVVector.z)DRW_dbg::dbgPT(parsedVVector.x, parsedVVector.y, parsedVVector .z); | |||
| 15752 | DRW_DBG("\nsize U: ")DRW_dbg::dbg("\nsize U: "); DRW_DBG(parsedSizeU)DRW_dbg::dbg(parsedSizeU); DRW_DBG("\nsize V: ")DRW_dbg::dbg("\nsize V: "); DRW_DBG(parsedSizeV)DRW_dbg::dbg(parsedSizeV); | |||
| 15753 | DRW_DBG("\ndisplay props: ")DRW_dbg::dbg("\ndisplay props: "); DRW_DBG(parsedDisplayProps)DRW_dbg::dbg(parsedDisplayProps); | |||
| 15754 | ||||
| 15755 | std::uint16_t parsedClipBoundaryType = 0; | |||
| 15756 | if (!readBoundedBitShort(*buf, bodyEndBit, parsedClipBoundaryType)) | |||
| 15757 | return fail(); | |||
| 15758 | std::vector<DRW_Coord> parsedClipPath; | |||
| 15759 | std::int32_t parsedDeclaredClipVertexCount = -1; | |||
| 15760 | if (parsedClipBoundaryType == 0) { | |||
| 15761 | // No clip boundary payload. | |||
| 15762 | } else if (parsedClipBoundaryType == 1){ | |||
| 15763 | // Rectangles are encoded as exactly two opposite corners. Keep that | |||
| 15764 | // canonical payload intact; rendering expands it independently. | |||
| 15765 | DRW_Coord ll; | |||
| 15766 | DRW_Coord ur; | |||
| 15767 | if (!readBoundedRawDouble(*buf, bodyEndBit, ll.x) | |||
| 15768 | || !readBoundedRawDouble(*buf, bodyEndBit, ll.y) | |||
| 15769 | || !readBoundedRawDouble(*buf, bodyEndBit, ur.x) | |||
| 15770 | || !readBoundedRawDouble(*buf, bodyEndBit, ur.y) | |||
| 15771 | || !finite(ll) || !finite(ur)) | |||
| 15772 | return fail(); | |||
| 15773 | parsedClipPath.push_back(ll); | |||
| 15774 | parsedClipPath.push_back(ur); | |||
| 15775 | parsedDeclaredClipVertexCount = 2; | |||
| 15776 | } else if (parsedClipBoundaryType == 2) { | |||
| 15777 | std::uint32_t numVerts = 0; | |||
| 15778 | if (!readTableBodyCount(version, buf, objSize, | |||
| 15779 | static_cast<std::uint32_t>(kMaxClipVertices), | |||
| 15780 | 128, numVerts)) | |||
| 15781 | return fail(); | |||
| 15782 | std::uint64_t vertexBits = 0; | |||
| 15783 | if (!dwgSafety::multiply(static_cast<std::uint64_t>(numVerts), 128, | |||
| 15784 | vertexBits) | |||
| 15785 | || !proxyEntityHasBits(*buf, bodyEndBit, vertexBits) | |||
| 15786 | || !DRW::reserve(parsedClipPath, numVerts)) | |||
| 15787 | return fail(); | |||
| 15788 | for (std::uint32_t i = 0; i < numVerts; ++i) { | |||
| 15789 | DRW_Coord point; | |||
| 15790 | if (!readBoundedRawDouble(*buf, bodyEndBit, point.x) | |||
| 15791 | || !readBoundedRawDouble(*buf, bodyEndBit, point.y) | |||
| 15792 | || !finite(point)) | |||
| 15793 | return fail(); | |||
| 15794 | parsedClipPath.push_back(point); | |||
| 15795 | } | |||
| 15796 | parsedDeclaredClipVertexCount = static_cast<std::int32_t>(numVerts); | |||
| 15797 | } else { | |||
| 15798 | DRW_DBG("unsupported image clip type: ")DRW_dbg::dbg("unsupported image clip type: "); DRW_DBG(parsedClipBoundaryType)DRW_dbg::dbg(parsedClipBoundaryType); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 15799 | return fail(); | |||
| 15800 | } | |||
| 15801 | ||||
| 15802 | if ((parsedClipBoundaryType == 0 && !parsedClipPath.empty()) | |||
| 15803 | || (parsedClipBoundaryType == 2 && parsedClipPath.size() < 3)) | |||
| 15804 | return fail(); | |||
| 15805 | ||||
| 15806 | if (!buf->isGood()) | |||
| 15807 | return fail(); | |||
| 15808 | std::uint64_t handleEndBit = 0; | |||
| 15809 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, | |||
| 15810 | handleEndBit)) | |||
| 15811 | return fail(); | |||
| 15812 | dwgBuffer handleProbe = buf->forkIndependent(); | |||
| 15813 | ret = DRW_Entity::parseDwgEntHandle(version, &handleProbe, true, | |||
| 15814 | handleEndBit); | |||
| 15815 | if (!ret) | |||
| 15816 | return fail(); | |||
| 15817 | DRW_DBG("Remaining bytes: ")DRW_dbg::dbg("Remaining bytes: "); DRW_DBG(handleProbe.numRemainingBytes())DRW_dbg::dbg(handleProbe.numRemainingBytes()); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 15818 | ||||
| 15819 | if (!proxyEntityHasBits(handleProbe, handleEndBit, 8)) | |||
| 15820 | return fail(); | |||
| 15821 | dwgHandle biH; | |||
| 15822 | if (!readBoundedDwgHandle(handleProbe, handleEndBit, handle, false, biH)) | |||
| 15823 | return fail(); | |||
| 15824 | DRW_DBG("ImageDef Handle: ")DRW_dbg::dbg("ImageDef Handle: "); DRW_DBGHL(biH.code, biH.size, biH.ref)DRW_dbg::dbgHL(biH.code, biH.size, biH.ref); | |||
| 15825 | if (!proxyEntityHasBits(handleProbe, handleEndBit, 8)) | |||
| 15826 | return fail(); | |||
| 15827 | dwgHandle reactorH; | |||
| 15828 | if (!readBoundedDwgHandle(handleProbe, handleEndBit, handle, false, | |||
| 15829 | reactorH)) | |||
| 15830 | return fail(); | |||
| 15831 | DRW_DBG("ImageDefReactor Handle: ")DRW_dbg::dbg("ImageDefReactor Handle: "); DRW_DBGHL(reactorH.code, reactorH.size, reactorH.ref)DRW_dbg::dbgHL(reactorH.code, reactorH.size, reactorH.ref); | |||
| 15832 | DRW_DBG("Remaining bytes: ")DRW_dbg::dbg("Remaining bytes: "); DRW_DBG(handleProbe.numRemainingBytes())DRW_dbg::dbg(handleProbe.numRemainingBytes()); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 15833 | if (!handleProbe.isGood() || !sBuf->isGood()) | |||
| 15834 | return fail(); | |||
| 15835 | m_classVersion = parsedClassVersion; | |||
| 15836 | basePoint = parsedBasePoint; | |||
| 15837 | secPoint = parsedSecPoint; | |||
| 15838 | vVector = parsedVVector; | |||
| 15839 | sizeu = parsedSizeU; | |||
| 15840 | sizev = parsedSizeV; | |||
| 15841 | m_displayProps = parsedDisplayProps; | |||
| 15842 | clip = parsedClip ? 1 : 0; | |||
| 15843 | brightness = parsedBrightness; | |||
| 15844 | contrast = parsedContrast; | |||
| 15845 | fade = parsedFade; | |||
| 15846 | clipMode = parsedClipMode; | |||
| 15847 | m_clipBoundaryType = parsedClipBoundaryType; | |||
| 15848 | clipPath = std::move(parsedClipPath); | |||
| 15849 | m_declaredClipVertexCount = parsedDeclaredClipVertexCount; | |||
| 15850 | m_clipPathHasOpenVertex = false; | |||
| 15851 | *sourceBuf = handleProbe; | |||
| 15852 | ref = biH.ref; | |||
| 15853 | m_imageDefReactorHandle = reactorH.ref; | |||
| 15854 | return true; | |||
| 15855 | } | |||
| 15856 | ||||
| 15857 | // DRW_Image::encodeDwg — inverse of DRW_Image::parseDwg above (libreDWG | |||
| 15858 | // dwg.spec:5533-5563). Body field order: BL class_version, 3 x 3BD | |||
| 15859 | // (base/uvec/vvec), 2 x RD (sizeu/sizev), BS display_props, B clip, | |||
| 15860 | // 3 x RC (brightness/contrast/fade), [R2010+ B clip_mode], BS | |||
| 15861 | // clip_boundary_type + verts. Both handles (imagedef code 5 + reactor | |||
| 15862 | // code 3) are emitted UNCONDITIONALLY at the END of the handle stream, | |||
| 15863 | // matching parseDwg's order — NOT the spec's interleaved mid-stream slots. | |||
| 15864 | bool DRW_Image::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, | |||
| 15865 | dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 15866 | (void)bs; (void)strBuf; | |||
| 15867 | if (!validatePayloadFields()) { | |||
| 15868 | DRW_DBG("IMAGE has an invalid scalar or clip field\n")DRW_dbg::dbg("IMAGE has an invalid scalar or clip field\n"); | |||
| 15869 | return false; | |||
| 15870 | } | |||
| 15871 | // Callers sometimes populate clipPath without setting m_clipBoundaryType | |||
| 15872 | // (DXF import historically stored only the vertices). Infer a coherent type | |||
| 15873 | // so encode does not reject a well-formed polygon/rectangle path. | |||
| 15874 | if (m_clipBoundaryType == 0 && !clipPath.empty()) { | |||
| 15875 | if (clipPath.size() == 2) | |||
| 15876 | m_clipBoundaryType = 1; | |||
| 15877 | else if (clipPath.size() >= 3) | |||
| 15878 | m_clipBoundaryType = 2; | |||
| 15879 | } | |||
| 15880 | if (!hasValidClipBoundary()) { | |||
| 15881 | DRW_DBG("IMAGE has invalid clip boundary\n")DRW_dbg::dbg("IMAGE has invalid clip boundary\n"); | |||
| 15882 | return false; | |||
| 15883 | } | |||
| 15884 | oType = 101; // IMAGE class id — see dwgreader.cpp case 101 | |||
| 15885 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 15886 | ||||
| 15887 | buf->putBitLong(m_classVersion); | |||
| 15888 | buf->putBitDouble(basePoint.x); buf->putBitDouble(basePoint.y); buf->putBitDouble(basePoint.z); | |||
| 15889 | buf->putBitDouble(secPoint.x); buf->putBitDouble(secPoint.y); buf->putBitDouble(secPoint.z); // uvec | |||
| 15890 | buf->putBitDouble(vVector.x); buf->putBitDouble(vVector.y); buf->putBitDouble(vVector.z); | |||
| 15891 | buf->putRawDouble(sizeu); | |||
| 15892 | buf->putRawDouble(sizev); | |||
| 15893 | buf->putBitShort(static_cast<std::uint16_t>(m_displayProps)); | |||
| 15894 | buf->putBit(static_cast<std::uint8_t>(clip & 1)); | |||
| 15895 | buf->putRawChar8(static_cast<std::uint8_t>(brightness)); | |||
| 15896 | buf->putRawChar8(static_cast<std::uint8_t>(contrast)); | |||
| 15897 | buf->putRawChar8(static_cast<std::uint8_t>(fade)); | |||
| 15898 | if (version > DRW::AC1021) { // 2010+ clip mode | |||
| 15899 | buf->putBit(clipMode ? 1 : 0); | |||
| 15900 | } | |||
| 15901 | if (m_clipBoundaryType == 0) { | |||
| 15902 | buf->putBitShort(0); // clip_boundary_type 0 = none | |||
| 15903 | } else if (m_clipBoundaryType == 1) { | |||
| 15904 | buf->putBitShort(1); | |||
| 15905 | buf->put2RawDouble(clipPath[0]); | |||
| 15906 | buf->put2RawDouble(clipPath[1]); | |||
| 15907 | } else { | |||
| 15908 | buf->putBitShort(2); | |||
| 15909 | buf->putBitLong(static_cast<std::int32_t>(clipPath.size())); | |||
| 15910 | for (std::size_t i = 0; i < clipPath.size(); ++i) | |||
| 15911 | buf->put2RawDouble(clipPath[i]); | |||
| 15912 | } | |||
| 15913 | ||||
| 15914 | if (!encodeDwgEntHandle(version, buf, handleBuf)) return false; | |||
| 15915 | ||||
| 15916 | // Emit both trailing handles UNCONDITIONALLY in parseDwg order: | |||
| 15917 | // imagedef (hard pointer, code 5) then imagedefreactor (hard owner, code 3). | |||
| 15918 | dwgBufferW *hb = handleBuf ? handleBuf : buf; | |||
| 15919 | auto makeHandle = [](std::uint8_t code, std::uint32_t r) { | |||
| 15920 | dwgHandle h; | |||
| 15921 | h.code = (r == 0) ? 0 : code; | |||
| 15922 | h.ref = r; | |||
| 15923 | h.size = 0; | |||
| 15924 | if (r != 0) { std::uint32_t t = r; while (t != 0) { t >>= 8; ++h.size; } } | |||
| 15925 | return h; | |||
| 15926 | }; | |||
| 15927 | hb->putHandle(makeHandle(5, ref)); // imagedef (340) | |||
| 15928 | hb->putHandle(makeHandle(3, m_imageDefReactorHandle)); // imagedefreactor (360) | |||
| 15929 | return true; | |||
| 15930 | } | |||
| 15931 | ||||
| 15932 | bool DRW_Wipeout::parseCode(int code, const std::unique_ptr<dxfReader>& reader) { | |||
| 15933 | return DRW_Image::parseCode(code, reader); | |||
| 15934 | } | |||
| 15935 | ||||
| 15936 | bool DRW_Wipeout::hasValidBoundary() const { | |||
| 15937 | return m_clipBoundaryType != 0 && hasValidClipBoundary(); | |||
| 15938 | } | |||
| 15939 | ||||
| 15940 | bool DRW_Wipeout::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs) { | |||
| 15941 | if (buf == nullptr) | |||
| 15942 | return false; | |||
| 15943 | ||||
| 15944 | // Image parsing is transactional; keep it on a second cursor because a | |||
| 15945 | // valid image payload is still invalid for WIPEOUT when it has no clip | |||
| 15946 | // boundary. The wrapper must preserve the same failure contract. | |||
| 15947 | dwgBuffer probe = buf->forkIndependent(); | |||
| 15948 | if (!DRW_Image::parseDwg(version, &probe, bs)) { | |||
| 15949 | buf->invalidate(); | |||
| 15950 | resetDwgState(); | |||
| 15951 | return false; | |||
| 15952 | } | |||
| 15953 | if (!hasValidBoundary()) { | |||
| 15954 | buf->invalidate(); | |||
| 15955 | resetDwgState(); | |||
| 15956 | return false; | |||
| 15957 | } | |||
| 15958 | *buf = probe; | |||
| 15959 | return true; | |||
| 15960 | } | |||
| 15961 | ||||
| 15962 | bool DRW_Wipeout::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, | |||
| 15963 | dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 15964 | (void)bs; (void)strBuf; | |||
| 15965 | if (!validatePayloadFields()) { | |||
| 15966 | DRW_DBG("WIPEOUT has an invalid scalar or clip field\n")DRW_dbg::dbg("WIPEOUT has an invalid scalar or clip field\n"); | |||
| 15967 | return false; | |||
| 15968 | } | |||
| 15969 | if (clipPath.size() > DRW_Image::kMaxClipVertices) { | |||
| 15970 | DRW_DBG("WIPEOUT clip vertices exceed DWG limit\n")DRW_dbg::dbg("WIPEOUT clip vertices exceed DWG limit\n"); | |||
| 15971 | return false; | |||
| 15972 | } | |||
| 15973 | if (!hasValidBoundary()) { | |||
| 15974 | DRW_DBG("WIPEOUT has invalid clip boundary\n")DRW_dbg::dbg("WIPEOUT has invalid clip boundary\n"); | |||
| 15975 | return false; | |||
| 15976 | } | |||
| 15977 | // WIPEOUT is fixed DWG entity type 1109. It is not a custom class and | |||
| 15978 | // must not depend on a file-local CLASSES ordinal. | |||
| 15979 | oType = dwgType::WIPEOUT; | |||
| 15980 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 15981 | ||||
| 15982 | buf->putBitLong(0); | |||
| 15983 | buf->putBitDouble(basePoint.x); buf->putBitDouble(basePoint.y); buf->putBitDouble(basePoint.z); | |||
| 15984 | buf->putBitDouble(secPoint.x); buf->putBitDouble(secPoint.y); buf->putBitDouble(secPoint.z); | |||
| 15985 | buf->putBitDouble(vVector.x); buf->putBitDouble(vVector.y); buf->putBitDouble(vVector.z); | |||
| 15986 | buf->putRawDouble(sizeu); | |||
| 15987 | buf->putRawDouble(sizev); | |||
| 15988 | buf->putBitShort(static_cast<std::uint16_t>(m_displayProps)); | |||
| 15989 | buf->putBit(static_cast<std::uint8_t>(clip & 1)); | |||
| 15990 | buf->putRawChar8(static_cast<std::uint8_t>(brightness)); | |||
| 15991 | buf->putRawChar8(static_cast<std::uint8_t>(contrast)); | |||
| 15992 | buf->putRawChar8(static_cast<std::uint8_t>(fade)); | |||
| 15993 | if (version > DRW::AC1021) { | |||
| 15994 | buf->putBit(clipMode ? 1 : 0); | |||
| 15995 | } | |||
| 15996 | if (m_clipBoundaryType == 1) { | |||
| 15997 | buf->putBitShort(1); | |||
| 15998 | buf->put2RawDouble(clipPath[0]); | |||
| 15999 | buf->put2RawDouble(clipPath[1]); | |||
| 16000 | } else { | |||
| 16001 | buf->putBitShort(2); | |||
| 16002 | buf->putBitLong(static_cast<std::int32_t>(clipPath.size())); | |||
| 16003 | for (std::size_t i = 0; i < clipPath.size(); ++i) | |||
| 16004 | buf->put2RawDouble(clipPath[i]); | |||
| 16005 | } | |||
| 16006 | ||||
| 16007 | if (!encodeDwgEntHandle(version, buf, handleBuf)) return false; | |||
| 16008 | ||||
| 16009 | dwgBufferW *hb = handleBuf ? handleBuf : buf; | |||
| 16010 | auto makeHandle = [](std::uint8_t code, std::uint32_t r) { | |||
| 16011 | dwgHandle h; | |||
| 16012 | h.code = (r == 0) ? 0 : code; | |||
| 16013 | h.ref = r; | |||
| 16014 | h.size = 0; | |||
| 16015 | if (r != 0) { std::uint32_t t = r; while (t != 0) { t >>= 8; ++h.size; } } | |||
| 16016 | return h; | |||
| 16017 | }; | |||
| 16018 | hb->putHandle(makeHandle(5, ref)); | |||
| 16019 | hb->putHandle(makeHandle(3, m_imageDefReactorHandle)); | |||
| 16020 | return true; | |||
| 16021 | } | |||
| 16022 | ||||
| 16023 | bool DRW_NavisworksModel::parseCode( | |||
| 16024 | int code, const std::unique_ptr<dxfReader>& reader) { | |||
| 16025 | if (code == 100) { | |||
| 16026 | const std::string subclass = reader->getString(); | |||
| 16027 | if (subclass == "AcDbNavisworksModel") | |||
| 16028 | m_dxfInBody = true; | |||
| 16029 | return true; | |||
| 16030 | } | |||
| 16031 | if (!m_dxfInBody) | |||
| 16032 | return DRW_Entity::parseCode(code, reader); | |||
| 16033 | ||||
| 16034 | switch (code) { | |||
| 16035 | case 70: { | |||
| 16036 | const std::int32_t value = reader->getInt32(); | |||
| 16037 | if (value < 0 || value > std::numeric_limits<std::uint16_t>::max()) | |||
| 16038 | return false; | |||
| 16039 | flags = static_cast<std::uint16_t>(value); | |||
| 16040 | m_dxfSawFlags = true; | |||
| 16041 | return true; | |||
| 16042 | } | |||
| 16043 | case 340: | |||
| 16044 | definitionHandle = reader->getHandleString(); | |||
| 16045 | m_dxfSawDefinition = true; | |||
| 16046 | return true; | |||
| 16047 | case 40: | |||
| 16048 | if (m_dxfTransformCount < kTransformSize) { | |||
| 16049 | transform[m_dxfTransformCount++] = reader->getDouble(); | |||
| 16050 | return true; | |||
| 16051 | } | |||
| 16052 | if (m_dxfSawUnitFactor) | |||
| 16053 | return false; | |||
| 16054 | unitFactor = reader->getDouble(); | |||
| 16055 | m_dxfSawUnitFactor = true; | |||
| 16056 | return true; | |||
| 16057 | default: | |||
| 16058 | return DRW_Entity::parseCode(code, reader); | |||
| 16059 | } | |||
| 16060 | } | |||
| 16061 | ||||
| 16062 | bool DRW_NavisworksModel::finalizeDxf() { | |||
| 16063 | return m_dxfTransformCount == kTransformSize && m_dxfSawUnitFactor | |||
| 16064 | && std::isfinite(unitFactor) | |||
| 16065 | && std::all_of(transform.begin(), transform.end(), | |||
| 16066 | [](double value) { return std::isfinite(value); }); | |||
| 16067 | } | |||
| 16068 | ||||
| 16069 | void DRW_NavisworksModel::resetDwgState() { | |||
| 16070 | DRW_Entity::reset(); | |||
| 16071 | flags = 0; | |||
| 16072 | definitionHandle = 0; | |||
| 16073 | transform = {1.0, 0.0, 0.0, 0.0, | |||
| 16074 | 0.0, 1.0, 0.0, 0.0, | |||
| 16075 | 0.0, 0.0, 1.0, 0.0, | |||
| 16076 | 0.0, 0.0, 0.0, 1.0}; | |||
| 16077 | unitFactor = 1.0; | |||
| 16078 | } | |||
| 16079 | ||||
| 16080 | bool DRW_NavisworksModel::parseDwg(DRW::Version version, dwgBuffer *buf, | |||
| 16081 | std::uint32_t bs) { | |||
| 16082 | resetDwgState(); | |||
| 16083 | dwgBuffer *sourceBuf = buf; | |||
| 16084 | auto fail = [this, sourceBuf]() { | |||
| 16085 | if (sourceBuf != nullptr) | |||
| 16086 | sourceBuf->invalidate(); | |||
| 16087 | resetDwgState(); | |||
| 16088 | return false; | |||
| 16089 | }; | |||
| 16090 | if (sourceBuf == nullptr) | |||
| 16091 | return fail(); | |||
| 16092 | if (version < DRW::AC1015) | |||
| 16093 | return fail(); | |||
| 16094 | ||||
| 16095 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 16096 | dwgBuffer stringBuffer = bodyProbe.forkIndependent(); | |||
| 16097 | dwgBuffer *stringBuf = version > DRW::AC1018 ? &stringBuffer : &bodyProbe; | |||
| 16098 | if (!DRW_Entity::parseDwg(version, &bodyProbe, stringBuf, bs)) | |||
| 16099 | return fail(); | |||
| 16100 | ||||
| 16101 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 16102 | std::uint64_t handleEndBit = 0; | |||
| 16103 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, | |||
| 16104 | handleEndBit)) | |||
| 16105 | return fail(); | |||
| 16106 | // BS is an unsigned bit-short at the codec boundary. The flags are a | |||
| 16107 | // mask, so values with bit 15 set must survive instead of being rejected | |||
| 16108 | // through an intermediate signed conversion. | |||
| 16109 | std::uint16_t parsedFlags = 0; | |||
| 16110 | if (!readBoundedBitShort(bodyProbe, bodyEndBit, parsedFlags)) | |||
| 16111 | return fail(); | |||
| 16112 | ||||
| 16113 | std::uint32_t parsedDefinitionHandle = 0; | |||
| 16114 | if (version <= DRW::AC1018) { | |||
| 16115 | dwgHandle definition; | |||
| 16116 | if (!readBoundedDwgHandle(bodyProbe, handleEndBit, 0, false, | |||
| 16117 | definition)) | |||
| 16118 | return fail(); | |||
| 16119 | parsedDefinitionHandle = definition.ref; | |||
| 16120 | } | |||
| 16121 | ||||
| 16122 | std::array<double, 16> parsedTransform{}; | |||
| 16123 | for (double& value : parsedTransform) { | |||
| 16124 | if (!readBoundedBitDouble(bodyProbe, bodyEndBit, value)) | |||
| 16125 | return fail(); | |||
| 16126 | } | |||
| 16127 | double parsedUnitFactor = 0.0; | |||
| 16128 | if (!readBoundedBitDouble(bodyProbe, bodyEndBit, parsedUnitFactor)) | |||
| 16129 | return fail(); | |||
| 16130 | if (!std::all_of(parsedTransform.begin(), parsedTransform.end(), | |||
| 16131 | [](double value) { return std::isfinite(value); }) | |||
| 16132 | || !std::isfinite(parsedUnitFactor)) { | |||
| 16133 | return fail(); | |||
| 16134 | } | |||
| 16135 | ||||
| 16136 | if (!DRW_Entity::parseDwgEntHandle(version, &bodyProbe, true, | |||
| 16137 | handleEndBit)) | |||
| 16138 | return fail(); | |||
| 16139 | dwgBuffer handleProbe = bodyProbe.forkIndependent(); | |||
| 16140 | if (version > DRW::AC1018) { | |||
| 16141 | dwgHandle definition; | |||
| 16142 | if (!readBoundedDwgHandle(handleProbe, handleEndBit, 0, false, | |||
| 16143 | definition)) | |||
| 16144 | return fail(); | |||
| 16145 | parsedDefinitionHandle = definition.ref; | |||
| 16146 | } | |||
| 16147 | if (!handleProbe.isGood() || !stringBuf->isGood()) | |||
| 16148 | return fail(); | |||
| 16149 | flags = parsedFlags; | |||
| 16150 | transform = parsedTransform; | |||
| 16151 | unitFactor = parsedUnitFactor; | |||
| 16152 | definitionHandle = parsedDefinitionHandle; | |||
| 16153 | *sourceBuf = handleProbe; | |||
| 16154 | return true; | |||
| 16155 | } | |||
| 16156 | ||||
| 16157 | bool DRW_NavisworksModel::encodeDwg(DRW::Version version, dwgBufferW *buf, | |||
| 16158 | std::uint32_t bs, dwgBufferW *strBuf, | |||
| 16159 | dwgBufferW *handleBuf) { | |||
| 16160 | (void)bs; | |||
| 16161 | if (version < DRW::AC1015 | |||
| 16162 | || !std::isfinite(unitFactor) | |||
| 16163 | || !std::all_of(transform.begin(), transform.end(), | |||
| 16164 | [](double value) { return std::isfinite(value); })) | |||
| 16165 | return false; | |||
| 16166 | ||||
| 16167 | oType = kDwgClassNum; | |||
| 16168 | if (!encodeDwgCommon(version, buf, strBuf)) | |||
| 16169 | return false; | |||
| 16170 | ||||
| 16171 | buf->putBitShort(flags); | |||
| 16172 | dwgBufferW *hb = handleBuf ? handleBuf : buf; | |||
| 16173 | auto makeHandle = [](std::uint8_t code, std::uint32_t ref) { | |||
| 16174 | dwgHandle handle; | |||
| 16175 | handle.code = ref == 0 ? 0 : code; | |||
| 16176 | handle.ref = ref; | |||
| 16177 | handle.size = 0; | |||
| 16178 | for (std::uint32_t value = ref; value != 0; value >>= 8) | |||
| 16179 | ++handle.size; | |||
| 16180 | return handle; | |||
| 16181 | }; | |||
| 16182 | ||||
| 16183 | // AC1015/AC1018 place this entity-specific handle before the matrix in | |||
| 16184 | // the legacy data stream. AC1021+ places it after the common handles. | |||
| 16185 | if (version <= DRW::AC1018) | |||
| 16186 | buf->putHandle(makeHandle(2, definitionHandle)); | |||
| 16187 | for (double value : transform) | |||
| 16188 | buf->putBitDouble(value); | |||
| 16189 | buf->putBitDouble(unitFactor); | |||
| 16190 | ||||
| 16191 | if (!DRW_Entity::encodeDwgEntHandle(version, buf, handleBuf)) | |||
| 16192 | return false; | |||
| 16193 | if (version > DRW::AC1018) | |||
| 16194 | hb->putHandle(makeHandle(2, definitionHandle)); | |||
| 16195 | return true; | |||
| 16196 | } | |||
| 16197 | ||||
| 16198 | bool DRW_PointCloud::parseCode(int code, const std::unique_ptr<dxfReader>& reader) { | |||
| 16199 | if (code == 100) { | |||
| 16200 | m_dxfInBody = reader->getString() == "AcDbPointCloud"; | |||
| 16201 | return true; | |||
| 16202 | } | |||
| 16203 | if (!m_dxfInBody) | |||
| 16204 | return DRW_Entity::parseCode(code, reader); | |||
| 16205 | switch (code) { | |||
| 16206 | case 70: | |||
| 16207 | m_dxfSawClassVersion = true; | |||
| 16208 | classVersion = reader->getInt32(); | |||
| 16209 | break; | |||
| 16210 | case 10: origin.x = reader->getDouble(); break; | |||
| 16211 | case 20: origin.y = reader->getDouble(); break; | |||
| 16212 | case 30: origin.z = reader->getDouble(); break; | |||
| 16213 | case 1: savedFilename = reader->getUtf8String(); break; | |||
| 16214 | case 90: | |||
| 16215 | if (m_dxfSawSourceCount) | |||
| 16216 | return false; | |||
| 16217 | m_dxfSawSourceCount = true; | |||
| 16218 | sourceFileCount = reader->getInt32(); | |||
| 16219 | if (!isValidCount(sourceFileCount, | |||
| 16220 | static_cast<std::int32_t>(kMaxItems))) { | |||
| 16221 | return false; | |||
| 16222 | } | |||
| 16223 | sourceFiles.clear(); | |||
| 16224 | if (!DRW::reserve(sourceFiles, sourceFileCount)) | |||
| 16225 | return false; | |||
| 16226 | break; | |||
| 16227 | case 2: | |||
| 16228 | if (sourceFiles.size() >= static_cast<std::size_t>(sourceFileCount)) | |||
| 16229 | return false; | |||
| 16230 | sourceFiles.push_back(reader->getUtf8String()); | |||
| 16231 | break; | |||
| 16232 | case 3: ucsName = reader->getUtf8String(); break; | |||
| 16233 | case 11: extentsMin.x = reader->getDouble(); break; | |||
| 16234 | case 21: extentsMin.y = reader->getDouble(); break; | |||
| 16235 | case 31: extentsMin.z = reader->getDouble(); break; | |||
| 16236 | case 12: extentsMax.x = reader->getDouble(); break; | |||
| 16237 | case 22: extentsMax.y = reader->getDouble(); break; | |||
| 16238 | case 32: extentsMax.z = reader->getDouble(); break; | |||
| 16239 | case 92: { | |||
| 16240 | if (m_dxfSawPointCount) | |||
| 16241 | return false; | |||
| 16242 | m_dxfSawPointCount = true; | |||
| 16243 | const std::int32_t count = reader->getInt32(); | |||
| 16244 | if (count < 0) | |||
| 16245 | return false; | |||
| 16246 | pointCount = static_cast<std::uint64_t>(count); | |||
| 16247 | break; | |||
| 16248 | } | |||
| 16249 | case 13: ucsOrigin.x = reader->getDouble(); break; | |||
| 16250 | case 23: ucsOrigin.y = reader->getDouble(); break; | |||
| 16251 | case 33: ucsOrigin.z = reader->getDouble(); break; | |||
| 16252 | case 210: ucsXDirection.x = reader->getDouble(); break; | |||
| 16253 | case 220: ucsXDirection.y = reader->getDouble(); break; | |||
| 16254 | case 230: ucsXDirection.z = reader->getDouble(); break; | |||
| 16255 | case 211: ucsYDirection.x = reader->getDouble(); break; | |||
| 16256 | case 221: ucsYDirection.y = reader->getDouble(); break; | |||
| 16257 | case 231: ucsYDirection.z = reader->getDouble(); break; | |||
| 16258 | case 212: ucsZDirection.x = reader->getDouble(); break; | |||
| 16259 | case 222: ucsZDirection.y = reader->getDouble(); break; | |||
| 16260 | case 232: ucsZDirection.z = reader->getDouble(); break; | |||
| 16261 | case 330: | |||
| 16262 | if (!m_dxfInBody) | |||
| 16263 | return DRW_Entity::parseCode(code, reader); | |||
| 16264 | definitionHandle = static_cast<std::uint32_t>(reader->getHandleString()); | |||
| 16265 | break; | |||
| 16266 | case 360: reactorHandle = static_cast<std::uint32_t>(reader->getHandleString()); break; | |||
| 16267 | case 71: intensityScheme = reader->getInt32(); break; | |||
| 16268 | case 40: intensityStyle.minIntensity = reader->getDouble(); break; | |||
| 16269 | case 41: intensityStyle.maxIntensity = reader->getDouble(); break; | |||
| 16270 | case 42: intensityStyle.lowThreshold = reader->getDouble(); break; | |||
| 16271 | case 43: intensityStyle.highThreshold = reader->getDouble(); break; | |||
| 16272 | default: | |||
| 16273 | return DRW_Entity::parseCode(code, reader); | |||
| 16274 | } | |||
| 16275 | return true; | |||
| 16276 | } | |||
| 16277 | ||||
| 16278 | bool DRW_PointCloud::finalizeDxf() { | |||
| 16279 | return m_dxfSawClassVersion && m_dxfSawSourceCount && m_dxfSawPointCount | |||
| 16280 | && isValidCount(sourceFileCount, | |||
| 16281 | static_cast<std::int32_t>(kMaxItems)) | |||
| 16282 | && sourceFiles.size() == static_cast<std::size_t>(sourceFileCount); | |||
| 16283 | } | |||
| 16284 | ||||
| 16285 | void DRW_PointCloud::resetDwgState() { | |||
| 16286 | DRW_Entity::reset(); | |||
| 16287 | classVersion = 0; | |||
| 16288 | origin = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 16289 | savedFilename.clear(); | |||
| 16290 | sourceFileCount = 0; | |||
| 16291 | sourceFiles.clear(); | |||
| 16292 | extentsMin = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 16293 | extentsMax = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 16294 | pointCount = 0; | |||
| 16295 | ucsName.clear(); | |||
| 16296 | ucsOrigin = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 16297 | ucsXDirection = DRW_Coord{1.0, 0.0, 0.0}; | |||
| 16298 | ucsYDirection = DRW_Coord{0.0, 1.0, 0.0}; | |||
| 16299 | ucsZDirection = DRW_Coord{0.0, 0.0, 1.0}; | |||
| 16300 | definitionHandle = 0; | |||
| 16301 | reactorHandle = 0; | |||
| 16302 | showIntensity = false; | |||
| 16303 | intensityScheme = 0; | |||
| 16304 | intensityStyle = DRW_PointCloudIntensityStyle{}; | |||
| 16305 | showClipping = false; | |||
| 16306 | clippingCount = 0; | |||
| 16307 | clippings.clear(); | |||
| 16308 | m_dxfInBody = false; | |||
| 16309 | m_dxfSawClassVersion = false; | |||
| 16310 | m_dxfSawSourceCount = false; | |||
| 16311 | m_dxfSawPointCount = false; | |||
| 16312 | } | |||
| 16313 | ||||
| 16314 | bool DRW_PointCloud::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs) { | |||
| 16315 | resetDwgState(); | |||
| 16316 | dwgBuffer *sourceBuf = buf; | |||
| 16317 | auto fail = [this, sourceBuf]() { | |||
| 16318 | if (sourceBuf != nullptr) | |||
| 16319 | sourceBuf->invalidate(); | |||
| 16320 | resetDwgState(); | |||
| 16321 | return false; | |||
| 16322 | }; | |||
| 16323 | if (sourceBuf == nullptr || version <= DRW::AC1018) | |||
| 16324 | return fail(); | |||
| 16325 | ||||
| 16326 | const auto finite = [](const DRW_Coord& point) { | |||
| 16327 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 16328 | && std::isfinite(point.z); | |||
| 16329 | }; | |||
| 16330 | ||||
| 16331 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 16332 | dwgBuffer stringProbe = sourceBuf->forkIndependent(); | |||
| 16333 | if (!DRW_Entity::parseDwg(version, &bodyProbe, &stringProbe, bs)) | |||
| 16334 | return fail(); | |||
| 16335 | ||||
| 16336 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 16337 | std::uint64_t stringEndBit = bodyEndBit; | |||
| 16338 | if (version > DRW::AC1021) { | |||
| 16339 | std::uint64_t ignoredBodyEndBit = 0; | |||
| 16340 | if (!entityBodyDataEndBit(stringProbe, version, objSize, | |||
| 16341 | ignoredBodyEndBit, &stringEndBit)) | |||
| 16342 | return fail(); | |||
| 16343 | } | |||
| 16344 | std::uint16_t parsedClassVersion = 0; | |||
| 16345 | if (!readBoundedBitShort(bodyProbe, bodyEndBit, parsedClassVersion) | |||
| 16346 | || !readBoundedBitCoord(bodyProbe, bodyEndBit, origin)) | |||
| 16347 | return fail(); | |||
| 16348 | classVersion = parsedClassVersion; | |||
| 16349 | if (!finite(origin)) | |||
| 16350 | return fail(); | |||
| 16351 | if (!readBoundedVariableText(stringProbe, stringEndBit, version, | |||
| 16352 | savedFilename)) | |||
| 16353 | return fail(); | |||
| 16354 | std::uint32_t declaredSourceFiles = 0; | |||
| 16355 | if (!readTableBodyCount( | |||
| 16356 | version, &bodyProbe, objSize, | |||
| 16357 | static_cast<std::uint32_t>(kMaxItems), 2, | |||
| 16358 | declaredSourceFiles)) { | |||
| 16359 | return fail(); | |||
| 16360 | } | |||
| 16361 | sourceFileCount = static_cast<int>(declaredSourceFiles); | |||
| 16362 | sourceFiles.clear(); | |||
| 16363 | ||||
| 16364 | if (sourceFileCount == 0) { | |||
| 16365 | if (!readBoundedBitCoord(bodyProbe, bodyEndBit, extentsMin) | |||
| 16366 | || !readBoundedBitCoord(bodyProbe, bodyEndBit, extentsMax) | |||
| 16367 | || !readBoundedRawLong64(bodyProbe, bodyEndBit, pointCount)) | |||
| 16368 | return fail(); | |||
| 16369 | if (!finite(extentsMin) || !finite(extentsMax)) | |||
| 16370 | return fail(); | |||
| 16371 | if (!readBoundedVariableText(stringProbe, stringEndBit, version, | |||
| 16372 | ucsName)) | |||
| 16373 | return fail(); | |||
| 16374 | if (!readBoundedBitCoord(bodyProbe, bodyEndBit, ucsOrigin) | |||
| 16375 | || !readBoundedBitCoord(bodyProbe, bodyEndBit, ucsXDirection) | |||
| 16376 | || !readBoundedBitCoord(bodyProbe, bodyEndBit, ucsYDirection) | |||
| 16377 | || !readBoundedBitCoord(bodyProbe, bodyEndBit, ucsZDirection)) | |||
| 16378 | return fail(); | |||
| 16379 | if (!finite(ucsOrigin) || !finite(ucsXDirection) | |||
| 16380 | || !finite(ucsYDirection) || !finite(ucsZDirection)) { | |||
| 16381 | return fail(); | |||
| 16382 | } | |||
| 16383 | ||||
| 16384 | if (version > DRW::AC1024) { | |||
| 16385 | std::uint16_t parsedIntensityScheme = 0; | |||
| 16386 | if (!readBoundedBit(bodyProbe, bodyEndBit, showIntensity) | |||
| 16387 | || !readBoundedBitShort(bodyProbe, bodyEndBit, | |||
| 16388 | parsedIntensityScheme) | |||
| 16389 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, | |||
| 16390 | intensityStyle.minIntensity) | |||
| 16391 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, | |||
| 16392 | intensityStyle.maxIntensity) | |||
| 16393 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, | |||
| 16394 | intensityStyle.lowThreshold) | |||
| 16395 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, | |||
| 16396 | intensityStyle.highThreshold)) | |||
| 16397 | return fail(); | |||
| 16398 | intensityScheme = static_cast<int>(parsedIntensityScheme); | |||
| 16399 | if (!std::isfinite(intensityStyle.minIntensity) | |||
| 16400 | || !std::isfinite(intensityStyle.maxIntensity) | |||
| 16401 | || !std::isfinite(intensityStyle.lowThreshold) | |||
| 16402 | || !std::isfinite(intensityStyle.highThreshold)) { | |||
| 16403 | return fail(); | |||
| 16404 | } | |||
| 16405 | if (!readBoundedBit(bodyProbe, bodyEndBit, showClipping)) | |||
| 16406 | return fail(); | |||
| 16407 | ||||
| 16408 | std::uint32_t declaredClippings = 0; | |||
| 16409 | if (!readTableBodyCount( | |||
| 16410 | version, &bodyProbe, objSize, | |||
| 16411 | static_cast<std::uint32_t>(kMaxItems), 2, | |||
| 16412 | declaredClippings)) { | |||
| 16413 | return fail(); | |||
| 16414 | } | |||
| 16415 | clippingCount = static_cast<int>(declaredClippings); | |||
| 16416 | clippings.clear(); | |||
| 16417 | if (!DRW::reserve(clippings, clippingCount)) | |||
| 16418 | return fail(); | |||
| 16419 | for (std::int32_t i = 0; i < clippingCount; ++i) { | |||
| 16420 | DRW_PointCloudClipping clipping; | |||
| 16421 | if (!readBoundedBit(bodyProbe, bodyEndBit, | |||
| 16422 | clipping.isInverted)) | |||
| 16423 | return fail(); | |||
| 16424 | std::uint16_t clippingType = 0; | |||
| 16425 | if (!readBoundedBitShort(bodyProbe, bodyEndBit, clippingType)) | |||
| 16426 | return fail(); | |||
| 16427 | clipping.type = clippingType; | |||
| 16428 | if (clipping.type < 1 || clipping.type > 3) | |||
| 16429 | return fail(); | |||
| 16430 | std::uint32_t vertexCount = 2; | |||
| 16431 | if (clipping.type == 3 | |||
| 16432 | && !readTableBodyCount( | |||
| 16433 | version, &bodyProbe, objSize, | |||
| 16434 | static_cast<std::uint32_t>(kMaxItems), 128, | |||
| 16435 | vertexCount)) { | |||
| 16436 | return fail(); | |||
| 16437 | } | |||
| 16438 | clipping.vertexCount = static_cast<int>(vertexCount); | |||
| 16439 | if (!DRW::reserve(clipping.vertices, clipping.vertexCount)) | |||
| 16440 | return fail(); | |||
| 16441 | for (std::int32_t j = 0; j < clipping.vertexCount; ++j) { | |||
| 16442 | DRW_Coord vertex; | |||
| 16443 | if (!readBounded2RawDouble(bodyProbe, bodyEndBit, vertex)) | |||
| 16444 | return fail(); | |||
| 16445 | clipping.vertices.push_back(vertex); | |||
| 16446 | } | |||
| 16447 | if (clipping.type == 1) { | |||
| 16448 | if (!readBoundedBitDouble(bodyProbe, bodyEndBit, | |||
| 16449 | clipping.zMin) | |||
| 16450 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, | |||
| 16451 | clipping.zMax)) | |||
| 16452 | return fail(); | |||
| 16453 | } | |||
| 16454 | if (!std::all_of( | |||
| 16455 | clipping.vertices.begin(), clipping.vertices.end(), | |||
| 16456 | finite) | |||
| 16457 | || !std::isfinite(clipping.zMin) | |||
| 16458 | || !std::isfinite(clipping.zMax)) { | |||
| 16459 | return fail(); | |||
| 16460 | } | |||
| 16461 | clippings.push_back(std::move(clipping)); | |||
| 16462 | } | |||
| 16463 | } else { | |||
| 16464 | showIntensity = false; | |||
| 16465 | intensityScheme = 0; | |||
| 16466 | showClipping = false; | |||
| 16467 | clippingCount = 0; | |||
| 16468 | clippings.clear(); | |||
| 16469 | } | |||
| 16470 | } | |||
| 16471 | ||||
| 16472 | if (!DRW::reserve(sourceFiles, sourceFileCount)) | |||
| 16473 | return fail(); | |||
| 16474 | for (std::int32_t i = 0; i < sourceFileCount; ++i) { | |||
| 16475 | UTF8STRINGstd::string sourceFile; | |||
| 16476 | if (!readBoundedVariableText(stringProbe, stringEndBit, version, | |||
| 16477 | sourceFile)) | |||
| 16478 | return fail(); | |||
| 16479 | sourceFiles.push_back(std::move(sourceFile)); | |||
| 16480 | } | |||
| 16481 | ||||
| 16482 | if (!bodyProbe.isGood() || !stringProbe.isGood() | |||
| 16483 | || currentDwgBit(&bodyProbe) > bodyEndBit | |||
| 16484 | || currentDwgBit(&stringProbe) > stringEndBit) | |||
| 16485 | return fail(); | |||
| 16486 | ||||
| 16487 | std::uint64_t handleEndBit = 0; | |||
| 16488 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, | |||
| 16489 | handleEndBit)) | |||
| 16490 | return fail(); | |||
| 16491 | dwgBuffer handleProbe = bodyProbe.forkIndependent(); | |||
| 16492 | if (!DRW_Entity::parseDwgEntHandle(version, &handleProbe, true, | |||
| 16493 | handleEndBit) | |||
| 16494 | || !handleProbe.isGood()) | |||
| 16495 | return fail(); | |||
| 16496 | std::uint32_t parsedDefinitionHandle = 0; | |||
| 16497 | std::uint32_t parsedReactorHandle = 0; | |||
| 16498 | if (version > DRW::AC1024 && sourceFileCount == 0) { | |||
| 16499 | dwgHandle definition; | |||
| 16500 | dwgHandle reactor; | |||
| 16501 | if (!readBoundedDwgHandle(handleProbe, handleEndBit, 0, false, | |||
| 16502 | definition) | |||
| 16503 | || !readBoundedDwgHandle(handleProbe, handleEndBit, 0, false, | |||
| 16504 | reactor)) | |||
| 16505 | return fail(); | |||
| 16506 | parsedDefinitionHandle = definition.ref; | |||
| 16507 | parsedReactorHandle = reactor.ref; | |||
| 16508 | } | |||
| 16509 | if (!handleProbe.isGood() || !stringProbe.isGood()) | |||
| 16510 | return fail(); | |||
| 16511 | definitionHandle = parsedDefinitionHandle; | |||
| 16512 | reactorHandle = parsedReactorHandle; | |||
| 16513 | *sourceBuf = handleProbe; | |||
| 16514 | return true; | |||
| 16515 | } | |||
| 16516 | ||||
| 16517 | bool DRW_PointCloud::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, | |||
| 16518 | dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 16519 | (void)bs; | |||
| 16520 | const auto finite = [](const DRW_Coord& point) { | |||
| 16521 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 16522 | && std::isfinite(point.z); | |||
| 16523 | }; | |||
| 16524 | if (version <= DRW::AC1018 | |||
| 16525 | || classVersion > std::numeric_limits<std::uint16_t>::max() | |||
| 16526 | || sourceFileCount < 0 | |||
| 16527 | || sourceFileCount > static_cast<int>(kMaxItems) | |||
| 16528 | || sourceFiles.size() != static_cast<std::size_t>(sourceFileCount) | |||
| 16529 | || clippingCount < 0 | |||
| 16530 | || (sourceFileCount == 0 && clippings.size() > kMaxItems) | |||
| 16531 | || (sourceFileCount != 0 | |||
| 16532 | && (clippingCount != 0 || !clippings.empty() | |||
| 16533 | || showIntensity || showClipping)) | |||
| 16534 | || intensityScheme < 0 | |||
| 16535 | || intensityScheme > std::numeric_limits<std::uint16_t>::max() | |||
| 16536 | || clippings.size() != static_cast<std::size_t>(clippingCount)) { | |||
| 16537 | return false; | |||
| 16538 | } | |||
| 16539 | if (!finite(origin) || !finite(extentsMin) || !finite(extentsMax) | |||
| 16540 | || !finite(ucsOrigin) || !finite(ucsXDirection) | |||
| 16541 | || !finite(ucsYDirection) || !finite(ucsZDirection) | |||
| 16542 | || !std::isfinite(intensityStyle.minIntensity) | |||
| 16543 | || !std::isfinite(intensityStyle.maxIntensity) | |||
| 16544 | || !std::isfinite(intensityStyle.lowThreshold) | |||
| 16545 | || !std::isfinite(intensityStyle.highThreshold)) { | |||
| 16546 | return false; | |||
| 16547 | } | |||
| 16548 | for (const DRW_PointCloudClipping& clipping : clippings) { | |||
| 16549 | if (clipping.type < 1 || clipping.type > 3 | |||
| 16550 | || clipping.vertexCount < 0 | |||
| 16551 | || clipping.vertexCount > static_cast<int>(kMaxItems) | |||
| 16552 | || clipping.vertices.size() != static_cast<std::size_t>(clipping.vertexCount) | |||
| 16553 | || (clipping.type != 3 && clipping.vertexCount != 2) | |||
| 16554 | || !std::isfinite(clipping.zMin) | |||
| 16555 | || !std::isfinite(clipping.zMax)) { | |||
| 16556 | return false; | |||
| 16557 | } | |||
| 16558 | for (const DRW_Coord& vertex : clipping.vertices) { | |||
| 16559 | if (!finite(vertex)) | |||
| 16560 | return false; | |||
| 16561 | } | |||
| 16562 | } | |||
| 16563 | ||||
| 16564 | oType = kDwgClassNum; | |||
| 16565 | if (!encodeDwgCommon(version, buf, strBuf)) | |||
| 16566 | return false; | |||
| 16567 | dwgBufferW *sBuf = strBuf ? strBuf : buf; | |||
| 16568 | buf->putBitShort(static_cast<std::uint16_t>(classVersion)); | |||
| 16569 | buf->put3BitDouble(origin); | |||
| 16570 | sBuf->putVariableText(version, savedFilename); | |||
| 16571 | buf->putBitLong(sourceFileCount); | |||
| 16572 | if (sourceFileCount == 0) { | |||
| 16573 | buf->put3BitDouble(extentsMin); | |||
| 16574 | buf->put3BitDouble(extentsMax); | |||
| 16575 | buf->putRawLong64(pointCount); | |||
| 16576 | sBuf->putVariableText(version, ucsName); | |||
| 16577 | buf->put3BitDouble(ucsOrigin); | |||
| 16578 | buf->put3BitDouble(ucsXDirection); | |||
| 16579 | buf->put3BitDouble(ucsYDirection); | |||
| 16580 | buf->put3BitDouble(ucsZDirection); | |||
| 16581 | ||||
| 16582 | if (version > DRW::AC1024) { | |||
| 16583 | buf->putBit(showIntensity ? 1 : 0); | |||
| 16584 | buf->putBitShort(static_cast<std::uint16_t>(intensityScheme)); | |||
| 16585 | buf->putBitDouble(intensityStyle.minIntensity); | |||
| 16586 | buf->putBitDouble(intensityStyle.maxIntensity); | |||
| 16587 | buf->putBitDouble(intensityStyle.lowThreshold); | |||
| 16588 | buf->putBitDouble(intensityStyle.highThreshold); | |||
| 16589 | buf->putBit(showClipping ? 1 : 0); | |||
| 16590 | buf->putBitLong(clippingCount); | |||
| 16591 | for (const DRW_PointCloudClipping& clipping : clippings) { | |||
| 16592 | buf->putBit(clipping.isInverted ? 1 : 0); | |||
| 16593 | buf->putBitShort(static_cast<std::uint16_t>(clipping.type)); | |||
| 16594 | if (clipping.type == 3) | |||
| 16595 | buf->putBitLong(clipping.vertexCount); | |||
| 16596 | for (const DRW_Coord& vertex : clipping.vertices) | |||
| 16597 | buf->put2RawDouble(vertex); | |||
| 16598 | if (clipping.type == 1) { | |||
| 16599 | buf->putBitDouble(clipping.zMin); | |||
| 16600 | buf->putBitDouble(clipping.zMax); | |||
| 16601 | } | |||
| 16602 | } | |||
| 16603 | } | |||
| 16604 | } | |||
| 16605 | for (const UTF8STRINGstd::string& sourceFile : sourceFiles) | |||
| 16606 | sBuf->putVariableText(version, sourceFile); | |||
| 16607 | ||||
| 16608 | if (!encodeDwgEntHandle(version, buf, handleBuf)) | |||
| 16609 | return false; | |||
| 16610 | if (version > DRW::AC1024 && sourceFileCount == 0) { | |||
| 16611 | dwgBufferW *hBuf = handleBuf ? handleBuf : buf; | |||
| 16612 | auto putHandle = [hBuf](std::uint8_t code, std::uint32_t ref) { | |||
| 16613 | dwgHandle handle; | |||
| 16614 | handle.code = ref == 0 ? 0 : code; | |||
| 16615 | handle.ref = ref; | |||
| 16616 | handle.size = 0; | |||
| 16617 | for (std::uint32_t value = ref; value != 0; value >>= 8) | |||
| 16618 | ++handle.size; | |||
| 16619 | hBuf->putHandle(handle); | |||
| 16620 | }; | |||
| 16621 | putHandle(5, definitionHandle); | |||
| 16622 | putHandle(3, reactorHandle); | |||
| 16623 | } | |||
| 16624 | return true; | |||
| 16625 | } | |||
| 16626 | ||||
| 16627 | bool DRW_PointCloudEx::parseCode(int code, const std::unique_ptr<dxfReader>& reader) { | |||
| 16628 | if (code == 100) { | |||
| 16629 | m_dxfInBody = reader->getString() == "AcDbPointCloud"; | |||
| 16630 | return true; | |||
| 16631 | } | |||
| 16632 | if (!m_dxfInBody) | |||
| 16633 | return DRW_Entity::parseCode(code, reader); | |||
| 16634 | switch (code) { | |||
| 16635 | case 70: | |||
| 16636 | if (m_dxfSeen70++ != 0) return false; | |||
| 16637 | classVersion = reader->getInt32(); | |||
| 16638 | break; | |||
| 16639 | case 10: extentsMin.x = reader->getDouble(); break; | |||
| 16640 | case 20: extentsMin.y = reader->getDouble(); break; | |||
| 16641 | case 30: extentsMin.z = reader->getDouble(); break; | |||
| 16642 | case 11: extentsMax.x = reader->getDouble(); break; | |||
| 16643 | case 21: extentsMax.y = reader->getDouble(); break; | |||
| 16644 | case 31: extentsMax.z = reader->getDouble(); break; | |||
| 16645 | case 12: ucsOrigin.x = reader->getDouble(); break; | |||
| 16646 | case 22: ucsOrigin.y = reader->getDouble(); break; | |||
| 16647 | case 32: ucsOrigin.z = reader->getDouble(); break; | |||
| 16648 | case 210: ucsXDirection.x = reader->getDouble(); break; | |||
| 16649 | case 220: ucsXDirection.y = reader->getDouble(); break; | |||
| 16650 | case 230: ucsXDirection.z = reader->getDouble(); break; | |||
| 16651 | case 211: ucsYDirection.x = reader->getDouble(); break; | |||
| 16652 | case 221: ucsYDirection.y = reader->getDouble(); break; | |||
| 16653 | case 231: ucsYDirection.z = reader->getDouble(); break; | |||
| 16654 | case 212: ucsZDirection.x = reader->getDouble(); break; | |||
| 16655 | case 222: ucsZDirection.y = reader->getDouble(); break; | |||
| 16656 | case 232: ucsZDirection.z = reader->getDouble(); break; | |||
| 16657 | case 290: | |||
| 16658 | if (m_dxfHasCropping) { | |||
| 16659 | if (m_dxfSeen290 % 2 == 0) | |||
| 16660 | m_dxfCurrentCropping.isInside = reader->getBool(); | |||
| 16661 | else | |||
| 16662 | m_dxfCurrentCropping.isInverted = reader->getBool(); | |||
| 16663 | ++m_dxfSeen290; | |||
| 16664 | } else { | |||
| 16665 | if (m_dxfSeen290++ != 0) return false; | |||
| 16666 | isLocked = reader->getBool(); | |||
| 16667 | } | |||
| 16668 | break; | |||
| 16669 | case 330: | |||
| 16670 | if (!m_dxfInBody) | |||
| 16671 | return DRW_Entity::parseCode(code, reader); | |||
| 16672 | definitionHandle = static_cast<std::uint32_t>(reader->getHandleString()); | |||
| 16673 | break; | |||
| 16674 | case 360: | |||
| 16675 | reactorHandle = static_cast<std::uint32_t>(reader->getHandleString()); | |||
| 16676 | break; | |||
| 16677 | case 1: | |||
| 16678 | switch (m_dxfTextCount++) { | |||
| 16679 | case 0: name = reader->getUtf8String(); break; | |||
| 16680 | case 1: intensityColorScheme = reader->getUtf8String(); break; | |||
| 16681 | case 2: currentColorScheme = reader->getUtf8String(); break; | |||
| 16682 | case 3: classificationColorScheme = reader->getUtf8String(); break; | |||
| 16683 | default: return false; | |||
| 16684 | } | |||
| 16685 | break; | |||
| 16686 | case 291: showIntensity = reader->getBool(); break; | |||
| 16687 | case 295: showCropping = reader->getBool(); break; | |||
| 16688 | case 71: | |||
| 16689 | if (m_dxfSeen71++ == 0) | |||
| 16690 | stylizationType = reader->getInt32(); | |||
| 16691 | else if (m_dxfSeen71 == 2) | |||
| 16692 | intensityOutOfRangeBehavior = reader->getInt32(); | |||
| 16693 | else | |||
| 16694 | return false; | |||
| 16695 | break; | |||
| 16696 | case 72: elevationOutOfRangeBehavior = reader->getInt32(); break; | |||
| 16697 | case 40: | |||
| 16698 | if (m_dxfSeen40++ == 0) | |||
| 16699 | elevationMin = reader->getDouble(); | |||
| 16700 | else if (m_dxfSeen40 == 2) | |||
| 16701 | elevationMax = reader->getDouble(); | |||
| 16702 | else | |||
| 16703 | return false; | |||
| 16704 | break; | |||
| 16705 | case 41: elevationMax = reader->getDouble(); break; | |||
| 16706 | case 90: | |||
| 16707 | if (m_dxfSeen90++ != 0) return false; | |||
| 16708 | intensityMin = reader->getInt32(); | |||
| 16709 | break; | |||
| 16710 | case 91: | |||
| 16711 | if (m_dxfSeen91++ != 0) return false; | |||
| 16712 | intensityMax = reader->getInt32(); | |||
| 16713 | break; | |||
| 16714 | case 292: elevationApplyToFixedRange = reader->getBool(); break; | |||
| 16715 | case 293: intensityAsGradient = reader->getBool(); break; | |||
| 16716 | case 294: elevationAsGradient = reader->getBool(); break; | |||
| 16717 | case 92: { | |||
| 16718 | if (m_dxfSawCroppingCount) return false; | |||
| 16719 | const std::int32_t count = reader->getInt32(); | |||
| 16720 | if (!isValidCount(count, static_cast<std::int32_t>(kMaxItems))) | |||
| 16721 | return false; | |||
| 16722 | croppingCount = count; | |||
| 16723 | m_dxfSawCroppingCount = true; | |||
| 16724 | break; | |||
| 16725 | } | |||
| 16726 | case 93: | |||
| 16727 | if (m_dxfHasCropping) { | |||
| 16728 | if (m_dxfSeen93++ != 0) return false; | |||
| 16729 | m_dxfCurrentCropping.pointCount = reader->getInt32(); | |||
| 16730 | if (!isValidCount(m_dxfCurrentCropping.pointCount, | |||
| 16731 | static_cast<std::int32_t>(kMaxItems))) { | |||
| 16732 | return false; | |||
| 16733 | } | |||
| 16734 | m_dxfCurrentCropping.points.clear(); | |||
| 16735 | if (!DRW::reserve(m_dxfCurrentCropping.points, | |||
| 16736 | m_dxfCurrentCropping.pointCount)) | |||
| 16737 | return false; | |||
| 16738 | } else if (m_dxfSawCroppingCount && croppingCount == 0) { | |||
| 16739 | if (m_dxfSeen93++ == 0) | |||
| 16740 | unknownInt0 = reader->getInt32(); | |||
| 16741 | else if (m_dxfSeen93 == 2) | |||
| 16742 | unknownInt1 = reader->getInt32(); | |||
| 16743 | else | |||
| 16744 | return false; | |||
| 16745 | } else { | |||
| 16746 | return false; | |||
| 16747 | } | |||
| 16748 | break; | |||
| 16749 | case 280: | |||
| 16750 | if (!m_dxfSawCroppingCount || croppingCount == 0 | |||
| 16751 | || !finishDxfCropping()) { | |||
| 16752 | return false; | |||
| 16753 | } | |||
| 16754 | m_dxfCurrentCropping = DRW_PointCloudExCropping{}; | |||
| 16755 | m_dxfCurrentCropping.type = reader->getInt32(); | |||
| 16756 | if (m_dxfCurrentCropping.type < 0 | |||
| 16757 | || m_dxfCurrentCropping.type > std::numeric_limits<std::uint16_t>::max()) { | |||
| 16758 | return false; | |||
| 16759 | } | |||
| 16760 | m_dxfHasCropping = true; | |||
| 16761 | m_dxfSeen290 = 0; | |||
| 16762 | m_dxfSeen93 = 0; | |||
| 16763 | m_dxfDirectionComponent = 0; | |||
| 16764 | m_dxfCropPlaneComponent = 0; | |||
| 16765 | m_dxfCropPointOpen = false; | |||
| 16766 | break; | |||
| 16767 | case 13: | |||
| 16768 | case 23: | |||
| 16769 | case 33: | |||
| 16770 | if (!m_dxfHasCropping) { | |||
| 16771 | if (code == 13) ucsOrigin.x = reader->getDouble(); | |||
| 16772 | else if (code == 23) ucsOrigin.y = reader->getDouble(); | |||
| 16773 | else ucsOrigin.z = reader->getDouble(); | |||
| 16774 | } else if (m_dxfCropPlaneComponent < 3) { | |||
| 16775 | if (code == 13 && m_dxfCropPlaneComponent != 0) return false; | |||
| 16776 | if (code == 23 && m_dxfCropPlaneComponent != 1) return false; | |||
| 16777 | if (code == 33 && m_dxfCropPlaneComponent != 2) return false; | |||
| 16778 | const double value = reader->getDouble(); | |||
| 16779 | if (code == 13) m_dxfCurrentCropping.cropPlane.x = value; | |||
| 16780 | else if (code == 23) m_dxfCurrentCropping.cropPlane.y = value; | |||
| 16781 | else m_dxfCurrentCropping.cropPlane.z = value; | |||
| 16782 | ++m_dxfCropPlaneComponent; | |||
| 16783 | } else { | |||
| 16784 | if (code == 13) { | |||
| 16785 | if (m_dxfCropPointOpen) return false; | |||
| 16786 | m_dxfCropPoint = DRW_Coord{}; | |||
| 16787 | m_dxfCropPointOpen = true; | |||
| 16788 | } else if (!m_dxfCropPointOpen) { | |||
| 16789 | return false; | |||
| 16790 | } | |||
| 16791 | const double value = reader->getDouble(); | |||
| 16792 | if (code == 13) m_dxfCropPoint.x = value; | |||
| 16793 | else if (code == 23) m_dxfCropPoint.y = value; | |||
| 16794 | else m_dxfCropPoint.z = value; | |||
| 16795 | if (code == 33) { | |||
| 16796 | m_dxfCurrentCropping.points.push_back(m_dxfCropPoint); | |||
| 16797 | m_dxfCropPointOpen = false; | |||
| 16798 | } | |||
| 16799 | } | |||
| 16800 | break; | |||
| 16801 | case 213: | |||
| 16802 | case 223: | |||
| 16803 | case 233: { | |||
| 16804 | if (!m_dxfHasCropping || m_dxfDirectionComponent >= 6) | |||
| 16805 | return false; | |||
| 16806 | const double value = reader->getDouble(); | |||
| 16807 | DRW_Coord *direction = m_dxfDirectionComponent < 3 | |||
| 16808 | ? &m_dxfCurrentCropping.cropXDirection | |||
| 16809 | : &m_dxfCurrentCropping.cropYDirection; | |||
| 16810 | const int component = static_cast<int>(m_dxfDirectionComponent % 3); | |||
| 16811 | if ((component == 0 && code != 213) | |||
| 16812 | || (component == 1 && code != 223) | |||
| 16813 | || (component == 2 && code != 233)) { | |||
| 16814 | return false; | |||
| 16815 | } | |||
| 16816 | if (component == 0) direction->x = value; | |||
| 16817 | else if (component == 1) direction->y = value; | |||
| 16818 | else direction->z = value; | |||
| 16819 | ++m_dxfDirectionComponent; | |||
| 16820 | break; | |||
| 16821 | } | |||
| 16822 | default: | |||
| 16823 | return DRW_Entity::parseCode(code, reader); | |||
| 16824 | } | |||
| 16825 | return true; | |||
| 16826 | } | |||
| 16827 | ||||
| 16828 | bool DRW_PointCloudEx::finishDxfCropping() { | |||
| 16829 | if (!m_dxfHasCropping) | |||
| 16830 | return true; | |||
| 16831 | if (m_dxfSeen290 != 2 || m_dxfDirectionComponent != 6 | |||
| 16832 | || m_dxfCropPlaneComponent != 3 || m_dxfCropPointOpen | |||
| 16833 | || m_dxfSeen93 != 1 | |||
| 16834 | || m_dxfCurrentCropping.points.size() | |||
| 16835 | != static_cast<std::size_t>(m_dxfCurrentCropping.pointCount)) { | |||
| 16836 | return false; | |||
| 16837 | } | |||
| 16838 | croppings.push_back(m_dxfCurrentCropping); | |||
| 16839 | m_dxfHasCropping = false; | |||
| 16840 | return true; | |||
| 16841 | } | |||
| 16842 | ||||
| 16843 | bool DRW_PointCloudEx::finalizeDxf() { | |||
| 16844 | if (!finishDxfCropping()) | |||
| 16845 | return false; | |||
| 16846 | if (m_dxfSeen70 != 1 || !m_dxfSawCroppingCount) | |||
| 16847 | return false; | |||
| 16848 | if (croppingCount == 0) | |||
| 16849 | return m_dxfSeen93 == 2 && croppings.empty(); | |||
| 16850 | return croppings.size() == static_cast<std::size_t>(croppingCount); | |||
| 16851 | } | |||
| 16852 | ||||
| 16853 | void DRW_PointCloudEx::resetDwgState() { | |||
| 16854 | DRW_Entity::reset(); | |||
| 16855 | classVersion = 0; | |||
| 16856 | extentsMin = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 16857 | extentsMax = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 16858 | ucsOrigin = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 16859 | ucsXDirection = DRW_Coord{1.0, 0.0, 0.0}; | |||
| 16860 | ucsYDirection = DRW_Coord{0.0, 1.0, 0.0}; | |||
| 16861 | ucsZDirection = DRW_Coord{0.0, 0.0, 1.0}; | |||
| 16862 | isLocked = false; | |||
| 16863 | definitionHandle = 0; | |||
| 16864 | reactorHandle = 0; | |||
| 16865 | name.clear(); | |||
| 16866 | showIntensity = false; | |||
| 16867 | showCropping = false; | |||
| 16868 | croppingCount = 0; | |||
| 16869 | unknownInt0 = 0; | |||
| 16870 | unknownInt1 = 0; | |||
| 16871 | stylizationType = 0; | |||
| 16872 | intensityColorScheme.clear(); | |||
| 16873 | currentColorScheme.clear(); | |||
| 16874 | classificationColorScheme.clear(); | |||
| 16875 | elevationMin = 0.0; | |||
| 16876 | elevationMax = 0.0; | |||
| 16877 | intensityMin = 0.0; | |||
| 16878 | intensityMax = 0.0; | |||
| 16879 | intensityOutOfRangeBehavior = 0; | |||
| 16880 | elevationOutOfRangeBehavior = 0; | |||
| 16881 | elevationApplyToFixedRange = false; | |||
| 16882 | intensityAsGradient = false; | |||
| 16883 | elevationAsGradient = false; | |||
| 16884 | croppings.clear(); | |||
| 16885 | m_dxfCurrentCropping = DRW_PointCloudExCropping{}; | |||
| 16886 | m_dxfTextCount = 0; | |||
| 16887 | m_dxfSeen70 = 0; | |||
| 16888 | m_dxfSeen71 = 0; | |||
| 16889 | m_dxfSeen90 = 0; | |||
| 16890 | m_dxfSeen91 = 0; | |||
| 16891 | m_dxfSeen93 = 0; | |||
| 16892 | m_dxfSeen290 = 0; | |||
| 16893 | m_dxfSeen40 = 0; | |||
| 16894 | m_dxfDirectionComponent = 0; | |||
| 16895 | m_dxfCropPlaneComponent = 0; | |||
| 16896 | m_dxfSawCroppingCount = false; | |||
| 16897 | m_dxfInBody = false; | |||
| 16898 | m_dxfHasCropping = false; | |||
| 16899 | m_dxfCropPointOpen = false; | |||
| 16900 | m_dxfCropPoint = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 16901 | } | |||
| 16902 | ||||
| 16903 | bool DRW_PointCloudEx::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs) { | |||
| 16904 | resetDwgState(); | |||
| 16905 | dwgBuffer *sourceBuf = buf; | |||
| 16906 | auto fail = [this, sourceBuf]() { | |||
| 16907 | if (sourceBuf != nullptr) | |||
| 16908 | sourceBuf->invalidate(); | |||
| 16909 | resetDwgState(); | |||
| 16910 | return false; | |||
| 16911 | }; | |||
| 16912 | if (sourceBuf == nullptr || version <= DRW::AC1024) | |||
| 16913 | return fail(); | |||
| 16914 | ||||
| 16915 | const auto finite = [](const DRW_Coord& point) { | |||
| 16916 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 16917 | && std::isfinite(point.z); | |||
| 16918 | }; | |||
| 16919 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 16920 | dwgBuffer stringProbe = sourceBuf->forkIndependent(); | |||
| 16921 | if (!DRW_Entity::parseDwg(version, &bodyProbe, &stringProbe, bs)) | |||
| 16922 | return fail(); | |||
| 16923 | ||||
| 16924 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 16925 | std::uint64_t stringEndBit = bodyEndBit; | |||
| 16926 | if (version > DRW::AC1021) { | |||
| 16927 | std::uint64_t ignoredBodyEndBit = 0; | |||
| 16928 | if (!entityBodyDataEndBit(stringProbe, version, objSize, | |||
| 16929 | ignoredBodyEndBit, &stringEndBit)) | |||
| 16930 | return fail(); | |||
| 16931 | } | |||
| 16932 | std::uint16_t parsedClassVersion = 0; | |||
| 16933 | if (!readBoundedBitShort(bodyProbe, bodyEndBit, parsedClassVersion) | |||
| 16934 | || !readBoundedBitCoord(bodyProbe, bodyEndBit, extentsMin) | |||
| 16935 | || !readBoundedBitCoord(bodyProbe, bodyEndBit, extentsMax) | |||
| 16936 | || !readBoundedBitCoord(bodyProbe, bodyEndBit, ucsOrigin) | |||
| 16937 | || !readBoundedBitCoord(bodyProbe, bodyEndBit, ucsXDirection) | |||
| 16938 | || !readBoundedBitCoord(bodyProbe, bodyEndBit, ucsYDirection) | |||
| 16939 | || !readBoundedBitCoord(bodyProbe, bodyEndBit, ucsZDirection)) | |||
| 16940 | return fail(); | |||
| 16941 | classVersion = parsedClassVersion; | |||
| 16942 | if (!finite(extentsMin) || !finite(extentsMax) || !finite(ucsOrigin) | |||
| 16943 | || !finite(ucsXDirection) || !finite(ucsYDirection) | |||
| 16944 | || !finite(ucsZDirection)) { | |||
| 16945 | return fail(); | |||
| 16946 | } | |||
| 16947 | if (!readBoundedBit(bodyProbe, bodyEndBit, isLocked)) | |||
| 16948 | return fail(); | |||
| 16949 | if (!readBoundedVariableText(stringProbe, stringEndBit, version, name)) | |||
| 16950 | return fail(); | |||
| 16951 | if (!readBoundedBit(bodyProbe, bodyEndBit, showIntensity) | |||
| 16952 | || !readBoundedBit(bodyProbe, bodyEndBit, showCropping)) | |||
| 16953 | return fail(); | |||
| 16954 | std::uint32_t declaredCroppings = 0; | |||
| 16955 | if (!readTableBodyCount( | |||
| 16956 | version, &bodyProbe, objSize, | |||
| 16957 | static_cast<std::uint32_t>(kMaxItems), 24, | |||
| 16958 | declaredCroppings)) { | |||
| 16959 | return fail(); | |||
| 16960 | } | |||
| 16961 | croppingCount = static_cast<int>(declaredCroppings); | |||
| 16962 | croppings.clear(); | |||
| 16963 | if (croppingCount == 0) { | |||
| 16964 | std::uint16_t parsedStylizationType = 0; | |||
| 16965 | if (!readBoundedBitLong(bodyProbe, bodyEndBit, unknownInt0) | |||
| 16966 | || !readBoundedBitLong(bodyProbe, bodyEndBit, unknownInt1) | |||
| 16967 | || !readBoundedBitShort(bodyProbe, bodyEndBit, | |||
| 16968 | parsedStylizationType)) | |||
| 16969 | return fail(); | |||
| 16970 | stylizationType = parsedStylizationType; | |||
| 16971 | if (!readBoundedVariableText(stringProbe, stringEndBit, version, | |||
| 16972 | intensityColorScheme) | |||
| 16973 | || !readBoundedVariableText(stringProbe, stringEndBit, version, | |||
| 16974 | currentColorScheme) | |||
| 16975 | || !readBoundedVariableText(stringProbe, stringEndBit, version, | |||
| 16976 | classificationColorScheme)) | |||
| 16977 | return fail(); | |||
| 16978 | std::int32_t parsedIntensityMin = 0; | |||
| 16979 | std::int32_t parsedIntensityMax = 0; | |||
| 16980 | if (!readBoundedBitDouble(bodyProbe, bodyEndBit, elevationMin) | |||
| 16981 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, elevationMax) | |||
| 16982 | || !readBoundedBitLong(bodyProbe, bodyEndBit, parsedIntensityMin) | |||
| 16983 | || !readBoundedBitLong(bodyProbe, bodyEndBit, parsedIntensityMax)) | |||
| 16984 | return fail(); | |||
| 16985 | intensityMin = static_cast<double>(parsedIntensityMin); | |||
| 16986 | intensityMax = static_cast<double>(parsedIntensityMax); | |||
| 16987 | if (!std::isfinite(elevationMin) || !std::isfinite(elevationMax)) | |||
| 16988 | return fail(); | |||
| 16989 | std::uint16_t parsedIntensityBehavior = 0; | |||
| 16990 | std::uint16_t parsedElevationBehavior = 0; | |||
| 16991 | if (!readBoundedBitShort(bodyProbe, bodyEndBit, | |||
| 16992 | parsedIntensityBehavior) | |||
| 16993 | || !readBoundedBitShort(bodyProbe, bodyEndBit, | |||
| 16994 | parsedElevationBehavior) | |||
| 16995 | || !readBoundedBit(bodyProbe, bodyEndBit, | |||
| 16996 | elevationApplyToFixedRange) | |||
| 16997 | || !readBoundedBit(bodyProbe, bodyEndBit, intensityAsGradient) | |||
| 16998 | || !readBoundedBit(bodyProbe, bodyEndBit, elevationAsGradient)) | |||
| 16999 | return fail(); | |||
| 17000 | intensityOutOfRangeBehavior = parsedIntensityBehavior; | |||
| 17001 | elevationOutOfRangeBehavior = parsedElevationBehavior; | |||
| 17002 | } else { | |||
| 17003 | unknownInt0 = 0; | |||
| 17004 | unknownInt1 = 0; | |||
| 17005 | } | |||
| 17006 | if (!bodyProbe.isGood() || !stringProbe.isGood() | |||
| 17007 | || currentDwgBit(&bodyProbe) > bodyEndBit | |||
| 17008 | || currentDwgBit(&stringProbe) > stringEndBit) | |||
| 17009 | return fail(); | |||
| 17010 | ||||
| 17011 | if (!DRW::reserve(croppings, croppingCount)) | |||
| 17012 | return fail(); | |||
| 17013 | for (std::uint32_t i = 0; i < declaredCroppings; ++i) { | |||
| 17014 | DRW_PointCloudExCropping cropping; | |||
| 17015 | std::uint16_t croppingType = 0; | |||
| 17016 | if (!readBoundedBitShort(bodyProbe, bodyEndBit, croppingType) | |||
| 17017 | || !readBoundedBit(bodyProbe, bodyEndBit, cropping.isInside) | |||
| 17018 | || !readBoundedBit(bodyProbe, bodyEndBit, cropping.isInverted) | |||
| 17019 | || !readBoundedBitCoord(bodyProbe, bodyEndBit, | |||
| 17020 | cropping.cropPlane) | |||
| 17021 | || !readBoundedBitCoord(bodyProbe, bodyEndBit, | |||
| 17022 | cropping.cropXDirection) | |||
| 17023 | || !readBoundedBitCoord(bodyProbe, bodyEndBit, | |||
| 17024 | cropping.cropYDirection)) { | |||
| 17025 | return fail(); | |||
| 17026 | } | |||
| 17027 | cropping.type = static_cast<int>(croppingType); | |||
| 17028 | if (!finite(cropping.cropPlane) || !finite(cropping.cropXDirection) | |||
| 17029 | || !finite(cropping.cropYDirection)) { | |||
| 17030 | return fail(); | |||
| 17031 | } | |||
| 17032 | std::uint32_t declaredPoints = 0; | |||
| 17033 | if (!readTableBodyCount( | |||
| 17034 | version, &bodyProbe, objSize, | |||
| 17035 | static_cast<std::uint32_t>(kMaxItems), | |||
| 17036 | 6, declaredPoints)) { | |||
| 17037 | return fail(); | |||
| 17038 | } | |||
| 17039 | std::uint64_t pointBits = 0; | |||
| 17040 | if (!dwgSafety::multiply(declaredPoints, 6, pointBits) | |||
| 17041 | || !proxyEntityHasBits(bodyProbe, bodyEndBit, pointBits)) { | |||
| 17042 | return fail(); | |||
| 17043 | } | |||
| 17044 | cropping.pointCount = static_cast<int>(declaredPoints); | |||
| 17045 | if (!DRW::reserve(cropping.points, cropping.pointCount)) | |||
| 17046 | return fail(); | |||
| 17047 | for (std::uint32_t j = 0; j < declaredPoints; ++j) { | |||
| 17048 | DRW_Coord point; | |||
| 17049 | if (!readBoundedBitCoord(bodyProbe, bodyEndBit, point)) | |||
| 17050 | return fail(); | |||
| 17051 | cropping.points.push_back(point); | |||
| 17052 | } | |||
| 17053 | if (!std::all_of(cropping.points.begin(), cropping.points.end(), finite)) | |||
| 17054 | return fail(); | |||
| 17055 | croppings.push_back(std::move(cropping)); | |||
| 17056 | } | |||
| 17057 | ||||
| 17058 | std::uint64_t handleEndBit = 0; | |||
| 17059 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, | |||
| 17060 | handleEndBit)) | |||
| 17061 | return fail(); | |||
| 17062 | dwgBuffer handleProbe = bodyProbe.forkIndependent(); | |||
| 17063 | if (!DRW_Entity::parseDwgEntHandle(version, &handleProbe, true, | |||
| 17064 | handleEndBit) | |||
| 17065 | || !handleProbe.isGood()) | |||
| 17066 | return fail(); | |||
| 17067 | dwgHandle definition; | |||
| 17068 | dwgHandle reactor; | |||
| 17069 | if (!readBoundedDwgHandle(handleProbe, handleEndBit, 0, false, | |||
| 17070 | definition) | |||
| 17071 | || !readBoundedDwgHandle(handleProbe, handleEndBit, 0, false, | |||
| 17072 | reactor)) | |||
| 17073 | return fail(); | |||
| 17074 | const std::uint32_t parsedDefinitionHandle = definition.ref; | |||
| 17075 | const std::uint32_t parsedReactorHandle = reactor.ref; | |||
| 17076 | if (!handleProbe.isGood() || !stringProbe.isGood()) | |||
| 17077 | return fail(); | |||
| 17078 | definitionHandle = parsedDefinitionHandle; | |||
| 17079 | reactorHandle = parsedReactorHandle; | |||
| 17080 | *sourceBuf = handleProbe; | |||
| 17081 | return true; | |||
| 17082 | } | |||
| 17083 | ||||
| 17084 | bool DRW_PointCloudEx::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, | |||
| 17085 | dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 17086 | (void)bs; | |||
| 17087 | const auto finite = [](const DRW_Coord& point) { | |||
| 17088 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 17089 | && std::isfinite(point.z); | |||
| 17090 | }; | |||
| 17091 | const auto fitsUint16 = [](int value) { | |||
| 17092 | return value >= 0 | |||
| 17093 | && value <= std::numeric_limits<std::uint16_t>::max(); | |||
| 17094 | }; | |||
| 17095 | if (version <= DRW::AC1024 | |||
| 17096 | || classVersion > std::numeric_limits<std::uint16_t>::max() | |||
| 17097 | || croppingCount < 0 | |||
| 17098 | || croppingCount > static_cast<int>(kMaxItems) | |||
| 17099 | || croppings.size() != static_cast<std::size_t>(croppingCount)) { | |||
| 17100 | return false; | |||
| 17101 | } | |||
| 17102 | for (const DRW_PointCloudExCropping& cropping : croppings) { | |||
| 17103 | if (cropping.pointCount < 0 | |||
| 17104 | || cropping.pointCount > static_cast<int>(kMaxItems) | |||
| 17105 | || cropping.points.size() != static_cast<std::size_t>(cropping.pointCount)) { | |||
| 17106 | return false; | |||
| 17107 | } | |||
| 17108 | if (!fitsUint16(cropping.type) || !finite(cropping.cropPlane) | |||
| 17109 | || !finite(cropping.cropXDirection) | |||
| 17110 | || !finite(cropping.cropYDirection)) { | |||
| 17111 | return false; | |||
| 17112 | } | |||
| 17113 | for (const DRW_Coord& point : cropping.points) { | |||
| 17114 | if (!finite(point)) | |||
| 17115 | return false; | |||
| 17116 | } | |||
| 17117 | } | |||
| 17118 | if (!finite(extentsMin) || !finite(extentsMax) || !finite(ucsOrigin) | |||
| 17119 | || !finite(ucsXDirection) || !finite(ucsYDirection) | |||
| 17120 | || !finite(ucsZDirection) || !std::isfinite(elevationMin) | |||
| 17121 | || !std::isfinite(elevationMax) | |||
| 17122 | || !fitsUint16(stylizationType) | |||
| 17123 | || !fitsUint16(intensityOutOfRangeBehavior) | |||
| 17124 | || !fitsUint16(elevationOutOfRangeBehavior)) { | |||
| 17125 | return false; | |||
| 17126 | } | |||
| 17127 | const auto integral32 = [](double value) { | |||
| 17128 | return std::isfinite(value) | |||
| 17129 | && value >= static_cast<double>(std::numeric_limits<std::int32_t>::min()) | |||
| 17130 | && value <= static_cast<double>(std::numeric_limits<std::int32_t>::max()) | |||
| 17131 | && std::floor(value) == value; | |||
| 17132 | }; | |||
| 17133 | if (croppingCount == 0 | |||
| 17134 | && (!integral32(intensityMin) || !integral32(intensityMax))) { | |||
| 17135 | return false; | |||
| 17136 | } | |||
| 17137 | ||||
| 17138 | oType = kDwgClassNum; | |||
| 17139 | if (!encodeDwgCommon(version, buf, strBuf)) | |||
| 17140 | return false; | |||
| 17141 | dwgBufferW *sBuf = strBuf ? strBuf : buf; | |||
| 17142 | buf->putBitShort(static_cast<std::uint16_t>(classVersion)); | |||
| 17143 | buf->put3BitDouble(extentsMin); | |||
| 17144 | buf->put3BitDouble(extentsMax); | |||
| 17145 | buf->put3BitDouble(ucsOrigin); | |||
| 17146 | buf->put3BitDouble(ucsXDirection); | |||
| 17147 | buf->put3BitDouble(ucsYDirection); | |||
| 17148 | buf->put3BitDouble(ucsZDirection); | |||
| 17149 | buf->putBit(isLocked ? 1 : 0); | |||
| 17150 | sBuf->putVariableText(version, name); | |||
| 17151 | buf->putBit(showIntensity ? 1 : 0); | |||
| 17152 | buf->putBit(showCropping ? 1 : 0); | |||
| 17153 | buf->putBitLong(croppingCount); | |||
| 17154 | if (croppingCount == 0) { | |||
| 17155 | buf->putBitLong(unknownInt0); | |||
| 17156 | buf->putBitLong(unknownInt1); | |||
| 17157 | buf->putBitShort(static_cast<std::uint16_t>(stylizationType)); | |||
| 17158 | sBuf->putVariableText(version, intensityColorScheme); | |||
| 17159 | sBuf->putVariableText(version, currentColorScheme); | |||
| 17160 | sBuf->putVariableText(version, classificationColorScheme); | |||
| 17161 | buf->putBitDouble(elevationMin); | |||
| 17162 | buf->putBitDouble(elevationMax); | |||
| 17163 | buf->putBitLong(static_cast<std::int32_t>(intensityMin)); | |||
| 17164 | buf->putBitLong(static_cast<std::int32_t>(intensityMax)); | |||
| 17165 | buf->putBitShort(static_cast<std::uint16_t>(intensityOutOfRangeBehavior)); | |||
| 17166 | buf->putBitShort(static_cast<std::uint16_t>(elevationOutOfRangeBehavior)); | |||
| 17167 | buf->putBit(elevationApplyToFixedRange ? 1 : 0); | |||
| 17168 | buf->putBit(intensityAsGradient ? 1 : 0); | |||
| 17169 | buf->putBit(elevationAsGradient ? 1 : 0); | |||
| 17170 | } | |||
| 17171 | for (const DRW_PointCloudExCropping& cropping : croppings) { | |||
| 17172 | buf->putBitShort(static_cast<std::uint16_t>(cropping.type)); | |||
| 17173 | buf->putBit(cropping.isInside ? 1 : 0); | |||
| 17174 | buf->putBit(cropping.isInverted ? 1 : 0); | |||
| 17175 | buf->put3BitDouble(cropping.cropPlane); | |||
| 17176 | buf->put3BitDouble(cropping.cropXDirection); | |||
| 17177 | buf->put3BitDouble(cropping.cropYDirection); | |||
| 17178 | buf->putBitLong(cropping.pointCount); | |||
| 17179 | for (const DRW_Coord& point : cropping.points) | |||
| 17180 | buf->put3BitDouble(point); | |||
| 17181 | } | |||
| 17182 | if (!encodeDwgEntHandle(version, buf, handleBuf)) | |||
| 17183 | return false; | |||
| 17184 | ||||
| 17185 | dwgBufferW *hBuf = handleBuf ? handleBuf : buf; | |||
| 17186 | auto putHandle = [hBuf](std::uint8_t code, std::uint32_t ref) { | |||
| 17187 | dwgHandle handle; | |||
| 17188 | handle.code = ref == 0 ? 0 : code; | |||
| 17189 | handle.ref = ref; | |||
| 17190 | handle.size = 0; | |||
| 17191 | for (std::uint32_t value = ref; value != 0; value >>= 8) | |||
| 17192 | ++handle.size; | |||
| 17193 | hBuf->putHandle(handle); | |||
| 17194 | }; | |||
| 17195 | putHandle(5, definitionHandle); | |||
| 17196 | putHandle(3, reactorHandle); | |||
| 17197 | return true; | |||
| 17198 | } | |||
| 17199 | ||||
| 17200 | bool DRW_Surface::parseCode(int code, const std::unique_ptr<dxfReader>& reader) { | |||
| 17201 | switch (code) { | |||
| 17202 | case 1: | |||
| 17203 | case 3: | |||
| 17204 | // SURFACE ACIS payloads use text groups in the AcDbModelerGeometry | |||
| 17205 | // subclass. Keep the bytes verbatim; group 3 is a continuation of | |||
| 17206 | // the same payload and must not be interpreted as a surface field. | |||
| 17207 | if (!appendTextBytesChecked(rawAcisData, reader->getString(), | |||
| 17208 | dwgSafety::MaxBufferSize)) | |||
| 17209 | return false; | |||
| 17210 | break; | |||
| 17211 | case 70: | |||
| 17212 | modelerFormatVersion = reader->getInt32(); | |||
| 17213 | break; | |||
| 17214 | case 71: | |||
| 17215 | uIsolines = reader->getInt32(); | |||
| 17216 | break; | |||
| 17217 | case 72: | |||
| 17218 | vIsolines = reader->getInt32(); | |||
| 17219 | break; | |||
| 17220 | case 310: | |||
| 17221 | { | |||
| 17222 | std::vector<std::uint8_t> decoded; | |||
| 17223 | if (!decodeHexBytes(reader->getString(), decoded)) | |||
| 17224 | return false; | |||
| 17225 | if (!appendBytesChecked(rawAcisData, decoded, | |||
| 17226 | dwgSafety::MaxBufferSize)) | |||
| 17227 | return false; | |||
| 17228 | } | |||
| 17229 | break; | |||
| 17230 | default: | |||
| 17231 | return DRW_Entity::parseCode(code, reader); | |||
| 17232 | } | |||
| 17233 | return true; | |||
| 17234 | } | |||
| 17235 | ||||
| 17236 | bool DRW_ExtrudedSurface::parseCode( | |||
| 17237 | int code, const std::unique_ptr<dxfReader>& reader) { | |||
| 17238 | switch (code) { | |||
| 17239 | case 100: { | |||
| 17240 | const std::string marker = reader->getString(); | |||
| 17241 | if (marker == "AcDbExtrudedSurface") | |||
| 17242 | m_dxfInSubtype = true; | |||
| 17243 | else if (marker == "AcDbModelerGeometry" | |||
| 17244 | || marker == "AcDbSurface") | |||
| 17245 | m_dxfInSubtype = false; | |||
| 17246 | break; | |||
| 17247 | } | |||
| 17248 | case 90: | |||
| 17249 | { | |||
| 17250 | // The class id, then the size of the 310 data that follows. | |||
| 17251 | const std::int32_t value = reader->getInt32(); | |||
| 17252 | if (value < 0 || m_dxfDataSizeSeen) | |||
| 17253 | return false; | |||
| 17254 | if (m_dxfClassIdSeen) { | |||
| 17255 | m_dxfDataSizeSeen = true; | |||
| 17256 | break; | |||
| 17257 | } | |||
| 17258 | classId = static_cast<std::uint32_t>(value); | |||
| 17259 | m_dxfClassIdSeen = true; | |||
| 17260 | } | |||
| 17261 | break; | |||
| 17262 | case 310: | |||
| 17263 | // Extrusion data is not kept; it must not join the ACIS body. | |||
| 17264 | if (!m_dxfInSubtype) | |||
| 17265 | return DRW_Surface::parseCode(code, reader); | |||
| 17266 | break; | |||
| 17267 | case 10: | |||
| 17268 | sweepVector.x = reader->getDouble(); | |||
| 17269 | break; | |||
| 17270 | case 20: | |||
| 17271 | sweepVector.y = reader->getDouble(); | |||
| 17272 | break; | |||
| 17273 | case 30: | |||
| 17274 | sweepVector.z = reader->getDouble(); | |||
| 17275 | break; | |||
| 17276 | case 11: | |||
| 17277 | referenceVector.x = reader->getDouble(); | |||
| 17278 | break; | |||
| 17279 | case 21: | |||
| 17280 | referenceVector.y = reader->getDouble(); | |||
| 17281 | break; | |||
| 17282 | case 31: | |||
| 17283 | referenceVector.z = reader->getDouble(); | |||
| 17284 | break; | |||
| 17285 | case 40: | |||
| 17286 | if (m_dxfExtrudedTransformCount >= extrudedTransform.size()) | |||
| 17287 | return false; | |||
| 17288 | extrudedTransform[m_dxfExtrudedTransformCount++] = reader->getDouble(); | |||
| 17289 | break; | |||
| 17290 | case 41: | |||
| 17291 | // Code 41 is not part of the AcDbExtrudedSurface mapping. Keep an | |||
| 17292 | // unexpected value out of the common entity state. | |||
| 17293 | return false; | |||
| 17294 | case 42: | |||
| 17295 | if (!m_dxfInSubtype) | |||
| 17296 | return DRW_Surface::parseCode(code, reader); | |||
| 17297 | draftAngle = reader->getDouble(); | |||
| 17298 | break; | |||
| 17299 | case 43: | |||
| 17300 | draftStartDistance = reader->getDouble(); | |||
| 17301 | break; | |||
| 17302 | case 44: | |||
| 17303 | draftEndDistance = reader->getDouble(); | |||
| 17304 | break; | |||
| 17305 | case 45: | |||
| 17306 | twistAngle = reader->getDouble(); | |||
| 17307 | break; | |||
| 17308 | case 46: | |||
| 17309 | if (m_dxfSweepTransformCount >= sweepEntityTransform.size()) | |||
| 17310 | return false; | |||
| 17311 | sweepEntityTransform[m_dxfSweepTransformCount++] = reader->getDouble(); | |||
| 17312 | break; | |||
| 17313 | case 47: | |||
| 17314 | if (m_dxfPathTransformCount >= pathEntityTransform.size()) | |||
| 17315 | return false; | |||
| 17316 | pathEntityTransform[m_dxfPathTransformCount++] = reader->getDouble(); | |||
| 17317 | break; | |||
| 17318 | case 48: | |||
| 17319 | scaleFactor = reader->getDouble(); | |||
| 17320 | break; | |||
| 17321 | case 49: | |||
| 17322 | alignAngle = reader->getDouble(); | |||
| 17323 | break; | |||
| 17324 | case 70: | |||
| 17325 | if (!m_dxfInSubtype) | |||
| 17326 | return DRW_Surface::parseCode(code, reader); | |||
| 17327 | { | |||
| 17328 | const std::int32_t value = reader->getInt32(); | |||
| 17329 | if (value < 0 || value > std::numeric_limits<std::uint16_t>::max()) | |||
| 17330 | return false; | |||
| 17331 | sweepAlignmentFlags = value; | |||
| 17332 | } | |||
| 17333 | break; | |||
| 17334 | case 71: | |||
| 17335 | if (!m_dxfInSubtype) | |||
| 17336 | return DRW_Surface::parseCode(code, reader); | |||
| 17337 | { | |||
| 17338 | const std::int32_t value = reader->getInt32(); | |||
| 17339 | if (value < 0 || value > std::numeric_limits<std::uint16_t>::max()) | |||
| 17340 | return false; | |||
| 17341 | pathFlags = value; | |||
| 17342 | } | |||
| 17343 | break; | |||
| 17344 | case 290: | |||
| 17345 | solid = reader->getInt32() != 0; | |||
| 17346 | break; | |||
| 17347 | case 292: | |||
| 17348 | alignStart = reader->getInt32() != 0; | |||
| 17349 | break; | |||
| 17350 | case 293: | |||
| 17351 | bank = reader->getInt32() != 0; | |||
| 17352 | break; | |||
| 17353 | case 294: | |||
| 17354 | basePointSet = reader->getInt32() != 0; | |||
| 17355 | break; | |||
| 17356 | case 295: | |||
| 17357 | sweepEntityTransformComputed = reader->getInt32() != 0; | |||
| 17358 | break; | |||
| 17359 | case 296: | |||
| 17360 | pathEntityTransformComputed = reader->getInt32() != 0; | |||
| 17361 | break; | |||
| 17362 | default: | |||
| 17363 | return DRW_Surface::parseCode(code, reader); | |||
| 17364 | } | |||
| 17365 | return true; | |||
| 17366 | } | |||
| 17367 | ||||
| 17368 | bool DRW_ExtrudedSurface::finalizeDxf() const { | |||
| 17369 | if (!m_dxfClassIdSeen) | |||
| 17370 | return true; | |||
| 17371 | return m_dxfInSubtype | |||
| 17372 | && m_dxfExtrudedTransformCount == extrudedTransform.size() | |||
| 17373 | && m_dxfSweepTransformCount == sweepEntityTransform.size() | |||
| 17374 | && m_dxfPathTransformCount == pathEntityTransform.size(); | |||
| 17375 | } | |||
| 17376 | ||||
| 17377 | bool DRW_SweptSurface::parseCode( | |||
| 17378 | int code, const std::unique_ptr<dxfReader>& reader) { | |||
| 17379 | switch (code) { | |||
| 17380 | case 100: { | |||
| 17381 | const std::string marker = reader->getString(); | |||
| 17382 | if (marker == "AcDbSweptSurface") | |||
| 17383 | m_dxfInSubtype = true; | |||
| 17384 | else if (marker == "AcDbModelerGeometry" | |||
| 17385 | || marker == "AcDbSurface") | |||
| 17386 | m_dxfInSubtype = false; | |||
| 17387 | break; | |||
| 17388 | } | |||
| 17389 | case 90: | |||
| 17390 | if (!m_dxfInSubtype) | |||
| 17391 | return DRW_Surface::parseCode(code, reader); | |||
| 17392 | m_dxfTypedFieldSeen = true; | |||
| 17393 | { | |||
| 17394 | // Each entity id may be followed by the size of its 310 data. | |||
| 17395 | const std::int32_t value = reader->getInt32(); | |||
| 17396 | if (value < 0) | |||
| 17397 | return false; | |||
| 17398 | if (m_dxfSweepEntityIdSeen) { | |||
| 17399 | if (m_dxfDataSizeCount >= (m_dxfPathEntityIdSeen ? 2 : 1)) | |||
| 17400 | return false; | |||
| 17401 | ++m_dxfDataSizeCount; | |||
| 17402 | break; | |||
| 17403 | } | |||
| 17404 | sweepEntityId = static_cast<std::uint32_t>(value); | |||
| 17405 | m_dxfSweepEntityIdSeen = true; | |||
| 17406 | } | |||
| 17407 | break; | |||
| 17408 | case 91: | |||
| 17409 | if (!m_dxfInSubtype) | |||
| 17410 | return DRW_Surface::parseCode(code, reader); | |||
| 17411 | if (m_dxfPathEntityIdSeen) | |||
| 17412 | return false; | |||
| 17413 | m_dxfTypedFieldSeen = true; | |||
| 17414 | { | |||
| 17415 | const std::int32_t value = reader->getInt32(); | |||
| 17416 | if (value < 0) | |||
| 17417 | return false; | |||
| 17418 | pathEntityId = static_cast<std::uint32_t>(value); | |||
| 17419 | m_dxfPathEntityIdSeen = true; | |||
| 17420 | } | |||
| 17421 | break; | |||
| 17422 | case 310: { | |||
| 17423 | if (!m_dxfInSubtype) | |||
| 17424 | return DRW_Surface::parseCode(code, reader); | |||
| 17425 | m_dxfTypedFieldSeen = true; | |||
| 17426 | std::vector<std::uint8_t> decoded; | |||
| 17427 | if (!decodeHexBytes(reader->getString(), decoded)) | |||
| 17428 | return false; | |||
| 17429 | auto& destination = m_dxfPathEntityIdSeen ? pathData : sweepData; | |||
| 17430 | if (!appendBytesChecked(destination, decoded, kMaxSweepDataSize)) | |||
| 17431 | return false; | |||
| 17432 | break; | |||
| 17433 | } | |||
| 17434 | case 11: | |||
| 17435 | if (!m_dxfInSubtype) | |||
| 17436 | return DRW_Surface::parseCode(code, reader); | |||
| 17437 | m_dxfTypedFieldSeen = true; | |||
| 17438 | referenceVector.x = reader->getDouble(); | |||
| 17439 | break; | |||
| 17440 | case 21: | |||
| 17441 | if (!m_dxfInSubtype) | |||
| 17442 | return DRW_Surface::parseCode(code, reader); | |||
| 17443 | m_dxfTypedFieldSeen = true; | |||
| 17444 | referenceVector.y = reader->getDouble(); | |||
| 17445 | break; | |||
| 17446 | case 31: | |||
| 17447 | if (!m_dxfInSubtype) | |||
| 17448 | return DRW_Surface::parseCode(code, reader); | |||
| 17449 | m_dxfTypedFieldSeen = true; | |||
| 17450 | referenceVector.z = reader->getDouble(); | |||
| 17451 | break; | |||
| 17452 | case 40: | |||
| 17453 | if (!m_dxfInSubtype) | |||
| 17454 | return DRW_Surface::parseCode(code, reader); | |||
| 17455 | m_dxfTypedFieldSeen = true; | |||
| 17456 | if (m_dxfSweepTransformCount >= sweepEntityTransformed.size()) | |||
| 17457 | return false; | |||
| 17458 | sweepEntityTransformed[m_dxfSweepTransformCount++] = reader->getDouble(); | |||
| 17459 | break; | |||
| 17460 | case 41: | |||
| 17461 | if (!m_dxfInSubtype) | |||
| 17462 | return DRW_Surface::parseCode(code, reader); | |||
| 17463 | m_dxfTypedFieldSeen = true; | |||
| 17464 | if (m_dxfPathTransformCount >= pathEntityTransformed.size()) | |||
| 17465 | return false; | |||
| 17466 | pathEntityTransformed[m_dxfPathTransformCount++] = reader->getDouble(); | |||
| 17467 | break; | |||
| 17468 | case 42: | |||
| 17469 | if (!m_dxfInSubtype) | |||
| 17470 | return DRW_Surface::parseCode(code, reader); | |||
| 17471 | m_dxfTypedFieldSeen = true; | |||
| 17472 | draftAngle = reader->getDouble(); | |||
| 17473 | break; | |||
| 17474 | case 43: | |||
| 17475 | if (!m_dxfInSubtype) | |||
| 17476 | return DRW_Surface::parseCode(code, reader); | |||
| 17477 | m_dxfTypedFieldSeen = true; | |||
| 17478 | draftStartDistance = reader->getDouble(); | |||
| 17479 | break; | |||
| 17480 | case 44: | |||
| 17481 | if (!m_dxfInSubtype) | |||
| 17482 | return DRW_Surface::parseCode(code, reader); | |||
| 17483 | m_dxfTypedFieldSeen = true; | |||
| 17484 | draftEndDistance = reader->getDouble(); | |||
| 17485 | break; | |||
| 17486 | case 45: | |||
| 17487 | if (!m_dxfInSubtype) | |||
| 17488 | return DRW_Surface::parseCode(code, reader); | |||
| 17489 | m_dxfTypedFieldSeen = true; | |||
| 17490 | twistAngle = reader->getDouble(); | |||
| 17491 | break; | |||
| 17492 | case 46: | |||
| 17493 | if (!m_dxfInSubtype) | |||
| 17494 | return DRW_Surface::parseCode(code, reader); | |||
| 17495 | m_dxfTypedFieldSeen = true; | |||
| 17496 | if (m_dxfSweepEntityTransformedCount >= sweepEntityTransform.size()) | |||
| 17497 | return false; | |||
| 17498 | sweepEntityTransform[m_dxfSweepEntityTransformedCount++] = | |||
| 17499 | reader->getDouble(); | |||
| 17500 | break; | |||
| 17501 | case 47: | |||
| 17502 | if (!m_dxfInSubtype) | |||
| 17503 | return DRW_Surface::parseCode(code, reader); | |||
| 17504 | m_dxfTypedFieldSeen = true; | |||
| 17505 | if (m_dxfPathEntityTransformedCount >= pathEntityTransform.size()) | |||
| 17506 | return false; | |||
| 17507 | pathEntityTransform[m_dxfPathEntityTransformedCount++] = | |||
| 17508 | reader->getDouble(); | |||
| 17509 | break; | |||
| 17510 | case 48: | |||
| 17511 | if (!m_dxfInSubtype) | |||
| 17512 | return DRW_Surface::parseCode(code, reader); | |||
| 17513 | m_dxfTypedFieldSeen = true; | |||
| 17514 | scaleFactor = reader->getDouble(); | |||
| 17515 | break; | |||
| 17516 | case 49: | |||
| 17517 | if (!m_dxfInSubtype) | |||
| 17518 | return DRW_Surface::parseCode(code, reader); | |||
| 17519 | m_dxfTypedFieldSeen = true; | |||
| 17520 | alignAngle = reader->getDouble(); | |||
| 17521 | break; | |||
| 17522 | case 70: | |||
| 17523 | if (!m_dxfInSubtype) | |||
| 17524 | return DRW_Surface::parseCode(code, reader); | |||
| 17525 | m_dxfTypedFieldSeen = true; | |||
| 17526 | { | |||
| 17527 | const std::int32_t value = reader->getInt32(); | |||
| 17528 | if (value < 0 || value > std::numeric_limits<std::uint16_t>::max()) | |||
| 17529 | return false; | |||
| 17530 | sweepAlignmentFlags = value; | |||
| 17531 | } | |||
| 17532 | break; | |||
| 17533 | case 71: | |||
| 17534 | if (!m_dxfInSubtype) | |||
| 17535 | return DRW_Surface::parseCode(code, reader); | |||
| 17536 | m_dxfTypedFieldSeen = true; | |||
| 17537 | { | |||
| 17538 | const std::int32_t value = reader->getInt32(); | |||
| 17539 | if (value < 0 || value > std::numeric_limits<std::uint16_t>::max()) | |||
| 17540 | return false; | |||
| 17541 | pathFlags = value; | |||
| 17542 | } | |||
| 17543 | break; | |||
| 17544 | case 290: | |||
| 17545 | if (!m_dxfInSubtype) | |||
| 17546 | return DRW_Surface::parseCode(code, reader); | |||
| 17547 | m_dxfTypedFieldSeen = true; | |||
| 17548 | solid = reader->getInt32() != 0; | |||
| 17549 | break; | |||
| 17550 | case 292: | |||
| 17551 | if (!m_dxfInSubtype) | |||
| 17552 | return DRW_Surface::parseCode(code, reader); | |||
| 17553 | m_dxfTypedFieldSeen = true; | |||
| 17554 | alignStart = reader->getInt32() != 0; | |||
| 17555 | break; | |||
| 17556 | case 293: | |||
| 17557 | if (!m_dxfInSubtype) | |||
| 17558 | return DRW_Surface::parseCode(code, reader); | |||
| 17559 | m_dxfTypedFieldSeen = true; | |||
| 17560 | bank = reader->getInt32() != 0; | |||
| 17561 | break; | |||
| 17562 | case 294: | |||
| 17563 | if (!m_dxfInSubtype) | |||
| 17564 | return DRW_Surface::parseCode(code, reader); | |||
| 17565 | m_dxfTypedFieldSeen = true; | |||
| 17566 | basePointSet = reader->getInt32() != 0; | |||
| 17567 | break; | |||
| 17568 | case 295: | |||
| 17569 | if (!m_dxfInSubtype) | |||
| 17570 | return DRW_Surface::parseCode(code, reader); | |||
| 17571 | m_dxfTypedFieldSeen = true; | |||
| 17572 | sweepEntityTransformComputed = reader->getInt32() != 0; | |||
| 17573 | break; | |||
| 17574 | case 296: | |||
| 17575 | if (!m_dxfInSubtype) | |||
| 17576 | return DRW_Surface::parseCode(code, reader); | |||
| 17577 | m_dxfTypedFieldSeen = true; | |||
| 17578 | pathEntityTransformComputed = reader->getInt32() != 0; | |||
| 17579 | break; | |||
| 17580 | default: | |||
| 17581 | return DRW_Surface::parseCode(code, reader); | |||
| 17582 | } | |||
| 17583 | return true; | |||
| 17584 | } | |||
| 17585 | ||||
| 17586 | bool DRW_SweptSurface::finalizeDxf() const { | |||
| 17587 | if (!m_dxfTypedFieldSeen) | |||
| 17588 | return true; | |||
| 17589 | return m_dxfInSubtype && m_dxfSweepEntityIdSeen | |||
| 17590 | && m_dxfPathEntityIdSeen | |||
| 17591 | && m_dxfSweepTransformCount == sweepEntityTransformed.size() | |||
| 17592 | && m_dxfPathTransformCount == pathEntityTransformed.size() | |||
| 17593 | && m_dxfSweepEntityTransformedCount == sweepEntityTransform.size() | |||
| 17594 | && m_dxfPathEntityTransformedCount == pathEntityTransform.size(); | |||
| 17595 | } | |||
| 17596 | ||||
| 17597 | bool DRW_LoftedSurface::parseCode( | |||
| 17598 | int code, const std::unique_ptr<dxfReader>& reader) { | |||
| 17599 | switch (code) { | |||
| 17600 | case 100: { | |||
| 17601 | const std::string marker = reader->getString(); | |||
| 17602 | if (marker == "AcDbLoftedSurface") | |||
| 17603 | m_dxfInSubtype = true; | |||
| 17604 | else if (marker == "AcDbModelerGeometry" | |||
| 17605 | || marker == "AcDbSurface") | |||
| 17606 | m_dxfInSubtype = false; | |||
| 17607 | break; | |||
| 17608 | } | |||
| 17609 | case 40: | |||
| 17610 | if (!m_dxfInSubtype) | |||
| 17611 | return DRW_Surface::parseCode(code, reader); | |||
| 17612 | m_dxfTypedFieldSeen = true; | |||
| 17613 | if (m_dxfTransformCount >= loftEntityTransform.size()) | |||
| 17614 | return false; | |||
| 17615 | loftEntityTransform[m_dxfTransformCount++] = reader->getDouble(); | |||
| 17616 | break; | |||
| 17617 | case 70: | |||
| 17618 | if (!m_dxfInSubtype) | |||
| 17619 | return DRW_Surface::parseCode(code, reader); | |||
| 17620 | m_dxfTypedFieldSeen = true; | |||
| 17621 | planeNormalLoftingType = reader->getInt32(); | |||
| 17622 | break; | |||
| 17623 | case 41: | |||
| 17624 | if (!m_dxfInSubtype) | |||
| 17625 | return DRW_Surface::parseCode(code, reader); | |||
| 17626 | m_dxfTypedFieldSeen = true; | |||
| 17627 | startDraftAngle = reader->getDouble(); | |||
| 17628 | break; | |||
| 17629 | case 42: | |||
| 17630 | if (!m_dxfInSubtype) | |||
| 17631 | return DRW_Surface::parseCode(code, reader); | |||
| 17632 | m_dxfTypedFieldSeen = true; | |||
| 17633 | endDraftAngle = reader->getDouble(); | |||
| 17634 | break; | |||
| 17635 | case 43: | |||
| 17636 | if (!m_dxfInSubtype) | |||
| 17637 | return DRW_Surface::parseCode(code, reader); | |||
| 17638 | m_dxfTypedFieldSeen = true; | |||
| 17639 | startDraftMagnitude = reader->getDouble(); | |||
| 17640 | break; | |||
| 17641 | case 44: | |||
| 17642 | if (!m_dxfInSubtype) | |||
| 17643 | return DRW_Surface::parseCode(code, reader); | |||
| 17644 | m_dxfTypedFieldSeen = true; | |||
| 17645 | endDraftMagnitude = reader->getDouble(); | |||
| 17646 | break; | |||
| 17647 | case 90: { | |||
| 17648 | if (!m_dxfInSubtype) | |||
| 17649 | return DRW_Surface::parseCode(code, reader); | |||
| 17650 | if (m_dxfReferenceTokenCount >= kMaxReferenceTokenCount) | |||
| 17651 | return false; | |||
| 17652 | const std::int32_t value = reader->getInt32(); | |||
| 17653 | if (value < 0 || static_cast<std::size_t>(value) | |||
| 17654 | > kMaxReferenceTokenCount) | |||
| 17655 | return false; | |||
| 17656 | m_dxfTypedFieldSeen = true; | |||
| 17657 | dxfReferenceData.emplace_back(90, value); | |||
| 17658 | ++m_dxfReferenceTokenCount; | |||
| 17659 | break; | |||
| 17660 | } | |||
| 17661 | case 310: { | |||
| 17662 | if (!m_dxfInSubtype) | |||
| 17663 | return DRW_Surface::parseCode(code, reader); | |||
| 17664 | std::vector<std::uint8_t> decoded; | |||
| 17665 | if (!decodeHexBytes(reader->getString(), decoded)) | |||
| 17666 | return false; | |||
| 17667 | if (m_dxfReferenceTokenCount >= kMaxReferenceTokenCount | |||
| 17668 | || decoded.size() > kMaxReferenceDataSize | |||
| 17669 | || m_dxfReferenceDataSize | |||
| 17670 | > kMaxReferenceDataSize - decoded.size()) | |||
| 17671 | return false; | |||
| 17672 | m_dxfTypedFieldSeen = true; | |||
| 17673 | dxfReferenceData.emplace_back(310, std::move(decoded)); | |||
| 17674 | m_dxfReferenceDataSize += dxfReferenceData.back().binary()->size(); | |||
| 17675 | ++m_dxfReferenceTokenCount; | |||
| 17676 | break; | |||
| 17677 | } | |||
| 17678 | case 290: | |||
| 17679 | if (!m_dxfInSubtype) | |||
| 17680 | return DRW_Surface::parseCode(code, reader); | |||
| 17681 | m_dxfTypedFieldSeen = true; | |||
| 17682 | arcLengthParameterization = reader->getInt32() != 0; | |||
| 17683 | break; | |||
| 17684 | case 291: | |||
| 17685 | if (!m_dxfInSubtype) | |||
| 17686 | return DRW_Surface::parseCode(code, reader); | |||
| 17687 | m_dxfTypedFieldSeen = true; | |||
| 17688 | noTwist = reader->getInt32() != 0; | |||
| 17689 | break; | |||
| 17690 | case 292: | |||
| 17691 | if (!m_dxfInSubtype) | |||
| 17692 | return DRW_Surface::parseCode(code, reader); | |||
| 17693 | m_dxfTypedFieldSeen = true; | |||
| 17694 | alignDirection = reader->getInt32() != 0; | |||
| 17695 | break; | |||
| 17696 | case 293: | |||
| 17697 | if (!m_dxfInSubtype) | |||
| 17698 | return DRW_Surface::parseCode(code, reader); | |||
| 17699 | m_dxfTypedFieldSeen = true; | |||
| 17700 | simpleSurfaces = reader->getInt32() != 0; | |||
| 17701 | break; | |||
| 17702 | case 294: | |||
| 17703 | if (!m_dxfInSubtype) | |||
| 17704 | return DRW_Surface::parseCode(code, reader); | |||
| 17705 | m_dxfTypedFieldSeen = true; | |||
| 17706 | closedSurfaces = reader->getInt32() != 0; | |||
| 17707 | break; | |||
| 17708 | case 295: | |||
| 17709 | if (!m_dxfInSubtype) | |||
| 17710 | return DRW_Surface::parseCode(code, reader); | |||
| 17711 | m_dxfTypedFieldSeen = true; | |||
| 17712 | solid = reader->getInt32() != 0; | |||
| 17713 | break; | |||
| 17714 | case 296: | |||
| 17715 | if (!m_dxfInSubtype) | |||
| 17716 | return DRW_Surface::parseCode(code, reader); | |||
| 17717 | m_dxfTypedFieldSeen = true; | |||
| 17718 | ruledSurface = reader->getInt32() != 0; | |||
| 17719 | break; | |||
| 17720 | case 297: | |||
| 17721 | if (!m_dxfInSubtype) | |||
| 17722 | return DRW_Surface::parseCode(code, reader); | |||
| 17723 | m_dxfTypedFieldSeen = true; | |||
| 17724 | virtualGuide = reader->getInt32() != 0; | |||
| 17725 | break; | |||
| 17726 | case 5: | |||
| 17727 | if (!m_dxfInSubtype) | |||
| 17728 | return DRW_Surface::parseCode(code, reader); | |||
| 17729 | if (!reader->isValidHandleString()) | |||
| 17730 | return false; | |||
| 17731 | m_dxfTypedFieldSeen = true; | |||
| 17732 | pathCurveHandle = reader->getHandleString(); | |||
| 17733 | break; | |||
| 17734 | default: | |||
| 17735 | return DRW_Surface::parseCode(code, reader); | |||
| 17736 | } | |||
| 17737 | return true; | |||
| 17738 | } | |||
| 17739 | ||||
| 17740 | bool DRW_LoftedSurface::finalizeDxf() const { | |||
| 17741 | if (!m_dxfTypedFieldSeen) | |||
| 17742 | return true; | |||
| 17743 | return m_dxfInSubtype | |||
| 17744 | && m_dxfTransformCount == loftEntityTransform.size() | |||
| 17745 | && std::all_of(loftEntityTransform.begin(), loftEntityTransform.end(), | |||
| 17746 | [](double value) { return std::isfinite(value); }) | |||
| 17747 | && std::isfinite(startDraftAngle) | |||
| 17748 | && std::isfinite(endDraftAngle) | |||
| 17749 | && std::isfinite(startDraftMagnitude) | |||
| 17750 | && std::isfinite(endDraftMagnitude); | |||
| 17751 | } | |||
| 17752 | ||||
| 17753 | bool DRW_NurbsSurface::parseCode( | |||
| 17754 | int code, const std::unique_ptr<dxfReader>& reader) { | |||
| 17755 | switch (code) { | |||
| 17756 | case 100: { | |||
| 17757 | const std::string marker = reader->getString(); | |||
| 17758 | if (marker == "AcDbNurbSurface") | |||
| 17759 | m_dxfInSubtype = true; | |||
| 17760 | else if (marker == "AcDbModelerGeometry" | |||
| 17761 | || marker == "AcDbSurface") | |||
| 17762 | m_dxfInSubtype = false; | |||
| 17763 | break; | |||
| 17764 | } | |||
| 17765 | case 170: | |||
| 17766 | if (!m_dxfInSubtype) | |||
| 17767 | return DRW_Surface::parseCode(code, reader); | |||
| 17768 | { | |||
| 17769 | const std::int32_t value = reader->getInt32(); | |||
| 17770 | if (value < 0 || value > std::numeric_limits<std::uint16_t>::max()) | |||
| 17771 | return false; | |||
| 17772 | short170 = static_cast<std::uint16_t>(value); | |||
| 17773 | m_dxfTypedFieldSeen = true; | |||
| 17774 | } | |||
| 17775 | break; | |||
| 17776 | case 290: | |||
| 17777 | if (!m_dxfInSubtype) | |||
| 17778 | return DRW_Surface::parseCode(code, reader); | |||
| 17779 | cvHullDisplay = reader->getInt32() != 0; | |||
| 17780 | m_dxfTypedFieldSeen = true; | |||
| 17781 | break; | |||
| 17782 | case 10: | |||
| 17783 | if (!m_dxfInSubtype) | |||
| 17784 | return DRW_Surface::parseCode(code, reader); | |||
| 17785 | uvec1.x = reader->getDouble(); | |||
| 17786 | m_dxfCoordinateMask[0] |= 1; | |||
| 17787 | m_dxfTypedFieldSeen = true; | |||
| 17788 | break; | |||
| 17789 | case 20: | |||
| 17790 | if (!m_dxfInSubtype) | |||
| 17791 | return DRW_Surface::parseCode(code, reader); | |||
| 17792 | uvec1.y = reader->getDouble(); | |||
| 17793 | m_dxfCoordinateMask[0] |= 2; | |||
| 17794 | m_dxfTypedFieldSeen = true; | |||
| 17795 | break; | |||
| 17796 | case 30: | |||
| 17797 | if (!m_dxfInSubtype) | |||
| 17798 | return DRW_Surface::parseCode(code, reader); | |||
| 17799 | uvec1.z = reader->getDouble(); | |||
| 17800 | m_dxfCoordinateMask[0] |= 4; | |||
| 17801 | m_dxfTypedFieldSeen = true; | |||
| 17802 | break; | |||
| 17803 | case 11: | |||
| 17804 | if (!m_dxfInSubtype) | |||
| 17805 | return DRW_Surface::parseCode(code, reader); | |||
| 17806 | vvec1.x = reader->getDouble(); | |||
| 17807 | m_dxfCoordinateMask[1] |= 1; | |||
| 17808 | m_dxfTypedFieldSeen = true; | |||
| 17809 | break; | |||
| 17810 | case 21: | |||
| 17811 | if (!m_dxfInSubtype) | |||
| 17812 | return DRW_Surface::parseCode(code, reader); | |||
| 17813 | vvec1.y = reader->getDouble(); | |||
| 17814 | m_dxfCoordinateMask[1] |= 2; | |||
| 17815 | m_dxfTypedFieldSeen = true; | |||
| 17816 | break; | |||
| 17817 | case 31: | |||
| 17818 | if (!m_dxfInSubtype) | |||
| 17819 | return DRW_Surface::parseCode(code, reader); | |||
| 17820 | vvec1.z = reader->getDouble(); | |||
| 17821 | m_dxfCoordinateMask[1] |= 4; | |||
| 17822 | m_dxfTypedFieldSeen = true; | |||
| 17823 | break; | |||
| 17824 | case 12: | |||
| 17825 | if (!m_dxfInSubtype) | |||
| 17826 | return DRW_Surface::parseCode(code, reader); | |||
| 17827 | uvec2.x = reader->getDouble(); | |||
| 17828 | m_dxfCoordinateMask[2] |= 1; | |||
| 17829 | m_dxfTypedFieldSeen = true; | |||
| 17830 | break; | |||
| 17831 | case 22: | |||
| 17832 | if (!m_dxfInSubtype) | |||
| 17833 | return DRW_Surface::parseCode(code, reader); | |||
| 17834 | uvec2.y = reader->getDouble(); | |||
| 17835 | m_dxfCoordinateMask[2] |= 2; | |||
| 17836 | m_dxfTypedFieldSeen = true; | |||
| 17837 | break; | |||
| 17838 | case 32: | |||
| 17839 | if (!m_dxfInSubtype) | |||
| 17840 | return DRW_Surface::parseCode(code, reader); | |||
| 17841 | uvec2.z = reader->getDouble(); | |||
| 17842 | m_dxfCoordinateMask[2] |= 4; | |||
| 17843 | m_dxfTypedFieldSeen = true; | |||
| 17844 | break; | |||
| 17845 | case 13: | |||
| 17846 | if (!m_dxfInSubtype) | |||
| 17847 | return DRW_Surface::parseCode(code, reader); | |||
| 17848 | vvec2.x = reader->getDouble(); | |||
| 17849 | m_dxfCoordinateMask[3] |= 1; | |||
| 17850 | m_dxfTypedFieldSeen = true; | |||
| 17851 | break; | |||
| 17852 | case 23: | |||
| 17853 | if (!m_dxfInSubtype) | |||
| 17854 | return DRW_Surface::parseCode(code, reader); | |||
| 17855 | vvec2.y = reader->getDouble(); | |||
| 17856 | m_dxfCoordinateMask[3] |= 2; | |||
| 17857 | m_dxfTypedFieldSeen = true; | |||
| 17858 | break; | |||
| 17859 | case 33: | |||
| 17860 | if (!m_dxfInSubtype) | |||
| 17861 | return DRW_Surface::parseCode(code, reader); | |||
| 17862 | vvec2.z = reader->getDouble(); | |||
| 17863 | m_dxfCoordinateMask[3] |= 4; | |||
| 17864 | m_dxfTypedFieldSeen = true; | |||
| 17865 | break; | |||
| 17866 | default: | |||
| 17867 | return DRW_Surface::parseCode(code, reader); | |||
| 17868 | } | |||
| 17869 | return true; | |||
| 17870 | } | |||
| 17871 | ||||
| 17872 | bool DRW_NurbsSurface::finalizeDxf() const { | |||
| 17873 | if (!m_dxfTypedFieldSeen) | |||
| 17874 | return true; | |||
| 17875 | const bool coordinatesSeen = std::any_of( | |||
| 17876 | m_dxfCoordinateMask.begin(), m_dxfCoordinateMask.end(), | |||
| 17877 | [](std::uint8_t mask) { return mask != 0; }); | |||
| 17878 | if (!m_dxfInSubtype | |||
| 17879 | || (coordinatesSeen && std::any_of( | |||
| 17880 | m_dxfCoordinateMask.begin(), m_dxfCoordinateMask.end(), | |||
| 17881 | [](std::uint8_t mask) { return mask != 7; }))) { | |||
| 17882 | return false; | |||
| 17883 | } | |||
| 17884 | return std::all_of(m_dxfCoordinateMask.begin(), m_dxfCoordinateMask.end(), | |||
| 17885 | [](std::uint8_t mask) { return mask == 0 || mask == 7; }) | |||
| 17886 | && std::isfinite(uvec1.x) && std::isfinite(uvec1.y) | |||
| 17887 | && std::isfinite(uvec1.z) && std::isfinite(vvec1.x) | |||
| 17888 | && std::isfinite(vvec1.y) && std::isfinite(vvec1.z) | |||
| 17889 | && std::isfinite(uvec2.x) && std::isfinite(uvec2.y) | |||
| 17890 | && std::isfinite(uvec2.z) && std::isfinite(vvec2.x) | |||
| 17891 | && std::isfinite(vvec2.y) && std::isfinite(vvec2.z); | |||
| 17892 | } | |||
| 17893 | ||||
| 17894 | bool DRW_RevolvedSurface::parseCode( | |||
| 17895 | int code, const std::unique_ptr<dxfReader>& reader) { | |||
| 17896 | switch (code) { | |||
| 17897 | case 90: | |||
| 17898 | if (!m_dxfClassIdSeen) { | |||
| 17899 | const std::int32_t value = reader->getInt32(); | |||
| 17900 | if (value < 0) | |||
| 17901 | return false; | |||
| 17902 | classId = static_cast<std::uint32_t>(value); | |||
| 17903 | m_dxfClassIdSeen = true; | |||
| 17904 | } else { | |||
| 17905 | const std::int32_t value = reader->getInt32(); | |||
| 17906 | if (value < 0) | |||
| 17907 | return false; | |||
| 17908 | id = static_cast<std::uint32_t>(value); | |||
| 17909 | } | |||
| 17910 | break; | |||
| 17911 | case 310: | |||
| 17912 | // Revolve data follows the subclass id; it must not join the ACIS body. | |||
| 17913 | if (!m_dxfClassIdSeen) | |||
| 17914 | return DRW_Surface::parseCode(code, reader); | |||
| 17915 | break; | |||
| 17916 | case 10: | |||
| 17917 | axisPoint.x = reader->getDouble(); | |||
| 17918 | break; | |||
| 17919 | case 20: | |||
| 17920 | axisPoint.y = reader->getDouble(); | |||
| 17921 | break; | |||
| 17922 | case 30: | |||
| 17923 | axisPoint.z = reader->getDouble(); | |||
| 17924 | break; | |||
| 17925 | case 11: | |||
| 17926 | axisVector.x = reader->getDouble(); | |||
| 17927 | break; | |||
| 17928 | case 21: | |||
| 17929 | axisVector.y = reader->getDouble(); | |||
| 17930 | break; | |||
| 17931 | case 31: | |||
| 17932 | axisVector.z = reader->getDouble(); | |||
| 17933 | break; | |||
| 17934 | case 40: | |||
| 17935 | revolveAngle = reader->getDouble(); | |||
| 17936 | break; | |||
| 17937 | case 41: | |||
| 17938 | startAngle = reader->getDouble(); | |||
| 17939 | break; | |||
| 17940 | case 42: | |||
| 17941 | if (m_dxfTransformCount >= transform.size()) | |||
| 17942 | return false; | |||
| 17943 | transform[m_dxfTransformCount++] = reader->getDouble(); | |||
| 17944 | break; | |||
| 17945 | case 43: | |||
| 17946 | draftAngle = reader->getDouble(); | |||
| 17947 | break; | |||
| 17948 | case 44: | |||
| 17949 | draftStartDistance = reader->getDouble(); | |||
| 17950 | break; | |||
| 17951 | case 45: | |||
| 17952 | draftEndDistance = reader->getDouble(); | |||
| 17953 | break; | |||
| 17954 | case 46: | |||
| 17955 | twistAngle = reader->getDouble(); | |||
| 17956 | break; | |||
| 17957 | case 290: | |||
| 17958 | solid = reader->getInt32() != 0; | |||
| 17959 | break; | |||
| 17960 | case 291: | |||
| 17961 | closeToAxis = reader->getInt32() != 0; | |||
| 17962 | break; | |||
| 17963 | default: | |||
| 17964 | return DRW_Surface::parseCode(code, reader); | |||
| 17965 | } | |||
| 17966 | return true; | |||
| 17967 | } | |||
| 17968 | ||||
| 17969 | void DRW_Surface::resetDwgState() { | |||
| 17970 | DRW_Entity::reset(); | |||
| 17971 | uIsolines = 0; | |||
| 17972 | vIsolines = 0; | |||
| 17973 | modelerFormatVersion = 0; | |||
| 17974 | acisEmpty = false; | |||
| 17975 | acisVersion = 0; | |||
| 17976 | rawAcisData.clear(); | |||
| 17977 | hasRawDwgBody = false; | |||
| 17978 | rawDwgBodyBitSize = 0; | |||
| 17979 | rawDwgBodyVersion = DRW::UNKNOWNV; | |||
| 17980 | crossSectionHandles.clear(); | |||
| 17981 | guideCurveHandles.clear(); | |||
| 17982 | dwgClassNum = 0; | |||
| 17983 | dwgPayloadDecoded = false; | |||
| 17984 | m_wireframe = DRW_AcisBrep(); | |||
| 17985 | m_wireframeDecoded = false; | |||
| 17986 | ||||
| 17987 | const auto identity = [] { | |||
| 17988 | return std::array<double, DRW_ExtrudedSurface::kTransformSize>{ | |||
| 17989 | 1.0, 0.0, 0.0, 0.0, | |||
| 17990 | 0.0, 1.0, 0.0, 0.0, | |||
| 17991 | 0.0, 0.0, 1.0, 0.0, | |||
| 17992 | 0.0, 0.0, 0.0, 1.0}; | |||
| 17993 | }; | |||
| 17994 | switch (eType) { | |||
| 17995 | case DRW::EXTRUDEDSURFACE: { | |||
| 17996 | auto *surface = static_cast<DRW_ExtrudedSurface *>(this); | |||
| 17997 | surface->classId = 0; | |||
| 17998 | surface->sweepVector = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 17999 | surface->extrudedTransform = identity(); | |||
| 18000 | surface->sweepEntityTransform = identity(); | |||
| 18001 | surface->pathEntityTransform = identity(); | |||
| 18002 | surface->draftAngle = 0.0; | |||
| 18003 | surface->draftStartDistance = 0.0; | |||
| 18004 | surface->draftEndDistance = 0.0; | |||
| 18005 | surface->twistAngle = 0.0; | |||
| 18006 | surface->scaleFactor = 0.0; | |||
| 18007 | surface->alignAngle = 0.0; | |||
| 18008 | surface->solid = false; | |||
| 18009 | surface->sweepAlignmentFlags = 0; | |||
| 18010 | surface->pathFlags = 0; | |||
| 18011 | surface->alignStart = false; | |||
| 18012 | surface->bank = false; | |||
| 18013 | surface->basePointSet = false; | |||
| 18014 | surface->sweepEntityTransformComputed = false; | |||
| 18015 | surface->pathEntityTransformComputed = false; | |||
| 18016 | surface->referenceVector = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 18017 | break; | |||
| 18018 | } | |||
| 18019 | case DRW::REVOLVEDSURFACE: { | |||
| 18020 | auto *surface = static_cast<DRW_RevolvedSurface *>(this); | |||
| 18021 | surface->classId = 0; | |||
| 18022 | surface->id = 0; | |||
| 18023 | surface->axisPoint = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 18024 | surface->axisVector = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 18025 | surface->revolveAngle = 0.0; | |||
| 18026 | surface->startAngle = 0.0; | |||
| 18027 | surface->transform = identity(); | |||
| 18028 | surface->draftAngle = 0.0; | |||
| 18029 | surface->draftStartDistance = 0.0; | |||
| 18030 | surface->draftEndDistance = 0.0; | |||
| 18031 | surface->twistAngle = 0.0; | |||
| 18032 | surface->solid = false; | |||
| 18033 | surface->closeToAxis = false; | |||
| 18034 | break; | |||
| 18035 | } | |||
| 18036 | case DRW::SWEPTSURFACE: { | |||
| 18037 | auto *surface = static_cast<DRW_SweptSurface *>(this); | |||
| 18038 | surface->classVersion = 0; | |||
| 18039 | surface->sweepEntityId = 0; | |||
| 18040 | surface->sweepData.clear(); | |||
| 18041 | surface->pathEntityId = 0; | |||
| 18042 | surface->pathData.clear(); | |||
| 18043 | surface->sweepEntityTransform = identity(); | |||
| 18044 | surface->pathEntityTransform = identity(); | |||
| 18045 | surface->draftAngle = 0.0; | |||
| 18046 | surface->draftStartDistance = 0.0; | |||
| 18047 | surface->draftEndDistance = 0.0; | |||
| 18048 | surface->twistAngle = 0.0; | |||
| 18049 | surface->scaleFactor = 1.0; | |||
| 18050 | surface->alignAngle = 0.0; | |||
| 18051 | surface->sweepEntityTransformed = identity(); | |||
| 18052 | surface->pathEntityTransformed = identity(); | |||
| 18053 | surface->solid = false; | |||
| 18054 | surface->sweepAlignmentFlags = 0; | |||
| 18055 | surface->pathFlags = 0; | |||
| 18056 | surface->alignStart = false; | |||
| 18057 | surface->bank = false; | |||
| 18058 | surface->basePointSet = false; | |||
| 18059 | surface->sweepEntityTransformComputed = false; | |||
| 18060 | surface->pathEntityTransformComputed = false; | |||
| 18061 | surface->referenceVector = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 18062 | break; | |||
| 18063 | } | |||
| 18064 | case DRW::LOFTEDSURFACE: { | |||
| 18065 | auto *surface = static_cast<DRW_LoftedSurface *>(this); | |||
| 18066 | surface->loftEntityTransform = identity(); | |||
| 18067 | surface->planeNormalLoftingType = 0; | |||
| 18068 | surface->startDraftAngle = 0.0; | |||
| 18069 | surface->endDraftAngle = 0.0; | |||
| 18070 | surface->startDraftMagnitude = 0.0; | |||
| 18071 | surface->endDraftMagnitude = 0.0; | |||
| 18072 | surface->arcLengthParameterization = false; | |||
| 18073 | surface->noTwist = true; | |||
| 18074 | surface->alignDirection = true; | |||
| 18075 | surface->simpleSurfaces = true; | |||
| 18076 | surface->closedSurfaces = false; | |||
| 18077 | surface->solid = false; | |||
| 18078 | surface->ruledSurface = false; | |||
| 18079 | surface->virtualGuide = false; | |||
| 18080 | surface->numCrossSections = 0; | |||
| 18081 | surface->numGuideCurves = 0; | |||
| 18082 | surface->dxfReferenceData.clear(); | |||
| 18083 | surface->pathCurveHandle = 0; | |||
| 18084 | break; | |||
| 18085 | } | |||
| 18086 | case DRW::NURBSURFACE: { | |||
| 18087 | auto *surface = static_cast<DRW_NurbsSurface *>(this); | |||
| 18088 | surface->short170 = 0; | |||
| 18089 | surface->cvHullDisplay = false; | |||
| 18090 | surface->uvec1 = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 18091 | surface->vvec1 = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 18092 | surface->uvec2 = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 18093 | surface->vvec2 = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 18094 | break; | |||
| 18095 | } | |||
| 18096 | default: | |||
| 18097 | break; | |||
| 18098 | } | |||
| 18099 | } | |||
| 18100 | ||||
| 18101 | bool DRW_Surface::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs) { | |||
| 18102 | resetDwgState(); | |||
| 18103 | dwgBuffer *sourceBuf = buf; | |||
| 18104 | auto fail = [this, sourceBuf]() { | |||
| 18105 | if (sourceBuf != nullptr) | |||
| 18106 | sourceBuf->invalidate(); | |||
| 18107 | resetDwgState(); | |||
| 18108 | return false; | |||
| 18109 | }; | |||
| 18110 | if (sourceBuf == nullptr) | |||
| 18111 | return fail(); | |||
| 18112 | ||||
| 18113 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 18114 | dwgBuffer stringProbe = sourceBuf->forkIndependent(); | |||
| 18115 | dwgBuffer *stringStream = version > DRW::AC1018 ? &stringProbe : nullptr; | |||
| 18116 | if (!DRW_Entity::parseDwg(version, &bodyProbe, stringStream, bs)) | |||
| 18117 | return fail(); | |||
| 18118 | buf = &bodyProbe; | |||
| 18119 | const std::uint64_t bodyStartBit = currentDwgBit(buf); | |||
| 18120 | ||||
| 18121 | // Surface bodies are opaque here, but their bounded bytes still carry the | |||
| 18122 | // ACIS payload and must be available for rendering and metadata replay. | |||
| 18123 | std::uint64_t bodyEndBit = bodyStartBit; | |||
| 18124 | if (!entityBodyDataEndBit( | |||
| 18125 | stringStream != nullptr ? *stringStream : bodyProbe, | |||
| 18126 | version, objSize, bodyEndBit)) | |||
| 18127 | return fail(); | |||
| 18128 | if (bodyEndBit < bodyStartBit) | |||
| 18129 | return fail(); | |||
| 18130 | if (bodyEndBit > bodyStartBit | |||
| 18131 | && bodyEndBit - bodyStartBit > std::numeric_limits<std::uint32_t>::max()) | |||
| 18132 | return fail(); | |||
| 18133 | hasRawDwgBody = bodyEndBit > bodyStartBit; | |||
| 18134 | rawDwgBodyBitSize = static_cast<std::uint32_t>( | |||
| 18135 | bodyEndBit >= bodyStartBit ? bodyEndBit - bodyStartBit : 0); | |||
| 18136 | rawDwgBodyVersion = version; | |||
| 18137 | dwgClassNum = oType >= 0 ? static_cast<std::uint16_t>(oType) : 0; | |||
| 18138 | dwgPayloadDecoded = false; | |||
| 18139 | crossSectionHandles.clear(); | |||
| 18140 | guideCurveHandles.clear(); | |||
| 18141 | if (bodyEndBit > bodyStartBit | |||
| 18142 | && !copyDwgBitRange(*buf, bodyStartBit, bodyEndBit, rawAcisData)) { | |||
| 18143 | return fail(); | |||
| 18144 | } | |||
| 18145 | ||||
| 18146 | // When has_ds_data is set, the bounded body is an inline DataStorage/SAB | |||
| 18147 | // payload. Keep it opaque, matching the cross-project reader contract; | |||
| 18148 | // interpreting its bytes as subtype fields can fabricate counts and make | |||
| 18149 | // a valid surface fail while reading a nonexistent handle tail. | |||
| 18150 | if (bodyEndBit > bodyStartBit && !hasDsData) { | |||
| 18151 | SurfaceDwgPayloadInfo payload; | |||
| 18152 | if (readSurfaceDwgPayload( | |||
| 18153 | rawAcisData, bodyEndBit - bodyStartBit, version, eType, | |||
| 18154 | surfaceHasModelerFormatVersion(eType), | |||
| 18155 | surfaceModelerFormatVersionLimit(eType), payload)) { | |||
| 18156 | acisEmpty = payload.acisEmpty; | |||
| 18157 | acisVersion = payload.acisVersion; | |||
| 18158 | modelerFormatVersion = payload.modelerFormatVersion; | |||
| 18159 | uIsolines = payload.uIsolines; | |||
| 18160 | vIsolines = payload.vIsolines; | |||
| 18161 | if (payload.extrudedFieldsValid | |||
| 18162 | && eType == DRW::EXTRUDEDSURFACE) { | |||
| 18163 | auto *extruded = static_cast<DRW_ExtrudedSurface *>(this); | |||
| 18164 | extruded->sweepVector = payload.extrudedSweepVector; | |||
| 18165 | extruded->extrudedTransform = payload.extrudedTransform; | |||
| 18166 | extruded->sweepEntityTransform = | |||
| 18167 | payload.extrudedSweepEntityTransform; | |||
| 18168 | extruded->pathEntityTransform = | |||
| 18169 | payload.extrudedPathEntityTransform; | |||
| 18170 | extruded->draftAngle = payload.extrudedDraftAngle; | |||
| 18171 | extruded->draftStartDistance = | |||
| 18172 | payload.extrudedDraftStartDistance; | |||
| 18173 | extruded->draftEndDistance = payload.extrudedDraftEndDistance; | |||
| 18174 | extruded->twistAngle = payload.extrudedTwistAngle; | |||
| 18175 | extruded->scaleFactor = payload.extrudedScaleFactor; | |||
| 18176 | extruded->alignAngle = payload.extrudedAlignAngle; | |||
| 18177 | extruded->solid = payload.extrudedSolid; | |||
| 18178 | extruded->sweepAlignmentFlags = | |||
| 18179 | payload.extrudedSweepAlignmentFlags; | |||
| 18180 | extruded->pathFlags = payload.extrudedPathFlags; | |||
| 18181 | extruded->alignStart = payload.extrudedAlignStart; | |||
| 18182 | extruded->bank = payload.extrudedBank; | |||
| 18183 | extruded->basePointSet = payload.extrudedBasePointSet; | |||
| 18184 | extruded->sweepEntityTransformComputed = | |||
| 18185 | payload.extrudedSweepEntityTransformComputed; | |||
| 18186 | extruded->pathEntityTransformComputed = | |||
| 18187 | payload.extrudedPathEntityTransformComputed; | |||
| 18188 | extruded->referenceVector = payload.extrudedReferenceVector; | |||
| 18189 | } | |||
| 18190 | if (payload.sweptFieldsValid && eType == DRW::SWEPTSURFACE) { | |||
| 18191 | auto *swept = static_cast<DRW_SweptSurface *>(this); | |||
| 18192 | swept->classVersion = payload.sweptClassVersion; | |||
| 18193 | swept->sweepEntityId = payload.sweptEntityId; | |||
| 18194 | swept->sweepData = payload.sweptData; | |||
| 18195 | swept->pathEntityId = payload.sweptPathEntityId; | |||
| 18196 | swept->pathData = payload.sweptPathData; | |||
| 18197 | swept->sweepEntityTransform = payload.sweptEntityTransform; | |||
| 18198 | swept->pathEntityTransform = payload.sweptPathEntityTransform; | |||
| 18199 | swept->draftAngle = payload.sweptDraftAngle; | |||
| 18200 | swept->draftStartDistance = payload.sweptDraftStartDistance; | |||
| 18201 | swept->draftEndDistance = payload.sweptDraftEndDistance; | |||
| 18202 | swept->twistAngle = payload.sweptTwistAngle; | |||
| 18203 | swept->scaleFactor = payload.sweptScaleFactor; | |||
| 18204 | swept->alignAngle = payload.sweptAlignAngle; | |||
| 18205 | swept->solid = payload.sweptSolid; | |||
| 18206 | swept->sweepAlignmentFlags = payload.sweptAlignmentFlags; | |||
| 18207 | swept->pathFlags = payload.sweptPathFlags; | |||
| 18208 | swept->alignStart = payload.sweptAlignStart; | |||
| 18209 | swept->bank = payload.sweptBank; | |||
| 18210 | swept->basePointSet = payload.sweptBasePointSet; | |||
| 18211 | swept->sweepEntityTransformComputed = | |||
| 18212 | payload.sweptEntityTransformComputed; | |||
| 18213 | swept->pathEntityTransformComputed = | |||
| 18214 | payload.sweptPathEntityTransformComputed; | |||
| 18215 | swept->referenceVector = payload.sweptReferenceVector; | |||
| 18216 | } | |||
| 18217 | if (payload.loftedFieldsValid && eType == DRW::LOFTEDSURFACE) { | |||
| 18218 | auto *lofted = static_cast<DRW_LoftedSurface *>(this); | |||
| 18219 | lofted->loftEntityTransform = payload.loftedEntityTransform; | |||
| 18220 | lofted->planeNormalLoftingType = | |||
| 18221 | payload.loftedPlaneNormalLoftingType; | |||
| 18222 | lofted->startDraftAngle = payload.loftedStartDraftAngle; | |||
| 18223 | lofted->endDraftAngle = payload.loftedEndDraftAngle; | |||
| 18224 | lofted->startDraftMagnitude = | |||
| 18225 | payload.loftedStartDraftMagnitude; | |||
| 18226 | lofted->endDraftMagnitude = payload.loftedEndDraftMagnitude; | |||
| 18227 | lofted->arcLengthParameterization = | |||
| 18228 | payload.loftedArcLengthParameterization; | |||
| 18229 | lofted->noTwist = payload.loftedNoTwist; | |||
| 18230 | lofted->alignDirection = payload.loftedAlignDirection; | |||
| 18231 | lofted->simpleSurfaces = payload.loftedSimpleSurfaces; | |||
| 18232 | lofted->closedSurfaces = payload.loftedClosedSurfaces; | |||
| 18233 | lofted->solid = payload.loftedSolid; | |||
| 18234 | lofted->ruledSurface = payload.loftedRuledSurface; | |||
| 18235 | lofted->virtualGuide = payload.loftedVirtualGuide; | |||
| 18236 | lofted->numCrossSections = payload.loftedNumCrossSections; | |||
| 18237 | lofted->numGuideCurves = payload.loftedNumGuideCurves; | |||
| 18238 | } | |||
| 18239 | if (payload.nurbsFieldsValid && eType == DRW::NURBSURFACE) { | |||
| 18240 | auto *nurbs = static_cast<DRW_NurbsSurface *>(this); | |||
| 18241 | nurbs->short170 = payload.nurbsShort170; | |||
| 18242 | nurbs->cvHullDisplay = payload.nurbsCvHullDisplay; | |||
| 18243 | nurbs->uvec1 = payload.nurbsUvec1; | |||
| 18244 | nurbs->vvec1 = payload.nurbsVvec1; | |||
| 18245 | nurbs->uvec2 = payload.nurbsUvec2; | |||
| 18246 | nurbs->vvec2 = payload.nurbsVvec2; | |||
| 18247 | } | |||
| 18248 | dwgPayloadDecoded = true; | |||
| 18249 | if (payload.revolvedFieldsValid | |||
| 18250 | && eType == DRW::REVOLVEDSURFACE) { | |||
| 18251 | auto *revolved = static_cast<DRW_RevolvedSurface *>(this); | |||
| 18252 | revolved->classId = payload.revolvedClassId; | |||
| 18253 | revolved->id = payload.revolvedId; | |||
| 18254 | revolved->axisPoint = payload.revolvedAxisPoint; | |||
| 18255 | revolved->axisVector = payload.revolvedAxisVector; | |||
| 18256 | revolved->revolveAngle = payload.revolvedAngle; | |||
| 18257 | revolved->startAngle = payload.revolvedStartAngle; | |||
| 18258 | revolved->transform = payload.revolvedTransform; | |||
| 18259 | revolved->draftAngle = payload.revolvedDraftAngle; | |||
| 18260 | revolved->draftStartDistance = payload.revolvedDraftStartDistance; | |||
| 18261 | revolved->draftEndDistance = payload.revolvedDraftEndDistance; | |||
| 18262 | revolved->twistAngle = payload.revolvedTwistAngle; | |||
| 18263 | revolved->solid = payload.revolvedSolid; | |||
| 18264 | revolved->closeToAxis = payload.revolvedCloseToAxis; | |||
| 18265 | } | |||
| 18266 | } | |||
| 18267 | } | |||
| 18268 | ||||
| 18269 | // R13-R2004 keep the handle stream inline; seek to the documented body | |||
| 18270 | // boundary before the common handle parser. R2007+ performs that seek in | |||
| 18271 | // parseDwgEntHandle() itself. | |||
| 18272 | dwgBuffer handleProbe = bodyProbe.forkIndependent(); | |||
| 18273 | if (version <= DRW::AC1018 && bodyEndBit > bodyStartBit) { | |||
| 18274 | if (!handleProbe.setPosition(bodyEndBit >> 3)) | |||
| 18275 | return fail(); | |||
| 18276 | handleProbe.setBitPos(static_cast<std::uint8_t>(bodyEndBit & 7u)); | |||
| 18277 | if (!handleProbe.isGood()) | |||
| 18278 | return fail(); | |||
| 18279 | } | |||
| 18280 | std::uint64_t handleEndBit = 0; | |||
| 18281 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, | |||
| 18282 | handleEndBit)) | |||
| 18283 | return fail(); | |||
| 18284 | if (!DRW_Entity::parseDwgEntHandle(version, &handleProbe, true, | |||
| 18285 | handleEndBit) | |||
| 18286 | || !handleProbe.isGood()) | |||
| 18287 | return fail(); | |||
| 18288 | std::vector<std::uint32_t> parsedCrossSectionHandles; | |||
| 18289 | std::vector<std::uint32_t> parsedGuideCurveHandles; | |||
| 18290 | std::uint32_t parsedPathCurveHandle = 0; | |||
| 18291 | const auto readHandleList = [&](std::int32_t count, | |||
| 18292 | std::vector<std::uint32_t>& values) { | |||
| 18293 | if (count < 0 | |||
| 18294 | || count > static_cast<std::int32_t>( | |||
| 18295 | DRW_LoftedSurface::kMaxReferenceTokenCount) | |||
| 18296 | || !DRW::reserve(values, count)) | |||
| 18297 | return false; | |||
| 18298 | for (std::int32_t i = 0; i < count; ++i) { | |||
| 18299 | dwgHandle value; | |||
| 18300 | if (!readBoundedDwgHandle(handleProbe, handleEndBit, handle, true, | |||
| 18301 | value)) | |||
| 18302 | return false; | |||
| 18303 | values.push_back(value.ref); | |||
| 18304 | } | |||
| 18305 | return true; | |||
| 18306 | }; | |||
| 18307 | if (eType == DRW::LOFTEDSURFACE && dwgPayloadDecoded) { | |||
| 18308 | auto *lofted = static_cast<DRW_LoftedSurface *>(this); | |||
| 18309 | if (!readHandleList(lofted->numCrossSections, | |||
| 18310 | parsedCrossSectionHandles) | |||
| 18311 | || !readHandleList(lofted->numGuideCurves, | |||
| 18312 | parsedGuideCurveHandles)) | |||
| 18313 | return fail(); | |||
| 18314 | dwgHandle pathCurve; | |||
| 18315 | if (!readBoundedDwgHandle(handleProbe, handleEndBit, handle, true, | |||
| 18316 | pathCurve)) | |||
| 18317 | return fail(); | |||
| 18318 | parsedPathCurveHandle = pathCurve.ref; | |||
| 18319 | } | |||
| 18320 | if (!handleProbe.isGood()) | |||
| 18321 | return fail(); | |||
| 18322 | crossSectionHandles = std::move(parsedCrossSectionHandles); | |||
| 18323 | guideCurveHandles = std::move(parsedGuideCurveHandles); | |||
| 18324 | if (eType == DRW::LOFTEDSURFACE) | |||
| 18325 | static_cast<DRW_LoftedSurface *>(this)->pathCurveHandle = | |||
| 18326 | parsedPathCurveHandle; | |||
| 18327 | *sourceBuf = handleProbe; | |||
| 18328 | return true; | |||
| 18329 | } | |||
| 18330 | ||||
| 18331 | bool DRW_Surface::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, | |||
| 18332 | dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 18333 | (void)bs; | |||
| 18334 | if (buf == nullptr || version < DRW::AC1021 || dwgClassNum == 0) | |||
| 18335 | return false; | |||
| 18336 | ||||
| 18337 | const auto validBitShort = [](int value) { | |||
| 18338 | return value >= 0 | |||
| 18339 | && value <= std::numeric_limits<std::uint16_t>::max(); | |||
| 18340 | }; | |||
| 18341 | const auto validCount = [](std::int32_t value, std::size_t limit) { | |||
| 18342 | return value >= 0 && static_cast<std::size_t>(value) <= limit; | |||
| 18343 | }; | |||
| 18344 | const auto validTypedPayload = [&]() { | |||
| 18345 | if (!acisEmpty && !rawAcisData.empty()) | |||
| 18346 | return false; | |||
| 18347 | if (surfaceHasModelerFormatVersion(eType) | |||
| 18348 | && (!validBitShort(modelerFormatVersion) | |||
| 18349 | || (eType == DRW::LOFTEDSURFACE | |||
| 18350 | && modelerFormatVersion | |||
| 18351 | > surfaceModelerFormatVersionLimit(eType)))) | |||
| 18352 | return false; | |||
| 18353 | if (!validBitShort(uIsolines) || !validBitShort(vIsolines)) | |||
| 18354 | return false; | |||
| 18355 | ||||
| 18356 | switch (eType) { | |||
| 18357 | case DRW::EXTRUDEDSURFACE: { | |||
| 18358 | const auto *surface = static_cast<const DRW_ExtrudedSurface *>(this); | |||
| 18359 | return std::isfinite(surface->draftAngle) | |||
| 18360 | && std::isfinite(surface->draftStartDistance) | |||
| 18361 | && std::isfinite(surface->draftEndDistance) | |||
| 18362 | && std::isfinite(surface->twistAngle) | |||
| 18363 | && std::isfinite(surface->scaleFactor) | |||
| 18364 | && std::isfinite(surface->alignAngle) | |||
| 18365 | && finiteSurfaceCoord(surface->referenceVector) | |||
| 18366 | && finiteSurfaceCoord(surface->sweepVector) | |||
| 18367 | && validBitShort(surface->sweepAlignmentFlags) | |||
| 18368 | && validBitShort(surface->pathFlags) | |||
| 18369 | && finiteSurfaceMatrix(surface->extrudedTransform) | |||
| 18370 | && finiteSurfaceMatrix(surface->sweepEntityTransform) | |||
| 18371 | && finiteSurfaceMatrix(surface->pathEntityTransform); | |||
| 18372 | } | |||
| 18373 | case DRW::LOFTEDSURFACE: { | |||
| 18374 | const auto *surface = static_cast<const DRW_LoftedSurface *>(this); | |||
| 18375 | return std::isfinite(surface->startDraftAngle) | |||
| 18376 | && std::isfinite(surface->endDraftAngle) | |||
| 18377 | && std::isfinite(surface->startDraftMagnitude) | |||
| 18378 | && std::isfinite(surface->endDraftMagnitude) | |||
| 18379 | && validCount(surface->numCrossSections, | |||
| 18380 | DRW_LoftedSurface::kMaxReferenceTokenCount) | |||
| 18381 | && validCount(surface->numGuideCurves, | |||
| 18382 | DRW_LoftedSurface::kMaxReferenceTokenCount) | |||
| 18383 | && surface->crossSectionHandles.size() | |||
| 18384 | == static_cast<std::size_t>(surface->numCrossSections) | |||
| 18385 | && surface->guideCurveHandles.size() | |||
| 18386 | == static_cast<std::size_t>(surface->numGuideCurves) | |||
| 18387 | && finiteSurfaceMatrix(surface->loftEntityTransform); | |||
| 18388 | } | |||
| 18389 | case DRW::REVOLVEDSURFACE: { | |||
| 18390 | const auto *surface = static_cast<const DRW_RevolvedSurface *>(this); | |||
| 18391 | return surface->classId <= std::numeric_limits<std::int32_t>::max() | |||
| 18392 | && surface->id <= std::numeric_limits<std::int32_t>::max() | |||
| 18393 | && finiteSurfaceCoord(surface->axisPoint) | |||
| 18394 | && finiteSurfaceCoord(surface->axisVector) | |||
| 18395 | && std::isfinite(surface->revolveAngle) | |||
| 18396 | && std::isfinite(surface->startAngle) | |||
| 18397 | && std::isfinite(surface->draftAngle) | |||
| 18398 | && std::isfinite(surface->draftStartDistance) | |||
| 18399 | && std::isfinite(surface->draftEndDistance) | |||
| 18400 | && std::isfinite(surface->twistAngle) | |||
| 18401 | && finiteSurfaceMatrix(surface->transform); | |||
| 18402 | } | |||
| 18403 | case DRW::SWEPTSURFACE: { | |||
| 18404 | const auto *surface = static_cast<const DRW_SweptSurface *>(this); | |||
| 18405 | return surface->classVersion <= 10 | |||
| 18406 | && surface->sweepEntityId | |||
| 18407 | <= std::numeric_limits<std::int32_t>::max() | |||
| 18408 | && surface->pathEntityId | |||
| 18409 | <= std::numeric_limits<std::int32_t>::max() | |||
| 18410 | && surface->sweepData.size() | |||
| 18411 | <= DRW_SweptSurface::kMaxSweepDataSize | |||
| 18412 | && surface->pathData.size() | |||
| 18413 | <= DRW_SweptSurface::kMaxSweepDataSize | |||
| 18414 | && std::isfinite(surface->draftAngle) | |||
| 18415 | && std::isfinite(surface->draftStartDistance) | |||
| 18416 | && std::isfinite(surface->draftEndDistance) | |||
| 18417 | && std::isfinite(surface->twistAngle) | |||
| 18418 | && std::isfinite(surface->scaleFactor) | |||
| 18419 | && std::isfinite(surface->alignAngle) | |||
| 18420 | && finiteSurfaceCoord(surface->referenceVector) | |||
| 18421 | && validBitShort(surface->sweepAlignmentFlags) | |||
| 18422 | && validBitShort(surface->pathFlags) | |||
| 18423 | && finiteSurfaceMatrix(surface->sweepEntityTransform) | |||
| 18424 | && finiteSurfaceMatrix(surface->pathEntityTransform); | |||
| 18425 | } | |||
| 18426 | case DRW::NURBSURFACE: | |||
| 18427 | if (version < DRW::AC1027) | |||
| 18428 | return true; | |||
| 18429 | { | |||
| 18430 | const auto *surface = static_cast<const DRW_NurbsSurface *>(this); | |||
| 18431 | return finiteSurfaceCoord(surface->uvec1) | |||
| 18432 | && finiteSurfaceCoord(surface->vvec1) | |||
| 18433 | && finiteSurfaceCoord(surface->uvec2) | |||
| 18434 | && finiteSurfaceCoord(surface->vvec2); | |||
| 18435 | } | |||
| 18436 | case DRW::PLANESURFACE: | |||
| 18437 | return true; | |||
| 18438 | default: | |||
| 18439 | return false; | |||
| 18440 | } | |||
| 18441 | }; | |||
| 18442 | ||||
| 18443 | if (hasRawDwgBody && rawDwgBodyVersion == version) { | |||
| 18444 | if (rawDwgBodyBitSize == 0 | |||
| 18445 | || rawDwgBodyBitSize > surfaceRawBitCapacity(rawAcisData)) | |||
| 18446 | return false; | |||
| 18447 | } else if (!validTypedPayload()) { | |||
| 18448 | return false; | |||
| 18449 | } | |||
| 18450 | if (!encodeDwgCommon(version, buf, strBuf)) | |||
| 18451 | return false; | |||
| 18452 | ||||
| 18453 | if (hasRawDwgBody && rawDwgBodyVersion == version) { | |||
| 18454 | if (!putSurfaceRawBits(buf, rawAcisData, rawDwgBodyBitSize)) | |||
| 18455 | return false; | |||
| 18456 | } else { | |||
| 18457 | // DXF ACIS/SAB bytes are not the bit-packed DWG ACTION_3DSOLID body. | |||
| 18458 | // Do not place them directly into a DWG object. Native ACIS emission | |||
| 18459 | // remains a separate conversion step; empty modeler bodies are valid | |||
| 18460 | // and allow metadata-only surfaces to round-trip safely. | |||
| 18461 | if (!acisEmpty && !rawAcisData.empty()) | |||
| 18462 | return false; | |||
| 18463 | buf->putBit(1); // ACTION_3DSOLID: no ACIS body | |||
| 18464 | ||||
| 18465 | const bool hasModelerFormat = surfaceHasModelerFormatVersion(eType); | |||
| 18466 | if (hasModelerFormat) { | |||
| 18467 | if (modelerFormatVersion < 0 | |||
| 18468 | || modelerFormatVersion > 0xFFFF | |||
| 18469 | || (eType == DRW::LOFTEDSURFACE && modelerFormatVersion > 3)) | |||
| 18470 | return false; | |||
| 18471 | buf->putBitShort(static_cast<std::uint16_t>(modelerFormatVersion)); | |||
| 18472 | } | |||
| 18473 | if (uIsolines < 0 || uIsolines > 0xFFFF | |||
| 18474 | || vIsolines < 0 || vIsolines > 0xFFFF) | |||
| 18475 | return false; | |||
| 18476 | buf->putBitShort(static_cast<std::uint16_t>(uIsolines)); | |||
| 18477 | buf->putBitShort(static_cast<std::uint16_t>(vIsolines)); | |||
| 18478 | ||||
| 18479 | auto putCoord = [&](const DRW_Coord& value) { | |||
| 18480 | if (!finiteSurfaceCoord(value)) | |||
| 18481 | return false; | |||
| 18482 | buf->put3BitDouble(value); | |||
| 18483 | return true; | |||
| 18484 | }; | |||
| 18485 | auto putBool = [&](bool value) { buf->putBit(value ? 1 : 0); }; | |||
| 18486 | auto putCount = [&](std::int32_t value, std::size_t limit) { | |||
| 18487 | return value >= 0 && static_cast<std::size_t>(value) <= limit; | |||
| 18488 | }; | |||
| 18489 | ||||
| 18490 | switch (eType) { | |||
| 18491 | case DRW::EXTRUDEDSURFACE: { | |||
| 18492 | const auto *surface = static_cast<const DRW_ExtrudedSurface *>(this); | |||
| 18493 | if (!std::isfinite(surface->draftAngle) | |||
| 18494 | || !std::isfinite(surface->draftStartDistance) | |||
| 18495 | || !std::isfinite(surface->draftEndDistance) | |||
| 18496 | || !std::isfinite(surface->twistAngle) | |||
| 18497 | || !std::isfinite(surface->scaleFactor) | |||
| 18498 | || !std::isfinite(surface->alignAngle) | |||
| 18499 | || !finiteSurfaceCoord(surface->referenceVector) | |||
| 18500 | || !finiteSurfaceCoord(surface->sweepVector) | |||
| 18501 | || surface->sweepAlignmentFlags < 0 | |||
| 18502 | || surface->sweepAlignmentFlags > 0xFFFF | |||
| 18503 | || surface->pathFlags < 0 || surface->pathFlags > 0xFFFF | |||
| 18504 | || !finiteSurfaceMatrix(surface->sweepEntityTransform) | |||
| 18505 | || !finiteSurfaceMatrix(surface->pathEntityTransform)) | |||
| 18506 | return false; | |||
| 18507 | buf->putBitDouble(surface->draftAngle); | |||
| 18508 | buf->putBitDouble(surface->draftStartDistance); | |||
| 18509 | buf->putBitDouble(surface->draftEndDistance); | |||
| 18510 | buf->putBitDouble(surface->twistAngle); | |||
| 18511 | buf->putBitDouble(surface->scaleFactor); | |||
| 18512 | buf->putBitDouble(surface->alignAngle); | |||
| 18513 | // The matrices were validated above; emit them in their specified | |||
| 18514 | // position after SweepOptions' scalar fields. | |||
| 18515 | for (double value : surface->sweepEntityTransform) | |||
| 18516 | buf->putBitDouble(value); | |||
| 18517 | for (double value : surface->pathEntityTransform) | |||
| 18518 | buf->putBitDouble(value); | |||
| 18519 | putBool(surface->solid); | |||
| 18520 | buf->putBitShort(static_cast<std::uint16_t>(surface->sweepAlignmentFlags)); | |||
| 18521 | buf->putBitShort(static_cast<std::uint16_t>(surface->pathFlags)); | |||
| 18522 | putBool(surface->alignStart); | |||
| 18523 | putBool(surface->bank); | |||
| 18524 | putBool(surface->basePointSet); | |||
| 18525 | putBool(surface->sweepEntityTransformComputed); | |||
| 18526 | putBool(surface->pathEntityTransformComputed); | |||
| 18527 | if (!finiteSurfaceCoord(surface->referenceVector) | |||
| 18528 | || !finiteSurfaceCoord(surface->sweepVector) | |||
| 18529 | || !finiteSurfaceMatrix(surface->extrudedTransform)) | |||
| 18530 | return false; | |||
| 18531 | putCoord(surface->referenceVector); | |||
| 18532 | putCoord(surface->sweepVector); | |||
| 18533 | for (double value : surface->extrudedTransform) | |||
| 18534 | buf->putBitDouble(value); | |||
| 18535 | break; | |||
| 18536 | } | |||
| 18537 | case DRW::LOFTEDSURFACE: { | |||
| 18538 | const auto *surface = static_cast<const DRW_LoftedSurface *>(this); | |||
| 18539 | if (!std::isfinite(surface->startDraftAngle) | |||
| 18540 | || !std::isfinite(surface->endDraftAngle) | |||
| 18541 | || !std::isfinite(surface->startDraftMagnitude) | |||
| 18542 | || !std::isfinite(surface->endDraftMagnitude) | |||
| 18543 | || !putCount(surface->numCrossSections, | |||
| 18544 | DRW_LoftedSurface::kMaxReferenceTokenCount) | |||
| 18545 | || !putCount(surface->numGuideCurves, | |||
| 18546 | DRW_LoftedSurface::kMaxReferenceTokenCount) | |||
| 18547 | || !finiteSurfaceMatrix(surface->loftEntityTransform)) | |||
| 18548 | return false; | |||
| 18549 | for (double value : surface->loftEntityTransform) | |||
| 18550 | buf->putBitDouble(value); | |||
| 18551 | buf->putBitLong(surface->planeNormalLoftingType); | |||
| 18552 | buf->putBitDouble(surface->startDraftAngle); | |||
| 18553 | buf->putBitDouble(surface->endDraftAngle); | |||
| 18554 | buf->putBitDouble(surface->startDraftMagnitude); | |||
| 18555 | buf->putBitDouble(surface->endDraftMagnitude); | |||
| 18556 | putBool(surface->arcLengthParameterization); | |||
| 18557 | putBool(surface->noTwist); | |||
| 18558 | putBool(surface->alignDirection); | |||
| 18559 | putBool(surface->simpleSurfaces); | |||
| 18560 | putBool(surface->closedSurfaces); | |||
| 18561 | putBool(surface->solid); | |||
| 18562 | putBool(surface->ruledSurface); | |||
| 18563 | putBool(surface->virtualGuide); | |||
| 18564 | buf->putBitShort(static_cast<std::uint16_t>(surface->numCrossSections)); | |||
| 18565 | buf->putBitShort(static_cast<std::uint16_t>(surface->numGuideCurves)); | |||
| 18566 | break; | |||
| 18567 | } | |||
| 18568 | case DRW::REVOLVEDSURFACE: { | |||
| 18569 | const auto *surface = static_cast<const DRW_RevolvedSurface *>(this); | |||
| 18570 | if (surface->classId > std::numeric_limits<std::int32_t>::max() | |||
| 18571 | || surface->id > std::numeric_limits<std::int32_t>::max() | |||
| 18572 | || !finiteSurfaceCoord(surface->axisPoint) | |||
| 18573 | || !finiteSurfaceCoord(surface->axisVector) | |||
| 18574 | || !std::isfinite(surface->revolveAngle) | |||
| 18575 | || !std::isfinite(surface->startAngle) | |||
| 18576 | || !std::isfinite(surface->draftAngle) | |||
| 18577 | || !std::isfinite(surface->draftStartDistance) | |||
| 18578 | || !std::isfinite(surface->draftEndDistance) | |||
| 18579 | || !std::isfinite(surface->twistAngle) | |||
| 18580 | || !finiteSurfaceMatrix(surface->transform)) | |||
| 18581 | return false; | |||
| 18582 | buf->putBitLong(static_cast<std::int32_t>(surface->classId)); | |||
| 18583 | buf->putBitLong(static_cast<std::int32_t>(surface->id)); | |||
| 18584 | buf->put3BitDouble(surface->axisPoint); | |||
| 18585 | buf->put3BitDouble(surface->axisVector); | |||
| 18586 | buf->putBitDouble(surface->revolveAngle); | |||
| 18587 | buf->putBitDouble(surface->startAngle); | |||
| 18588 | for (double value : surface->transform) | |||
| 18589 | buf->putBitDouble(value); | |||
| 18590 | buf->putBitDouble(surface->draftAngle); | |||
| 18591 | buf->putBitDouble(surface->draftStartDistance); | |||
| 18592 | buf->putBitDouble(surface->draftEndDistance); | |||
| 18593 | buf->putBitDouble(surface->twistAngle); | |||
| 18594 | putBool(surface->solid); | |||
| 18595 | putBool(surface->closeToAxis); | |||
| 18596 | break; | |||
| 18597 | } | |||
| 18598 | case DRW::SWEPTSURFACE: { | |||
| 18599 | const auto *surface = static_cast<const DRW_SweptSurface *>(this); | |||
| 18600 | if (surface->classVersion > 10 | |||
| 18601 | || surface->sweepEntityId > std::numeric_limits<std::int32_t>::max() | |||
| 18602 | || surface->pathEntityId > std::numeric_limits<std::int32_t>::max() | |||
| 18603 | || surface->sweepData.size() > DRW_SweptSurface::kMaxSweepDataSize | |||
| 18604 | || surface->pathData.size() > DRW_SweptSurface::kMaxSweepDataSize | |||
| 18605 | || !std::isfinite(surface->draftAngle) | |||
| 18606 | || !std::isfinite(surface->draftStartDistance) | |||
| 18607 | || !std::isfinite(surface->draftEndDistance) | |||
| 18608 | || !std::isfinite(surface->twistAngle) | |||
| 18609 | || !std::isfinite(surface->scaleFactor) | |||
| 18610 | || !std::isfinite(surface->alignAngle) | |||
| 18611 | || !finiteSurfaceCoord(surface->referenceVector) | |||
| 18612 | || surface->sweepAlignmentFlags < 0 | |||
| 18613 | || surface->sweepAlignmentFlags > 0xFFFF | |||
| 18614 | || surface->pathFlags < 0 || surface->pathFlags > 0xFFFF | |||
| 18615 | || !finiteSurfaceMatrix(surface->sweepEntityTransform) | |||
| 18616 | || !finiteSurfaceMatrix(surface->pathEntityTransform)) | |||
| 18617 | return false; | |||
| 18618 | buf->putBitLong(static_cast<std::int32_t>(surface->classVersion)); | |||
| 18619 | buf->putBitLong(static_cast<std::int32_t>(surface->sweepEntityId)); | |||
| 18620 | buf->putBitLong(static_cast<std::int32_t>(surface->sweepData.size())); | |||
| 18621 | if (!surface->sweepData.empty()) | |||
| 18622 | buf->putBytes(surface->sweepData.data(), surface->sweepData.size()); | |||
| 18623 | buf->putBitLong(static_cast<std::int32_t>(surface->pathEntityId)); | |||
| 18624 | buf->putBitLong(static_cast<std::int32_t>(surface->pathData.size())); | |||
| 18625 | if (!surface->pathData.empty()) | |||
| 18626 | buf->putBytes(surface->pathData.data(), surface->pathData.size()); | |||
| 18627 | buf->putBitDouble(surface->draftAngle); | |||
| 18628 | buf->putBitDouble(surface->draftStartDistance); | |||
| 18629 | buf->putBitDouble(surface->draftEndDistance); | |||
| 18630 | buf->putBitDouble(surface->twistAngle); | |||
| 18631 | buf->putBitDouble(surface->scaleFactor); | |||
| 18632 | buf->putBitDouble(surface->alignAngle); | |||
| 18633 | for (double value : surface->sweepEntityTransform) | |||
| 18634 | buf->putBitDouble(value); | |||
| 18635 | for (double value : surface->pathEntityTransform) | |||
| 18636 | buf->putBitDouble(value); | |||
| 18637 | putBool(surface->solid); | |||
| 18638 | buf->putBitShort(static_cast<std::uint16_t>(surface->sweepAlignmentFlags)); | |||
| 18639 | buf->putBitShort(static_cast<std::uint16_t>(surface->pathFlags)); | |||
| 18640 | putBool(surface->alignStart); | |||
| 18641 | putBool(surface->bank); | |||
| 18642 | putBool(surface->basePointSet); | |||
| 18643 | putBool(surface->sweepEntityTransformComputed); | |||
| 18644 | putBool(surface->pathEntityTransformComputed); | |||
| 18645 | if (!finiteSurfaceCoord(surface->referenceVector)) | |||
| 18646 | return false; | |||
| 18647 | putCoord(surface->referenceVector); | |||
| 18648 | break; | |||
| 18649 | } | |||
| 18650 | case DRW::NURBSURFACE: { | |||
| 18651 | if (version < DRW::AC1027) | |||
| 18652 | break; | |||
| 18653 | const auto *surface = static_cast<const DRW_NurbsSurface *>(this); | |||
| 18654 | if (!finiteSurfaceCoord(surface->uvec1) | |||
| 18655 | || !finiteSurfaceCoord(surface->vvec1) | |||
| 18656 | || !finiteSurfaceCoord(surface->uvec2) | |||
| 18657 | || !finiteSurfaceCoord(surface->vvec2)) | |||
| 18658 | return false; | |||
| 18659 | buf->putBitShort(surface->short170); | |||
| 18660 | putBool(surface->cvHullDisplay); | |||
| 18661 | buf->put3BitDouble(surface->uvec1); | |||
| 18662 | buf->put3BitDouble(surface->vvec1); | |||
| 18663 | buf->put3BitDouble(surface->uvec2); | |||
| 18664 | buf->put3BitDouble(surface->vvec2); | |||
| 18665 | break; | |||
| 18666 | } | |||
| 18667 | case DRW::PLANESURFACE: | |||
| 18668 | break; | |||
| 18669 | default: | |||
| 18670 | return false; | |||
| 18671 | } | |||
| 18672 | } | |||
| 18673 | ||||
| 18674 | if (!encodeDwgEntHandle(version, buf, handleBuf)) | |||
| 18675 | return false; | |||
| 18676 | if (eType == DRW::LOFTEDSURFACE) { | |||
| 18677 | dwgBufferW *hb = handleBuf != nullptr ? handleBuf : buf; | |||
| 18678 | for (std::uint32_t ref : crossSectionHandles) | |||
| 18679 | putSurfaceHandle(hb, ref); | |||
| 18680 | for (std::uint32_t ref : guideCurveHandles) | |||
| 18681 | putSurfaceHandle(hb, ref); | |||
| 18682 | putSurfaceHandle(hb, | |||
| 18683 | static_cast<const DRW_LoftedSurface *>(this) | |||
| 18684 | ->pathCurveHandle); | |||
| 18685 | } | |||
| 18686 | return true; | |||
| 18687 | } | |||
| 18688 | ||||
| 18689 | bool DRW_Dimension::parseCode(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 18690 | switch (code) { | |||
| 18691 | case 1: | |||
| 18692 | text = reader->getUtf8String(); | |||
| 18693 | break; | |||
| 18694 | case 2: | |||
| 18695 | name = reader->getString(); | |||
| 18696 | break; | |||
| 18697 | case 3: | |||
| 18698 | style = reader->getUtf8String(); | |||
| 18699 | break; | |||
| 18700 | case 70: | |||
| 18701 | type = reader->getInt32(); | |||
| 18702 | break; | |||
| 18703 | case 71: | |||
| 18704 | align = reader->getInt32(); | |||
| 18705 | break; | |||
| 18706 | case 72: | |||
| 18707 | linesty = reader->getInt32(); | |||
| 18708 | break; | |||
| 18709 | case 10: | |||
| 18710 | defPoint.x = reader->getDouble(); | |||
| 18711 | break; | |||
| 18712 | case 20: | |||
| 18713 | defPoint.y = reader->getDouble(); | |||
| 18714 | break; | |||
| 18715 | case 30: | |||
| 18716 | defPoint.z = reader->getDouble(); | |||
| 18717 | break; | |||
| 18718 | case 11: | |||
| 18719 | textPoint.x = reader->getDouble(); | |||
| 18720 | break; | |||
| 18721 | case 21: | |||
| 18722 | textPoint.y = reader->getDouble(); | |||
| 18723 | break; | |||
| 18724 | case 31: | |||
| 18725 | textPoint.z = reader->getDouble(); | |||
| 18726 | break; | |||
| 18727 | case 12: | |||
| 18728 | clonePoint.x = reader->getDouble(); | |||
| 18729 | break; | |||
| 18730 | case 22: | |||
| 18731 | clonePoint.y = reader->getDouble(); | |||
| 18732 | break; | |||
| 18733 | case 32: | |||
| 18734 | clonePoint.z = reader->getDouble(); | |||
| 18735 | break; | |||
| 18736 | case 13: | |||
| 18737 | def1.x = reader->getDouble(); | |||
| 18738 | break; | |||
| 18739 | case 23: | |||
| 18740 | def1.y = reader->getDouble(); | |||
| 18741 | break; | |||
| 18742 | case 33: | |||
| 18743 | def1.z = reader->getDouble(); | |||
| 18744 | break; | |||
| 18745 | case 14: | |||
| 18746 | def2.x = reader->getDouble(); | |||
| 18747 | break; | |||
| 18748 | case 24: | |||
| 18749 | def2.y = reader->getDouble(); | |||
| 18750 | break; | |||
| 18751 | case 34: | |||
| 18752 | def2.z = reader->getDouble(); | |||
| 18753 | break; | |||
| 18754 | case 15: | |||
| 18755 | circlePoint.x = reader->getDouble(); | |||
| 18756 | break; | |||
| 18757 | case 25: | |||
| 18758 | circlePoint.y = reader->getDouble(); | |||
| 18759 | break; | |||
| 18760 | case 35: | |||
| 18761 | circlePoint.z = reader->getDouble(); | |||
| 18762 | break; | |||
| 18763 | case 16: | |||
| 18764 | arcPoint.x = reader->getDouble(); | |||
| 18765 | break; | |||
| 18766 | case 26: | |||
| 18767 | arcPoint.y = reader->getDouble(); | |||
| 18768 | break; | |||
| 18769 | case 36: | |||
| 18770 | arcPoint.z = reader->getDouble(); | |||
| 18771 | break; | |||
| 18772 | case 41: | |||
| 18773 | linefactor = reader->getDouble(); | |||
| 18774 | break; | |||
| 18775 | case 53: | |||
| 18776 | rot = reader->getDouble(); | |||
| 18777 | break; | |||
| 18778 | case 50: | |||
| 18779 | angle = reader->getDouble(); | |||
| 18780 | break; | |||
| 18781 | case 52: | |||
| 18782 | oblique = reader->getDouble(); | |||
| 18783 | break; | |||
| 18784 | case 40: | |||
| 18785 | length = reader->getDouble(); | |||
| 18786 | break; | |||
| 18787 | case 51: | |||
| 18788 | hdir = reader->getDouble(); | |||
| 18789 | break; | |||
| 18790 | case 42: | |||
| 18791 | measureValue = reader->getDouble(); | |||
| 18792 | break; | |||
| 18793 | case 74: | |||
| 18794 | flipArrow1 = reader->getInt32() != 0; | |||
| 18795 | break; | |||
| 18796 | case 75: | |||
| 18797 | flipArrow2 = reader->getInt32() != 0; | |||
| 18798 | break; | |||
| 18799 | case 76: | |||
| 18800 | genTol = reader->getInt32() != 0; | |||
| 18801 | break; | |||
| 18802 | case 77: | |||
| 18803 | limGen = reader->getInt32() != 0; | |||
| 18804 | break; | |||
| 18805 | case 43: | |||
| 18806 | tolPlus = reader->getDouble(); | |||
| 18807 | break; | |||
| 18808 | case 44: | |||
| 18809 | tolMinus = reader->getDouble(); | |||
| 18810 | break; | |||
| 18811 | case 45: | |||
| 18812 | tolScale = reader->getDouble(); | |||
| 18813 | break; | |||
| 18814 | case 78: | |||
| 18815 | tolDecimals = reader->getInt32(); | |||
| 18816 | break; | |||
| 18817 | case 79: | |||
| 18818 | tolAlign = reader->getInt32(); | |||
| 18819 | break; | |||
| 18820 | case 80: | |||
| 18821 | tolZero = reader->getInt32(); | |||
| 18822 | break; | |||
| 18823 | case 81: | |||
| 18824 | altTolDecimals = reader->getInt32(); | |||
| 18825 | break; | |||
| 18826 | case 82: | |||
| 18827 | altZero = reader->getInt32(); | |||
| 18828 | break; | |||
| 18829 | case 83: | |||
| 18830 | altTolZero = reader->getInt32(); | |||
| 18831 | break; | |||
| 18832 | case 84: | |||
| 18833 | textMove = reader->getInt32(); | |||
| 18834 | break; | |||
| 18835 | default: | |||
| 18836 | return DRW_Entity::parseCode(code, reader); | |||
| 18837 | } | |||
| 18838 | ||||
| 18839 | return true; | |||
| 18840 | } | |||
| 18841 | ||||
| 18842 | bool DRW_Dimension::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs) | |||
| 18843 | { | |||
| 18844 | DRW_UNUSED( version)(void)version; | |||
| 18845 | DRW_UNUSED( buf)(void)buf; | |||
| 18846 | DRW_UNUSED( bs)(void)bs; | |||
| 18847 | ||||
| 18848 | DRW_DBG("DRW_Dimension::parseDwg(): base class implemntation should never be called direct!\n")DRW_dbg::dbg("DRW_Dimension::parseDwg(): base class implemntation should never be called direct!\n" ); | |||
| 18849 | ||||
| 18850 | return false; | |||
| 18851 | } | |||
| 18852 | ||||
| 18853 | void DRW_Dimension::resetDwgState() { | |||
| 18854 | DRW_Entity::reset(); | |||
| 18855 | type = 0; | |||
| 18856 | name.clear(); | |||
| 18857 | defPoint = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 18858 | textPoint = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 18859 | text.clear(); | |||
| 18860 | style = "STANDARD"; | |||
| 18861 | align = 5; | |||
| 18862 | linesty = 1; | |||
| 18863 | linefactor = 1.0; | |||
| 18864 | rot = 0.0; | |||
| 18865 | extPoint = DRW_Coord{0.0, 0.0, 1.0}; | |||
| 18866 | hdir = 0.0; | |||
| 18867 | clonePoint = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 18868 | def1 = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 18869 | def2 = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 18870 | angle = 0.0; | |||
| 18871 | oblique = 0.0; | |||
| 18872 | circlePoint = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 18873 | arcPoint = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 18874 | length = 0.0; | |||
| 18875 | measureValue = 0.0; | |||
| 18876 | flipArrow1 = false; | |||
| 18877 | flipArrow2 = false; | |||
| 18878 | genTol = false; | |||
| 18879 | limGen = false; | |||
| 18880 | tolPlus = 0.0; | |||
| 18881 | tolMinus = 0.0; | |||
| 18882 | tolScale = 0.0; | |||
| 18883 | tolDecimals = 0; | |||
| 18884 | tolAlign = 0; | |||
| 18885 | tolZero = 0; | |||
| 18886 | altTolDecimals = 0; | |||
| 18887 | altZero = 0; | |||
| 18888 | altTolZero = 0; | |||
| 18889 | textMove = 0; | |||
| 18890 | dimStyleH = dwgHandle{}; | |||
| 18891 | blockH = dwgHandle{}; | |||
| 18892 | } | |||
| 18893 | ||||
| 18894 | bool DRW_Dimension::parseDwg(DRW::Version version, dwgBuffer *buf, dwgBuffer *sBuf, std::uint32_t bs /*= 0*/) { | |||
| 18895 | (void)sBuf; | |||
| 18896 | resetDwgState(); | |||
| 18897 | if (buf == nullptr) | |||
| 18898 | return false; | |||
| 18899 | ||||
| 18900 | dwgBuffer sBuff = *buf; | |||
| 18901 | dwgBuffer *commonStringBuffer = buf; | |||
| 18902 | if (version > DRW::AC1018) {//2007+ | |||
| 18903 | commonStringBuffer = &sBuff; //separate buffer for strings | |||
| 18904 | } | |||
| 18905 | ||||
| 18906 | if (!DRW_Entity::parseDwg(version, buf, commonStringBuffer, bs)) | |||
| 18907 | return false; | |||
| 18908 | ||||
| 18909 | DRW_DBG("\n***************************** parsing dimension *********************************************")DRW_dbg::dbg("\n***************************** parsing dimension *********************************************" ); | |||
| 18910 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 18911 | dwgBuffer bodyProbe = buf->forkIndependent(); | |||
| 18912 | dwgBuffer stringProbe = sBuff; | |||
| 18913 | dwgBuffer *textBuffer = &bodyProbe; | |||
| 18914 | if (version > DRW::AC1018) | |||
| 18915 | textBuffer = &stringProbe; | |||
| 18916 | std::uint64_t stringStartBit = bodyEndBit; | |||
| 18917 | std::uint64_t stringEndBit = bodyEndBit; | |||
| 18918 | if (version > DRW::AC1018) { | |||
| 18919 | stringStartBit = currentDwgBit(textBuffer); | |||
| 18920 | if (version > DRW::AC1021) { | |||
| 18921 | std::uint64_t ignoredBodyEndBit = 0; | |||
| 18922 | if (!entityBodyDataEndBit(*textBuffer, version, objSize, | |||
| 18923 | ignoredBodyEndBit, &stringEndBit)) | |||
| 18924 | return false; | |||
| 18925 | } | |||
| 18926 | } | |||
| 18927 | ||||
| 18928 | std::uint8_t parsedDimVersion = 0; | |||
| 18929 | if (version > DRW::AC1021) { //2010+ | |||
| 18930 | if (!readBoundedRawChar8(bodyProbe, bodyEndBit, parsedDimVersion)) | |||
| 18931 | return false; | |||
| 18932 | DRW_DBG("\ndimVersion: ")DRW_dbg::dbg("\ndimVersion: "); DRW_DBG(parsedDimVersion)DRW_dbg::dbg(parsedDimVersion); | |||
| 18933 | } | |||
| 18934 | ||||
| 18935 | DRW_Coord parsedExtrusion; | |||
| 18936 | DRW_Coord parsedTextPoint; | |||
| 18937 | DRW_Coord ignoredInsertionPoint; | |||
| 18938 | double parsedTextPointZ = 0.0; | |||
| 18939 | double ignoredInsertionRotation = 0.0; | |||
| 18940 | std::uint8_t parsedType = 0; | |||
| 18941 | if (!readBoundedBitCoord(bodyProbe, bodyEndBit, parsedExtrusion) | |||
| 18942 | || !readBoundedRawDouble(bodyProbe, bodyEndBit, parsedTextPoint.x) | |||
| 18943 | || !readBoundedRawDouble(bodyProbe, bodyEndBit, parsedTextPoint.y) | |||
| 18944 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, parsedTextPointZ) | |||
| 18945 | || !readBoundedRawChar8(bodyProbe, bodyEndBit, parsedType)) { | |||
| 18946 | return false; | |||
| 18947 | } | |||
| 18948 | parsedTextPoint.z = parsedTextPointZ; | |||
| 18949 | ||||
| 18950 | // ODA §20.4.22: Extrusion is plain 3BD (NOT BE) — confirmed by libreDWG dwg_spec_shared.h | |||
| 18951 | DRW_DBG("\nextPoint: ")DRW_dbg::dbg("\nextPoint: "); DRW_DBGPT(parsedExtrusion.x, parsedExtrusion.y,DRW_dbg::dbgPT(parsedExtrusion.x, parsedExtrusion.y, parsedExtrusion .z) | |||
| 18952 | parsedExtrusion.z)DRW_dbg::dbgPT(parsedExtrusion.x, parsedExtrusion.y, parsedExtrusion .z); | |||
| 18953 | DRW_DBG("\ntextPoint: ")DRW_dbg::dbg("\ntextPoint: "); DRW_DBGPT(parsedTextPoint.x, parsedTextPoint.y,DRW_dbg::dbgPT(parsedTextPoint.x, parsedTextPoint.y, parsedTextPoint .z) | |||
| 18954 | parsedTextPoint.z)DRW_dbg::dbgPT(parsedTextPoint.x, parsedTextPoint.y, parsedTextPoint .z); | |||
| 18955 | DRW_DBG("\ntype (70) read: ")DRW_dbg::dbg("\ntype (70) read: "); DRW_DBG(parsedType)DRW_dbg::dbg(parsedType); | |||
| 18956 | const std::uint8_t parsedDimensionType = | |||
| 18957 | static_cast<std::uint8_t>((parsedType & 1) ? parsedType & 0x7F | |||
| 18958 | : parsedType | 0x80); | |||
| 18959 | int parsedTypeValue = (parsedDimensionType & 2) ? parsedDimensionType | 0x20 | |||
| 18960 | : parsedDimensionType & 0xDF; | |||
| 18961 | DRW_DBG(" type (70) set: ")DRW_dbg::dbg(" type (70) set: "); DRW_DBG(parsedTypeValue)DRW_dbg::dbg(parsedTypeValue); | |||
| 18962 | //clear last 3 bits to set integer dim type | |||
| 18963 | parsedTypeValue &= 0xF8; | |||
| 18964 | UTF8STRINGstd::string parsedText; | |||
| 18965 | if (version > DRW::AC1018 && stringStartBit >= stringEndBit) { | |||
| 18966 | parsedText.clear(); | |||
| 18967 | } else if (!readBoundedVariableText(*textBuffer, stringEndBit, version, | |||
| 18968 | parsedText)) { | |||
| 18969 | return false; | |||
| 18970 | } | |||
| 18971 | DRW_DBG("\nforced dim text: ")DRW_dbg::dbg("\nforced dim text: "); DRW_DBG(parsedText.c_str())DRW_dbg::dbg(parsedText.c_str()); | |||
| 18972 | double parsedRot = 0.0; | |||
| 18973 | double parsedHDir = 0.0; | |||
| 18974 | if (!readBoundedBitDouble(bodyProbe, bodyEndBit, parsedRot) | |||
| 18975 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, parsedHDir) | |||
| 18976 | || !readBoundedBitCoord(bodyProbe, bodyEndBit, ignoredInsertionPoint) | |||
| 18977 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, | |||
| 18978 | ignoredInsertionRotation)) { | |||
| 18979 | return false; | |||
| 18980 | } | |||
| 18981 | DRW_DBG("\ninspoint: ")DRW_dbg::dbg("\ninspoint: "); DRW_DBGPT(ignoredInsertionPoint.x,DRW_dbg::dbgPT(ignoredInsertionPoint.x, ignoredInsertionPoint .y, ignoredInsertionPoint.z) | |||
| 18982 | ignoredInsertionPoint.y,DRW_dbg::dbgPT(ignoredInsertionPoint.x, ignoredInsertionPoint .y, ignoredInsertionPoint.z) | |||
| 18983 | ignoredInsertionPoint.z)DRW_dbg::dbgPT(ignoredInsertionPoint.x, ignoredInsertionPoint .y, ignoredInsertionPoint.z); | |||
| 18984 | DRW_DBG(" insRot_code54: ")DRW_dbg::dbg(" insRot_code54: "); DRW_DBG(ignoredInsertionRotation)DRW_dbg::dbg(ignoredInsertionRotation); | |||
| 18985 | ||||
| 18986 | std::uint16_t parsedAlign = 5; | |||
| 18987 | std::uint16_t parsedLineStyle = 1; | |||
| 18988 | double parsedLineFactor = 1.0; | |||
| 18989 | double parsedMeasureValue = 0.0; | |||
| 18990 | bool parsedFlipArrow1 = false; | |||
| 18991 | bool parsedFlipArrow2 = false; | |||
| 18992 | if (version > DRW::AC1014) { //2000+ | |||
| 18993 | if (!readBoundedBitShort(bodyProbe, bodyEndBit, parsedAlign) | |||
| 18994 | || !readBoundedBitShort(bodyProbe, bodyEndBit, parsedLineStyle) | |||
| 18995 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, parsedLineFactor) | |||
| 18996 | || !readBoundedBitDouble(bodyProbe, bodyEndBit, | |||
| 18997 | parsedMeasureValue)) | |||
| 18998 | return false; | |||
| 18999 | DRW_DBG("\n actMeas_code42: ")DRW_dbg::dbg("\n actMeas_code42: "); DRW_DBG(parsedMeasureValue)DRW_dbg::dbg(parsedMeasureValue); | |||
| 19000 | if (version > DRW::AC1018) { //2007+ | |||
| 19001 | bool ignoredBit = false; | |||
| 19002 | if (!readBoundedBit(bodyProbe, bodyEndBit, ignoredBit) | |||
| 19003 | || !readBoundedBit(bodyProbe, bodyEndBit, parsedFlipArrow1) | |||
| 19004 | || !readBoundedBit(bodyProbe, bodyEndBit, parsedFlipArrow2)) | |||
| 19005 | return false; | |||
| 19006 | DRW_DBG("\n2007, unk, flip1, flip2: ")DRW_dbg::dbg("\n2007, unk, flip1, flip2: "); DRW_DBG(ignoredBit)DRW_dbg::dbg(ignoredBit); | |||
| 19007 | DRW_DBG(parsedFlipArrow1)DRW_dbg::dbg(parsedFlipArrow1); DRW_DBG(parsedFlipArrow2)DRW_dbg::dbg(parsedFlipArrow2); | |||
| 19008 | } | |||
| 19009 | } | |||
| 19010 | DRW_Coord parsedClonePoint; | |||
| 19011 | if (!readBoundedRawDouble(bodyProbe, bodyEndBit, parsedClonePoint.x) | |||
| 19012 | || !readBoundedRawDouble(bodyProbe, bodyEndBit, parsedClonePoint.y)) | |||
| 19013 | return false; | |||
| 19014 | parsedClonePoint.z = 0.0; | |||
| 19015 | if (!bodyProbe.isGood() || !textBuffer->isGood() | |||
| 19016 | || currentDwgBit(&bodyProbe) > bodyEndBit | |||
| 19017 | || currentDwgBit(textBuffer) > stringEndBit | |||
| 19018 | || !std::isfinite(parsedExtrusion.x) | |||
| 19019 | || !std::isfinite(parsedExtrusion.y) | |||
| 19020 | || !std::isfinite(parsedExtrusion.z) | |||
| 19021 | || !std::isfinite(parsedTextPoint.x) | |||
| 19022 | || !std::isfinite(parsedTextPoint.y) | |||
| 19023 | || !std::isfinite(parsedTextPoint.z) | |||
| 19024 | || !std::isfinite(ignoredInsertionPoint.x) | |||
| 19025 | || !std::isfinite(ignoredInsertionPoint.y) | |||
| 19026 | || !std::isfinite(ignoredInsertionPoint.z) | |||
| 19027 | || !std::isfinite(parsedRot) | |||
| 19028 | || !std::isfinite(parsedHDir) | |||
| 19029 | || !std::isfinite(ignoredInsertionRotation) | |||
| 19030 | || !std::isfinite(parsedLineFactor) | |||
| 19031 | || !std::isfinite(parsedMeasureValue) | |||
| 19032 | || !std::isfinite(parsedClonePoint.x) | |||
| 19033 | || !std::isfinite(parsedClonePoint.y)) | |||
| 19034 | return false; | |||
| 19035 | ||||
| 19036 | extPoint = parsedExtrusion; | |||
| 19037 | textPoint = parsedTextPoint; | |||
| 19038 | type = parsedTypeValue; | |||
| 19039 | text = parsedText; | |||
| 19040 | rot = parsedRot; | |||
| 19041 | hdir = parsedHDir; | |||
| 19042 | align = parsedAlign; | |||
| 19043 | linesty = parsedLineStyle; | |||
| 19044 | linefactor = parsedLineFactor; | |||
| 19045 | measureValue = parsedMeasureValue; | |||
| 19046 | flipArrow1 = parsedFlipArrow1; | |||
| 19047 | flipArrow2 = parsedFlipArrow2; | |||
| 19048 | clonePoint = parsedClonePoint; | |||
| 19049 | *buf = bodyProbe; | |||
| 19050 | return true; | |||
| 19051 | } | |||
| 19052 | ||||
| 19053 | bool DRW_Dimension::parseDwgDimensionHandles(DRW::Version version, | |||
| 19054 | dwgBuffer *buf, | |||
| 19055 | std::uint64_t handleEndBit) { | |||
| 19056 | if (buf == nullptr) | |||
| 19057 | return false; | |||
| 19058 | dwgBuffer probe = buf->forkIndependent(); | |||
| 19059 | if (!parseDwgEntHandle(version, &probe, true, handleEndBit)) | |||
| 19060 | return false; | |||
| 19061 | dwgHandle parsedDimStyle; | |||
| 19062 | dwgHandle parsedBlock; | |||
| 19063 | if (!readBoundedDwgHandle(probe, handleEndBit, 0, false, parsedDimStyle) | |||
| 19064 | || !readBoundedDwgHandle(probe, handleEndBit, 0, false, parsedBlock)) | |||
| 19065 | return false; | |||
| 19066 | dimStyleH = parsedDimStyle; | |||
| 19067 | blockH = parsedBlock; | |||
| 19068 | *buf = probe; | |||
| 19069 | return true; | |||
| 19070 | } | |||
| 19071 | ||||
| 19072 | bool DRW_DimAligned::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){ | |||
| 19073 | DRW_Dimension::resetDwgState(); | |||
| 19074 | dwgBuffer *sourceBuf = buf; | |||
| 19075 | auto fail = [this, sourceBuf]() { | |||
| 19076 | if (sourceBuf != nullptr) | |||
| 19077 | sourceBuf->invalidate(); | |||
| 19078 | DRW_Dimension::resetDwgState(); | |||
| 19079 | return false; | |||
| 19080 | }; | |||
| 19081 | if (sourceBuf == nullptr) | |||
| 19082 | return fail(); | |||
| 19083 | ||||
| 19084 | dwgBuffer probe = sourceBuf->forkIndependent(); | |||
| 19085 | if (!DRW_Dimension::parseDwg(version, &probe, nullptr, bs)) | |||
| 19086 | return fail(); | |||
| 19087 | buf = &probe; | |||
| 19088 | ||||
| 19089 | if (oType == 0x15) | |||
| 19090 | DRW_DBG("\n***************************** parsing dim linear *********************************************\n")DRW_dbg::dbg("\n***************************** parsing dim linear *********************************************\n" ); | |||
| 19091 | else | |||
| 19092 | DRW_DBG("\n***************************** parsing dim aligned *********************************************\n")DRW_dbg::dbg("\n***************************** parsing dim aligned *********************************************\n" ); | |||
| 19093 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 19094 | DRW_Coord parsedDef1; | |||
| 19095 | DRW_Coord parsedDef2; | |||
| 19096 | DRW_Coord parsedDimPoint; | |||
| 19097 | double parsedOblique = 0.0; | |||
| 19098 | double parsedAngle = 0.0; | |||
| 19099 | if (!readBoundedBitCoord(*buf, bodyEndBit, parsedDef1) | |||
| 19100 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedDef2) | |||
| 19101 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedDimPoint) | |||
| 19102 | || !readBoundedBitDouble(*buf, bodyEndBit, parsedOblique)) | |||
| 19103 | return fail(); | |||
| 19104 | if (oType == 0x15 | |||
| 19105 | && !readBoundedBitDouble(*buf, bodyEndBit, parsedAngle)) | |||
| 19106 | return fail(); | |||
| 19107 | const auto finite = [](const DRW_Coord& point) { | |||
| 19108 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 19109 | && std::isfinite(point.z); | |||
| 19110 | }; | |||
| 19111 | if (!std::isfinite(parsedOblique) || !std::isfinite(parsedAngle) | |||
| 19112 | || !finite(parsedDef1) || !finite(parsedDef2) | |||
| 19113 | || !finite(parsedDimPoint)) { | |||
| 19114 | return fail(); | |||
| 19115 | } | |||
| 19116 | setPt3(parsedDef1); //def1 | |||
| 19117 | setPt4(parsedDef2); | |||
| 19118 | setDefPoint(parsedDimPoint); | |||
| 19119 | setOb52(parsedOblique * ARAD57.29577951308232); // radians → degrees | |||
| 19120 | if (oType == 0x15) | |||
| 19121 | setAn50(parsedAngle * ARAD57.29577951308232); | |||
| 19122 | else | |||
| 19123 | type |= 1; | |||
| 19124 | DRW_DBG("\n type (70) final: ")DRW_dbg::dbg("\n type (70) final: "); DRW_DBG(type)DRW_dbg::dbg(type); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 19125 | ||||
| 19126 | std::uint64_t handleEndBit = 0; | |||
| 19127 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, handleEndBit) | |||
| 19128 | || !parseDwgDimensionHandles(version, buf, handleEndBit)) { | |||
| 19129 | DRW_DBG("Failed: parseDwgEntHandle() in DRW_DimAligned::parseDwg()\n")DRW_dbg::dbg("Failed: parseDwgEntHandle() in DRW_DimAligned::parseDwg()\n" ); | |||
| 19130 | return fail(); | |||
| 19131 | } | |||
| 19132 | DRW_DBG("Remaining bytes: ")DRW_dbg::dbg("Remaining bytes: "); DRW_DBG(buf->numRemainingBytes())DRW_dbg::dbg(buf->numRemainingBytes()); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 19133 | DRW_DBG("Remaining bytes: ")DRW_dbg::dbg("Remaining bytes: "); DRW_DBG(buf->numRemainingBytes())DRW_dbg::dbg(buf->numRemainingBytes()); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 19134 | ||||
| 19135 | // RS crc; //RS */ | |||
| 19136 | if (!buf->isGood()) | |||
| 19137 | return fail(); | |||
| 19138 | *sourceBuf = probe; | |||
| 19139 | return true; | |||
| 19140 | } | |||
| 19141 | ||||
| 19142 | bool DRW_DimRadial::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){ | |||
| 19143 | DRW_Dimension::resetDwgState(); | |||
| 19144 | dwgBuffer *sourceBuf = buf; | |||
| 19145 | auto fail = [this, sourceBuf]() { | |||
| 19146 | if (sourceBuf != nullptr) | |||
| 19147 | sourceBuf->invalidate(); | |||
| 19148 | DRW_Dimension::resetDwgState(); | |||
| 19149 | return false; | |||
| 19150 | }; | |||
| 19151 | if (sourceBuf == nullptr) | |||
| 19152 | return fail(); | |||
| 19153 | ||||
| 19154 | dwgBuffer probe = sourceBuf->forkIndependent(); | |||
| 19155 | if (!DRW_Dimension::parseDwg(version, &probe, nullptr, bs)) | |||
| 19156 | return fail(); | |||
| 19157 | buf = &probe; | |||
| 19158 | ||||
| 19159 | DRW_DBG("\n***************************** parsing dim radial *********************************************\n")DRW_dbg::dbg("\n***************************** parsing dim radial *********************************************\n" ); | |||
| 19160 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 19161 | DRW_Coord parsedDefPoint; | |||
| 19162 | DRW_Coord parsedCenter; | |||
| 19163 | double parsedLength = 0.0; | |||
| 19164 | if (!readBoundedBitCoord(*buf, bodyEndBit, parsedDefPoint) | |||
| 19165 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedCenter) | |||
| 19166 | || !readBoundedBitDouble(*buf, bodyEndBit, parsedLength) | |||
| 19167 | || !std::isfinite(parsedDefPoint.x) | |||
| 19168 | || !std::isfinite(parsedDefPoint.y) | |||
| 19169 | || !std::isfinite(parsedDefPoint.z) | |||
| 19170 | || !std::isfinite(parsedCenter.x) | |||
| 19171 | || !std::isfinite(parsedCenter.y) | |||
| 19172 | || !std::isfinite(parsedCenter.z) | |||
| 19173 | || !std::isfinite(parsedLength)) | |||
| 19174 | return fail(); | |||
| 19175 | setDefPoint(parsedDefPoint); //code 10 | |||
| 19176 | DRW_DBG("defPoint: ")DRW_dbg::dbg("defPoint: "); DRW_DBGPT(parsedDefPoint.x, parsedDefPoint.y,DRW_dbg::dbgPT(parsedDefPoint.x, parsedDefPoint.y, parsedDefPoint .z) | |||
| 19177 | parsedDefPoint.z)DRW_dbg::dbgPT(parsedDefPoint.x, parsedDefPoint.y, parsedDefPoint .z); | |||
| 19178 | setPt5(parsedCenter); //center pt code 15 | |||
| 19179 | DRW_DBG("\ncenter point: ")DRW_dbg::dbg("\ncenter point: "); DRW_DBGPT(parsedCenter.x, parsedCenter.y,DRW_dbg::dbgPT(parsedCenter.x, parsedCenter.y, parsedCenter.z ) | |||
| 19180 | parsedCenter.z)DRW_dbg::dbgPT(parsedCenter.x, parsedCenter.y, parsedCenter.z ); | |||
| 19181 | setRa40(parsedLength); //leader length code 40 | |||
| 19182 | DRW_DBG("\nleader length: ")DRW_dbg::dbg("\nleader length: "); DRW_DBG(getRa40())DRW_dbg::dbg(getRa40()); | |||
| 19183 | type |= 4; | |||
| 19184 | DRW_DBG("\n type (70) final: ")DRW_dbg::dbg("\n type (70) final: "); DRW_DBG(type)DRW_dbg::dbg(type); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 19185 | if (!buf->isGood()) | |||
| 19186 | return fail(); | |||
| 19187 | ||||
| 19188 | std::uint64_t handleEndBit = 0; | |||
| 19189 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, handleEndBit) | |||
| 19190 | || !parseDwgDimensionHandles(version, buf, handleEndBit)) { | |||
| 19191 | DRW_DBG("Failed: parseDwgEntHandle() in DRW_DimRadial::parseDwg()\n")DRW_dbg::dbg("Failed: parseDwgEntHandle() in DRW_DimRadial::parseDwg()\n" ); | |||
| 19192 | return fail(); | |||
| 19193 | } | |||
| 19194 | DRW_DBG("Remaining bytes: ")DRW_dbg::dbg("Remaining bytes: "); DRW_DBG(buf->numRemainingBytes())DRW_dbg::dbg(buf->numRemainingBytes()); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 19195 | DRW_DBG("Remaining bytes: ")DRW_dbg::dbg("Remaining bytes: "); DRW_DBG(buf->numRemainingBytes())DRW_dbg::dbg(buf->numRemainingBytes()); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 19196 | ||||
| 19197 | // RS crc; //RS */ | |||
| 19198 | if (!buf->isGood()) | |||
| 19199 | return fail(); | |||
| 19200 | *sourceBuf = probe; | |||
| 19201 | return true; | |||
| 19202 | } | |||
| 19203 | ||||
| 19204 | // DRW_DimLargeRadial (AcDbRadialDimensionLarge, LARGE_RADIAL_DIMENSION). | |||
| 19205 | // DXF group-code parser: the AcDbRadialDimensionLarge subclass overloads codes | |||
| 19206 | // 13/14/15/40 (chord / override center / jog point / jog angle), so gate them on | |||
| 19207 | // the subclass marker (like DRW_DimArc). The chord point is stored as the radial | |||
| 19208 | // diameter point so the existing addDimRadial consumer renders center→chord. | |||
| 19209 | bool DRW_DimLargeRadial::parseCode(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 19210 | if (code == 100) { | |||
| 19211 | std::string s = reader->getString(); | |||
| 19212 | if (s == "AcDbRadialDimensionLarge") { | |||
| 19213 | m_largeRadialSubclassSeen = true; | |||
| 19214 | return true; | |||
| 19215 | } | |||
| 19216 | return DRW_Dimension::parseCode(code, reader); | |||
| 19217 | } | |||
| 19218 | if (m_largeRadialSubclassSeen) { | |||
| 19219 | DRW_Coord chord; | |||
| 19220 | switch (code) { | |||
| 19221 | case 13: chord = getPt5(); chord.x = reader->getDouble(); setPt5(chord); return true; | |||
| 19222 | case 23: chord = getPt5(); chord.y = reader->getDouble(); setPt5(chord); return true; | |||
| 19223 | case 33: chord = getPt5(); chord.z = reader->getDouble(); setPt5(chord); return true; | |||
| 19224 | case 14: overrideCenterPoint.x = reader->getDouble(); return true; | |||
| 19225 | case 24: overrideCenterPoint.y = reader->getDouble(); return true; | |||
| 19226 | case 34: overrideCenterPoint.z = reader->getDouble(); return true; | |||
| 19227 | case 15: jogPoint.x = reader->getDouble(); return true; | |||
| 19228 | case 25: jogPoint.y = reader->getDouble(); return true; | |||
| 19229 | case 35: jogPoint.z = reader->getDouble(); return true; | |||
| 19230 | case 40: jogAngle = reader->getDouble(); return true; | |||
| 19231 | default: break; | |||
| 19232 | } | |||
| 19233 | } | |||
| 19234 | return DRW_Dimension::parseCode(code, reader); | |||
| 19235 | } | |||
| 19236 | ||||
| 19237 | // DRW_DimLargeRadial DWG body: five subclass reads then the dim-style and | |||
| 19238 | // anon-block handles. The three subclass points are ordered | |||
| 19239 | // definition point, JOG point, jog angle, CHORD point, OVERRIDDEN center | |||
| 19240 | // so that the decoded fields match the DXF group codes (chord=13, override=14, | |||
| 19241 | // jog=15) and libdxfrw's own DXF parseCode. The read-only reference parser | |||
| 19242 | // (parseLargeRadialDimension) labels the 2nd/4th/5th reads chord/override/jog, | |||
| 19243 | // i.e. a cyclic rotation of the point roles; that is inconsistent with the DXF | |||
| 19244 | // semantics and with an ODA File Converter DXF↔DWG round-trip (which preserves | |||
| 19245 | // codes 13/14/15 exactly). Verified by large_radial_dim_dwg_tests.cpp against | |||
| 19246 | // an ODA-synthesized fixture, cross-checked with the dwg-parser's DXF read. | |||
| 19247 | // Only the field labels change vs. the reference parser — the read sizes/order | |||
| 19248 | // (3BD, 3BD, BD, 3BD, 3BD) are identical, so buffer alignment is unchanged. | |||
| 19249 | bool DRW_DimLargeRadial::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){ | |||
| 19250 | DRW_Dimension::resetDwgState(); | |||
| 19251 | overrideCenterPoint = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 19252 | jogPoint = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 19253 | jogAngle = 0.0; | |||
| 19254 | m_largeRadialSubclassSeen = false; | |||
| 19255 | dwgBuffer *sourceBuf = buf; | |||
| 19256 | auto fail = [this, sourceBuf]() { | |||
| 19257 | if (sourceBuf != nullptr) | |||
| 19258 | sourceBuf->invalidate(); | |||
| 19259 | DRW_Dimension::resetDwgState(); | |||
| 19260 | overrideCenterPoint = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 19261 | jogPoint = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 19262 | jogAngle = 0.0; | |||
| 19263 | m_largeRadialSubclassSeen = false; | |||
| 19264 | return false; | |||
| 19265 | }; | |||
| 19266 | if (sourceBuf == nullptr) | |||
| 19267 | return fail(); | |||
| 19268 | ||||
| 19269 | dwgBuffer probe = sourceBuf->forkIndependent(); | |||
| 19270 | if (!DRW_Dimension::parseDwg(version, &probe, nullptr, bs)) | |||
| 19271 | return fail(); | |||
| 19272 | buf = &probe; | |||
| 19273 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 19274 | DRW_Coord parsedDefPoint; | |||
| 19275 | DRW_Coord parsedJogPoint; | |||
| 19276 | DRW_Coord parsedChordPoint; | |||
| 19277 | DRW_Coord parsedOverrideCenter; | |||
| 19278 | double parsedJogAngle = 0.0; | |||
| 19279 | if (!readBoundedBitCoord(*buf, bodyEndBit, parsedDefPoint) | |||
| 19280 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedJogPoint) | |||
| 19281 | || !readBoundedBitDouble(*buf, bodyEndBit, parsedJogAngle) | |||
| 19282 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedChordPoint) | |||
| 19283 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedOverrideCenter) | |||
| 19284 | || !std::isfinite(parsedDefPoint.x) | |||
| 19285 | || !std::isfinite(parsedDefPoint.y) | |||
| 19286 | || !std::isfinite(parsedDefPoint.z) | |||
| 19287 | || !std::isfinite(parsedJogPoint.x) | |||
| 19288 | || !std::isfinite(parsedJogPoint.y) | |||
| 19289 | || !std::isfinite(parsedJogPoint.z) | |||
| 19290 | || !std::isfinite(parsedChordPoint.x) | |||
| 19291 | || !std::isfinite(parsedChordPoint.y) | |||
| 19292 | || !std::isfinite(parsedChordPoint.z) | |||
| 19293 | || !std::isfinite(parsedOverrideCenter.x) | |||
| 19294 | || !std::isfinite(parsedOverrideCenter.y) | |||
| 19295 | || !std::isfinite(parsedOverrideCenter.z) | |||
| 19296 | || !std::isfinite(parsedJogAngle)) | |||
| 19297 | return fail(); | |||
| 19298 | setDefPoint(parsedDefPoint); // definition point (code 10) | |||
| 19299 | jogPoint = parsedJogPoint; // jog vertex (code 15) | |||
| 19300 | jogAngle = parsedJogAngle; // jog transverse angle (code 40) | |||
| 19301 | setPt5(parsedChordPoint); // chord point (code 13) | |||
| 19302 | overrideCenterPoint = parsedOverrideCenter; // overridden center (code 14) | |||
| 19303 | type |= 4; // radial dimension type bit | |||
| 19304 | if (!buf->isGood()) | |||
| 19305 | return fail(); | |||
| 19306 | std::uint64_t handleEndBit = 0; | |||
| 19307 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, handleEndBit) | |||
| 19308 | || !parseDwgDimensionHandles(version, buf, handleEndBit)) { | |||
| 19309 | return fail(); | |||
| 19310 | } | |||
| 19311 | *sourceBuf = probe; | |||
| 19312 | return true; | |||
| 19313 | } | |||
| 19314 | ||||
| 19315 | bool DRW_DimDiametric::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){ | |||
| 19316 | DRW_Dimension::resetDwgState(); | |||
| 19317 | dwgBuffer *sourceBuf = buf; | |||
| 19318 | auto fail = [this, sourceBuf]() { | |||
| 19319 | if (sourceBuf != nullptr) | |||
| 19320 | sourceBuf->invalidate(); | |||
| 19321 | DRW_Dimension::resetDwgState(); | |||
| 19322 | return false; | |||
| 19323 | }; | |||
| 19324 | if (sourceBuf == nullptr) | |||
| 19325 | return fail(); | |||
| 19326 | ||||
| 19327 | dwgBuffer probe = sourceBuf->forkIndependent(); | |||
| 19328 | if (!DRW_Dimension::parseDwg(version, &probe, nullptr, bs)) | |||
| 19329 | return fail(); | |||
| 19330 | buf = &probe; | |||
| 19331 | ||||
| 19332 | DRW_DBG("\n***************************** parsing dim diametric *********************************************\n")DRW_dbg::dbg("\n***************************** parsing dim diametric *********************************************\n" ); | |||
| 19333 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 19334 | DRW_Coord parsedCenter; | |||
| 19335 | DRW_Coord parsedDefPoint; | |||
| 19336 | double parsedLength = 0.0; | |||
| 19337 | if (!readBoundedBitCoord(*buf, bodyEndBit, parsedCenter) | |||
| 19338 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedDefPoint) | |||
| 19339 | || !readBoundedBitDouble(*buf, bodyEndBit, parsedLength) | |||
| 19340 | || !std::isfinite(parsedCenter.x) | |||
| 19341 | || !std::isfinite(parsedCenter.y) | |||
| 19342 | || !std::isfinite(parsedCenter.z) | |||
| 19343 | || !std::isfinite(parsedDefPoint.x) | |||
| 19344 | || !std::isfinite(parsedDefPoint.y) | |||
| 19345 | || !std::isfinite(parsedDefPoint.z) | |||
| 19346 | || !std::isfinite(parsedLength)) | |||
| 19347 | return fail(); | |||
| 19348 | setPt5(parsedCenter); //center pt code 15 | |||
| 19349 | DRW_DBG("center point: ")DRW_dbg::dbg("center point: "); DRW_DBGPT(parsedCenter.x, parsedCenter.y,DRW_dbg::dbgPT(parsedCenter.x, parsedCenter.y, parsedCenter.z ) | |||
| 19350 | parsedCenter.z)DRW_dbg::dbgPT(parsedCenter.x, parsedCenter.y, parsedCenter.z ); | |||
| 19351 | setDefPoint(parsedDefPoint); //code 10 | |||
| 19352 | DRW_DBG("\ndefPoint: ")DRW_dbg::dbg("\ndefPoint: "); DRW_DBGPT(parsedDefPoint.x, parsedDefPoint.y,DRW_dbg::dbgPT(parsedDefPoint.x, parsedDefPoint.y, parsedDefPoint .z) | |||
| 19353 | parsedDefPoint.z)DRW_dbg::dbgPT(parsedDefPoint.x, parsedDefPoint.y, parsedDefPoint .z); | |||
| 19354 | setRa40(parsedLength); //leader length code 40 | |||
| 19355 | DRW_DBG("\nleader length: ")DRW_dbg::dbg("\nleader length: "); DRW_DBG(getRa40())DRW_dbg::dbg(getRa40()); | |||
| 19356 | type |= 3; | |||
| 19357 | DRW_DBG("\n type (70) final: ")DRW_dbg::dbg("\n type (70) final: "); DRW_DBG(type)DRW_dbg::dbg(type); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 19358 | if (!buf->isGood()) | |||
| 19359 | return fail(); | |||
| 19360 | ||||
| 19361 | std::uint64_t handleEndBit = 0; | |||
| 19362 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, handleEndBit) | |||
| 19363 | || !parseDwgDimensionHandles(version, buf, handleEndBit)) { | |||
| 19364 | DRW_DBG("Failed: parseDwgEntHandle() in DRW_DimDiametric::parseDwg()\n")DRW_dbg::dbg("Failed: parseDwgEntHandle() in DRW_DimDiametric::parseDwg()\n" ); | |||
| 19365 | return fail(); | |||
| 19366 | } | |||
| 19367 | DRW_DBG("Remaining bytes: ")DRW_dbg::dbg("Remaining bytes: "); DRW_DBG(buf->numRemainingBytes())DRW_dbg::dbg(buf->numRemainingBytes()); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 19368 | DRW_DBG("Remaining bytes: ")DRW_dbg::dbg("Remaining bytes: "); DRW_DBG(buf->numRemainingBytes())DRW_dbg::dbg(buf->numRemainingBytes()); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 19369 | ||||
| 19370 | // RS crc; //RS */ | |||
| 19371 | if (!buf->isGood()) | |||
| 19372 | return fail(); | |||
| 19373 | *sourceBuf = probe; | |||
| 19374 | return true; | |||
| 19375 | } | |||
| 19376 | ||||
| 19377 | bool DRW_DimAngular::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){ | |||
| 19378 | DRW_Dimension::resetDwgState(); | |||
| 19379 | dwgBuffer *sourceBuf = buf; | |||
| 19380 | auto fail = [this, sourceBuf]() { | |||
| 19381 | if (sourceBuf != nullptr) | |||
| 19382 | sourceBuf->invalidate(); | |||
| 19383 | DRW_Dimension::resetDwgState(); | |||
| 19384 | return false; | |||
| 19385 | }; | |||
| 19386 | if (sourceBuf == nullptr) | |||
| 19387 | return fail(); | |||
| 19388 | ||||
| 19389 | dwgBuffer probe = sourceBuf->forkIndependent(); | |||
| 19390 | if (!DRW_Dimension::parseDwg(version, &probe, nullptr, bs)) | |||
| 19391 | return fail(); | |||
| 19392 | buf = &probe; | |||
| 19393 | ||||
| 19394 | DRW_DBG("\n***************************** parsing dim angular *********************************************\n")DRW_dbg::dbg("\n***************************** parsing dim angular *********************************************\n" ); | |||
| 19395 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 19396 | DRW_Coord parsedArcPoint; | |||
| 19397 | DRW_Coord parsedDef1; | |||
| 19398 | DRW_Coord parsedDef2; | |||
| 19399 | DRW_Coord parsedCenter; | |||
| 19400 | DRW_Coord parsedDefPoint; | |||
| 19401 | if (!readBoundedRawDouble(*buf, bodyEndBit, parsedArcPoint.x) | |||
| 19402 | || !readBoundedRawDouble(*buf, bodyEndBit, parsedArcPoint.y) | |||
| 19403 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedDef1) | |||
| 19404 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedDef2) | |||
| 19405 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedCenter) | |||
| 19406 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedDefPoint)) | |||
| 19407 | return fail(); | |||
| 19408 | parsedArcPoint.z = 0.0; | |||
| 19409 | const auto finite = [](const DRW_Coord& point) { | |||
| 19410 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 19411 | && std::isfinite(point.z); | |||
| 19412 | }; | |||
| 19413 | if (!finite(parsedArcPoint) || !finite(parsedDef1) || !finite(parsedDef2) | |||
| 19414 | || !finite(parsedCenter) || !finite(parsedDefPoint)) | |||
| 19415 | return fail(); | |||
| 19416 | setPt6(parsedArcPoint); //code 16 | |||
| 19417 | DRW_DBG("arc Point: ")DRW_dbg::dbg("arc Point: "); DRW_DBGPT(parsedArcPoint.x, parsedArcPoint.y,DRW_dbg::dbgPT(parsedArcPoint.x, parsedArcPoint.y, parsedArcPoint .z) | |||
| 19418 | parsedArcPoint.z)DRW_dbg::dbgPT(parsedArcPoint.x, parsedArcPoint.y, parsedArcPoint .z); | |||
| 19419 | setPt3(parsedDef1); //def1 code 13 | |||
| 19420 | DRW_DBG("\ndef1: ")DRW_dbg::dbg("\ndef1: "); DRW_DBGPT(parsedDef1.x, parsedDef1.y, parsedDef1.z)DRW_dbg::dbgPT(parsedDef1.x, parsedDef1.y, parsedDef1.z); | |||
| 19421 | setPt4(parsedDef2); //def2 code 14 | |||
| 19422 | DRW_DBG("\ndef2: ")DRW_dbg::dbg("\ndef2: "); DRW_DBGPT(parsedDef2.x, parsedDef2.y, parsedDef2.z)DRW_dbg::dbgPT(parsedDef2.x, parsedDef2.y, parsedDef2.z); | |||
| 19423 | setPt5(parsedCenter); //center pt code 15 | |||
| 19424 | DRW_DBG("\ncenter point: ")DRW_dbg::dbg("\ncenter point: "); DRW_DBGPT(parsedCenter.x, parsedCenter.y,DRW_dbg::dbgPT(parsedCenter.x, parsedCenter.y, parsedCenter.z ) | |||
| 19425 | parsedCenter.z)DRW_dbg::dbgPT(parsedCenter.x, parsedCenter.y, parsedCenter.z ); | |||
| 19426 | setDefPoint(parsedDefPoint); //code 10 | |||
| 19427 | DRW_DBG("\ndefPoint: ")DRW_dbg::dbg("\ndefPoint: "); DRW_DBGPT(parsedDefPoint.x, parsedDefPoint.y,DRW_dbg::dbgPT(parsedDefPoint.x, parsedDefPoint.y, parsedDefPoint .z) | |||
| 19428 | parsedDefPoint.z)DRW_dbg::dbgPT(parsedDefPoint.x, parsedDefPoint.y, parsedDefPoint .z); | |||
| 19429 | type |= 0x02; | |||
| 19430 | DRW_DBG("\n type (70) final: ")DRW_dbg::dbg("\n type (70) final: "); DRW_DBG(type)DRW_dbg::dbg(type); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 19431 | if (!buf->isGood()) | |||
| 19432 | return fail(); | |||
| 19433 | ||||
| 19434 | std::uint64_t handleEndBit = 0; | |||
| 19435 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, handleEndBit) | |||
| 19436 | || !parseDwgDimensionHandles(version, buf, handleEndBit)) { | |||
| 19437 | DRW_DBG("Failed: parseDwgEntHandle() in DRW_DimAngular::parseDwg()\n")DRW_dbg::dbg("Failed: parseDwgEntHandle() in DRW_DimAngular::parseDwg()\n" ); | |||
| 19438 | return fail(); | |||
| 19439 | } | |||
| 19440 | DRW_DBG("Remaining bytes: ")DRW_dbg::dbg("Remaining bytes: "); DRW_DBG(buf->numRemainingBytes())DRW_dbg::dbg(buf->numRemainingBytes()); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 19441 | DRW_DBG("Remaining bytes: ")DRW_dbg::dbg("Remaining bytes: "); DRW_DBG(buf->numRemainingBytes())DRW_dbg::dbg(buf->numRemainingBytes()); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 19442 | ||||
| 19443 | // RS crc; //RS */ | |||
| 19444 | if (!buf->isGood()) | |||
| 19445 | return fail(); | |||
| 19446 | *sourceBuf = probe; | |||
| 19447 | return true; | |||
| 19448 | } | |||
| 19449 | ||||
| 19450 | bool DRW_DimAngular3p::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){ | |||
| 19451 | DRW_Dimension::resetDwgState(); | |||
| 19452 | dwgBuffer *sourceBuf = buf; | |||
| 19453 | auto fail = [this, sourceBuf]() { | |||
| 19454 | if (sourceBuf != nullptr) | |||
| 19455 | sourceBuf->invalidate(); | |||
| 19456 | DRW_Dimension::resetDwgState(); | |||
| 19457 | return false; | |||
| 19458 | }; | |||
| 19459 | if (sourceBuf == nullptr) | |||
| 19460 | return fail(); | |||
| 19461 | ||||
| 19462 | dwgBuffer probe = sourceBuf->forkIndependent(); | |||
| 19463 | if (!DRW_Dimension::parseDwg(version, &probe, nullptr, bs)) | |||
| 19464 | return fail(); | |||
| 19465 | buf = &probe; | |||
| 19466 | ||||
| 19467 | DRW_DBG("\n***************************** parsing dim angular3p *********************************************\n")DRW_dbg::dbg("\n***************************** parsing dim angular3p *********************************************\n" ); | |||
| 19468 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 19469 | DRW_Coord parsedDefPoint; | |||
| 19470 | DRW_Coord parsedDef1; | |||
| 19471 | DRW_Coord parsedDef2; | |||
| 19472 | DRW_Coord parsedCenter; | |||
| 19473 | if (!readBoundedBitCoord(*buf, bodyEndBit, parsedDefPoint) | |||
| 19474 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedDef1) | |||
| 19475 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedDef2) | |||
| 19476 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedCenter)) | |||
| 19477 | return fail(); | |||
| 19478 | const auto finite = [](const DRW_Coord& point) { | |||
| 19479 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 19480 | && std::isfinite(point.z); | |||
| 19481 | }; | |||
| 19482 | if (!finite(parsedDefPoint) || !finite(parsedDef1) || !finite(parsedDef2) | |||
| 19483 | || !finite(parsedCenter)) | |||
| 19484 | return fail(); | |||
| 19485 | setDefPoint(parsedDefPoint); //code 10 | |||
| 19486 | DRW_DBG("defPoint: ")DRW_dbg::dbg("defPoint: "); DRW_DBGPT(parsedDefPoint.x, parsedDefPoint.y,DRW_dbg::dbgPT(parsedDefPoint.x, parsedDefPoint.y, parsedDefPoint .z) | |||
| 19487 | parsedDefPoint.z)DRW_dbg::dbgPT(parsedDefPoint.x, parsedDefPoint.y, parsedDefPoint .z); | |||
| 19488 | setPt3(parsedDef1); //def1 code 13 | |||
| 19489 | DRW_DBG("\ndef1: ")DRW_dbg::dbg("\ndef1: "); DRW_DBGPT(parsedDef1.x, parsedDef1.y, parsedDef1.z)DRW_dbg::dbgPT(parsedDef1.x, parsedDef1.y, parsedDef1.z); | |||
| 19490 | setPt4(parsedDef2); //def2 code 14 | |||
| 19491 | DRW_DBG("\ndef2: ")DRW_dbg::dbg("\ndef2: "); DRW_DBGPT(parsedDef2.x, parsedDef2.y, parsedDef2.z)DRW_dbg::dbgPT(parsedDef2.x, parsedDef2.y, parsedDef2.z); | |||
| 19492 | setPt5(parsedCenter); //center pt code 15 | |||
| 19493 | DRW_DBG("\ncenter point: ")DRW_dbg::dbg("\ncenter point: "); DRW_DBGPT(parsedCenter.x, parsedCenter.y,DRW_dbg::dbgPT(parsedCenter.x, parsedCenter.y, parsedCenter.z ) | |||
| 19494 | parsedCenter.z)DRW_dbg::dbgPT(parsedCenter.x, parsedCenter.y, parsedCenter.z ); | |||
| 19495 | type |= 0x05; | |||
| 19496 | DRW_DBG("\n type (70) final: ")DRW_dbg::dbg("\n type (70) final: "); DRW_DBG(type)DRW_dbg::dbg(type); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 19497 | if (!buf->isGood()) | |||
| 19498 | return fail(); | |||
| 19499 | ||||
| 19500 | std::uint64_t handleEndBit = 0; | |||
| 19501 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, handleEndBit) | |||
| 19502 | || !parseDwgDimensionHandles(version, buf, handleEndBit)) { | |||
| 19503 | DRW_DBG("Failed: parseDwgEntHandle() in DRW_DimAngular3p::parseDwg()\n")DRW_dbg::dbg("Failed: parseDwgEntHandle() in DRW_DimAngular3p::parseDwg()\n" ); | |||
| 19504 | return fail(); | |||
| 19505 | } | |||
| 19506 | DRW_DBG("Remaining bytes: ")DRW_dbg::dbg("Remaining bytes: "); DRW_DBG(buf->numRemainingBytes())DRW_dbg::dbg(buf->numRemainingBytes()); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 19507 | DRW_DBG("Remaining bytes: ")DRW_dbg::dbg("Remaining bytes: "); DRW_DBG(buf->numRemainingBytes())DRW_dbg::dbg(buf->numRemainingBytes()); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 19508 | ||||
| 19509 | // RS crc; //RS */ | |||
| 19510 | if (!buf->isGood()) | |||
| 19511 | return fail(); | |||
| 19512 | *sourceBuf = probe; | |||
| 19513 | return true; | |||
| 19514 | } | |||
| 19515 | ||||
| 19516 | bool DRW_DimOrdinate::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){ | |||
| 19517 | DRW_Dimension::resetDwgState(); | |||
| 19518 | dwgBuffer *sourceBuf = buf; | |||
| 19519 | auto fail = [this, sourceBuf]() { | |||
| 19520 | if (sourceBuf != nullptr) | |||
| 19521 | sourceBuf->invalidate(); | |||
| 19522 | DRW_Dimension::resetDwgState(); | |||
| 19523 | return false; | |||
| 19524 | }; | |||
| 19525 | if (sourceBuf == nullptr) | |||
| 19526 | return fail(); | |||
| 19527 | ||||
| 19528 | dwgBuffer probe = sourceBuf->forkIndependent(); | |||
| 19529 | if (!DRW_Dimension::parseDwg(version, &probe, nullptr, bs)) | |||
| 19530 | return fail(); | |||
| 19531 | buf = &probe; | |||
| 19532 | ||||
| 19533 | DRW_DBG("\n***************************** parsing dim ordinate *********************************************\n")DRW_dbg::dbg("\n***************************** parsing dim ordinate *********************************************\n" ); | |||
| 19534 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 19535 | DRW_Coord parsedDefPoint; | |||
| 19536 | DRW_Coord parsedDef1; | |||
| 19537 | DRW_Coord parsedDef2; | |||
| 19538 | std::uint8_t type2 = 0; | |||
| 19539 | if (!readBoundedBitCoord(*buf, bodyEndBit, parsedDefPoint) | |||
| 19540 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedDef1) | |||
| 19541 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedDef2) | |||
| 19542 | || !readBoundedRawChar8(*buf, bodyEndBit, type2)) | |||
| 19543 | return fail(); | |||
| 19544 | const auto finite = [](const DRW_Coord& point) { | |||
| 19545 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 19546 | && std::isfinite(point.z); | |||
| 19547 | }; | |||
| 19548 | if (!finite(parsedDefPoint) || !finite(parsedDef1) || !finite(parsedDef2)) | |||
| 19549 | return fail(); | |||
| 19550 | setDefPoint(parsedDefPoint); | |||
| 19551 | DRW_DBG("defPoint: ")DRW_dbg::dbg("defPoint: "); DRW_DBGPT(parsedDefPoint.x, parsedDefPoint.y,DRW_dbg::dbgPT(parsedDefPoint.x, parsedDefPoint.y, parsedDefPoint .z) | |||
| 19552 | parsedDefPoint.z)DRW_dbg::dbgPT(parsedDefPoint.x, parsedDefPoint.y, parsedDefPoint .z); | |||
| 19553 | setPt3(parsedDef1); //def1 | |||
| 19554 | DRW_DBG("\ndef1: ")DRW_dbg::dbg("\ndef1: "); DRW_DBGPT(parsedDef1.x, parsedDef1.y, parsedDef1.z)DRW_dbg::dbgPT(parsedDef1.x, parsedDef1.y, parsedDef1.z); | |||
| 19555 | setPt4(parsedDef2); | |||
| 19556 | DRW_DBG("\ndef2: ")DRW_dbg::dbg("\ndef2: "); DRW_DBGPT(parsedDef2.x, parsedDef2.y, parsedDef2.z)DRW_dbg::dbgPT(parsedDef2.x, parsedDef2.y, parsedDef2.z); | |||
| 19557 | DRW_DBG("type2 (70) read: ")DRW_dbg::dbg("type2 (70) read: "); DRW_DBG(type2)DRW_dbg::dbg(type2); | |||
| 19558 | // 0B.1: x-vs-y ordinate flag is DXF group-70 bit 6 (0x40), matching the | |||
| 19559 | // filter (rs_filterdxfrw.cpp `type & 64`) and the DWG parseCode path. | |||
| 19560 | // (Previously set bit 7/0x80, which the filter never checks.) The clear | |||
| 19561 | // mask 0xBF already clears 0x40. The DIMENSION base type byte (bit 7) is | |||
| 19562 | // a separate field — see :6141/:6409/:6660, NOT touched here. | |||
| 19563 | int parsedType = type; | |||
| 19564 | parsedType = (type2 & 1) ? parsedType | 0x40 : parsedType & 0xBF; | |||
| 19565 | DRW_DBG(" type (70) set: ")DRW_dbg::dbg(" type (70) set: "); DRW_DBG(parsedType)DRW_dbg::dbg(parsedType); | |||
| 19566 | parsedType |= 6; | |||
| 19567 | DRW_DBG("\n type (70) final: ")DRW_dbg::dbg("\n type (70) final: "); DRW_DBG(parsedType)DRW_dbg::dbg(parsedType); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 19568 | ||||
| 19569 | std::uint64_t handleEndBit = 0; | |||
| 19570 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, handleEndBit) | |||
| 19571 | || !parseDwgDimensionHandles(version, buf, handleEndBit)) { | |||
| 19572 | DRW_DBG("Failed: parseDwgEntHandle() in DRW_DimAligned::parseDwg()\n")DRW_dbg::dbg("Failed: parseDwgEntHandle() in DRW_DimAligned::parseDwg()\n" ); | |||
| 19573 | return fail(); | |||
| 19574 | } | |||
| 19575 | DRW_DBG("Remaining bytes: ")DRW_dbg::dbg("Remaining bytes: "); DRW_DBG(buf->numRemainingBytes())DRW_dbg::dbg(buf->numRemainingBytes()); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 19576 | DRW_DBG("Remaining bytes: ")DRW_dbg::dbg("Remaining bytes: "); DRW_DBG(buf->numRemainingBytes())DRW_dbg::dbg(buf->numRemainingBytes()); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 19577 | ||||
| 19578 | // RS crc; //RS */ | |||
| 19579 | if (!buf->isGood()) | |||
| 19580 | return fail(); | |||
| 19581 | type = parsedType; | |||
| 19582 | *sourceBuf = probe; | |||
| 19583 | return true; | |||
| 19584 | } | |||
| 19585 | ||||
| 19586 | // ---------------------------------------------------------------------------- | |||
| 19587 | // DRW_Dimension shared base encoder (R2000 / AC1015) | |||
| 19588 | // ---------------------------------------------------------------------------- | |||
| 19589 | bool DRW_Dimension::encodeDwgDimBase(DRW::Version version, dwgBufferW *buf, | |||
| 19590 | dwgBufferW *strBuf) const { | |||
| 19591 | // ODA §20.4.22: version RC present for R2010+ (mirrors parseDwg read at version > AC1021) | |||
| 19592 | if (version > DRW::AC1021) | |||
| 19593 | buf->putRawChar8(0); | |||
| 19594 | // R2007+: the dim text below is routed to strBuf (the separate string | |||
| 19595 | // stream) via the (strBuf ? strBuf : buf) selector in putVariableText. | |||
| 19596 | buf->put3BitDouble(extPoint); // 3BD per ODA §20.4.22 (NOT BE, NO padding bits) | |||
| 19597 | buf->putRawDouble(textPoint.x); | |||
| 19598 | buf->putRawDouble(textPoint.y); | |||
| 19599 | buf->putBitDouble(textPoint.z); | |||
| 19600 | // Reverse the parseDwg type-byte transformation: | |||
| 19601 | // parseDwg bit0=0 → type bit7 set; bit0=1 → type bit7 clear | |||
| 19602 | // parseDwg bit1=1 → type bit5 set; bit1=0 → type bit5 clear | |||
| 19603 | std::uint8_t rawByte = static_cast<std::uint8_t>( | |||
| 19604 | ((type & 0x80) ? 0 : 1) | ((type & 0x20) ? 2 : 0)); | |||
| 19605 | buf->putRawChar8(rawByte); | |||
| 19606 | (strBuf ? strBuf : buf)->putVariableText(version, text); | |||
| 19607 | buf->putBitDouble(rot); | |||
| 19608 | buf->putBitDouble(hdir); | |||
| 19609 | // ins_scale (3BD) of the dimension's anonymous block — not stored by the | |||
| 19610 | // reader, but ODA/libreDWG default it to (1,1,1) (dwg.spec FIELD_3BD_1), not | |||
| 19611 | // (0,0,0). A zero scale is degenerate for ODA consumers. (write-review #46) | |||
| 19612 | const DRW_Coord insScale{1.0, 1.0, 1.0}; | |||
| 19613 | buf->put3BitDouble(insScale); | |||
| 19614 | buf->putBitDouble(0.0); // ins_rotation (code 54) — default 0, not stored | |||
| 19615 | // R2000 (version > AC1014): alignment, spacing, line factor, measure | |||
| 19616 | buf->putBitShort(static_cast<std::uint16_t>(align)); | |||
| 19617 | buf->putBitShort(static_cast<std::uint16_t>(linesty)); | |||
| 19618 | buf->putBitDouble(linefactor); | |||
| 19619 | buf->putBitDouble(measureValue); | |||
| 19620 | if (version > DRW::AC1018) { | |||
| 19621 | buf->putBit(0); // unknown R2007+ bit | |||
| 19622 | buf->putBit(flipArrow1 ? 1 : 0); | |||
| 19623 | buf->putBit(flipArrow2 ? 1 : 0); | |||
| 19624 | } | |||
| 19625 | buf->putRawDouble(clonePoint.x); | |||
| 19626 | buf->putRawDouble(clonePoint.y); | |||
| 19627 | return true; | |||
| 19628 | } | |||
| 19629 | ||||
| 19630 | // Helper: emit dimStyleH (defaults to STANDARD=0x15) and blockH. | |||
| 19631 | static void putDimHandles(dwgBufferW *buf, const dwgHandle& dimStyleH, const dwgHandle& blockH, | |||
| 19632 | dwgBufferW *hBuf = nullptr) { | |||
| 19633 | dwgBufferW *hb = hBuf ? hBuf : buf; | |||
| 19634 | dwgHandle dsH; | |||
| 19635 | dsH.code = 5; | |||
| 19636 | dsH.ref = (dimStyleH.ref == 0) ? 0x15 : dimStyleH.ref; | |||
| 19637 | dsH.size = 0; | |||
| 19638 | if (dsH.ref != 0) { std::uint32_t t = dsH.ref; while (t != 0) { t >>= 8; ++dsH.size; } } | |||
| 19639 | hb->putHandle(dsH); | |||
| 19640 | ||||
| 19641 | dwgHandle bhH; | |||
| 19642 | bhH.code = (blockH.ref == 0) ? 0 : 5; | |||
| 19643 | bhH.ref = blockH.ref; | |||
| 19644 | bhH.size = 0; | |||
| 19645 | if (bhH.ref != 0) { std::uint32_t t = bhH.ref; while (t != 0) { t >>= 8; ++bhH.size; } } | |||
| 19646 | hb->putHandle(bhH); | |||
| 19647 | } | |||
| 19648 | ||||
| 19649 | // ---------------------------------------------------------------------------- | |||
| 19650 | // DRW_DimAligned::encodeDwg (oType=22) | |||
| 19651 | // ---------------------------------------------------------------------------- | |||
| 19652 | bool DRW_DimAligned::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 19653 | (void)bs; | |||
| 19654 | oType = 22; | |||
| 19655 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 19656 | if (!encodeDwgDimBase(version, buf, strBuf)) return false; | |||
| 19657 | buf->put3BitDouble(getPt3()); // def1 | |||
| 19658 | buf->put3BitDouble(getPt4()); // def2 | |||
| 19659 | buf->put3BitDouble(getDefPoint()); // defPoint | |||
| 19660 | buf->putBitDouble(getOb52() / ARAD57.29577951308232); // oblique: degrees → radians | |||
| 19661 | if (!encodeDwgEntHandle(version, buf, handleBuf)) return false; | |||
| 19662 | putDimHandles(buf, dimStyleH, blockH, handleBuf); | |||
| 19663 | return true; | |||
| 19664 | } | |||
| 19665 | ||||
| 19666 | // ---------------------------------------------------------------------------- | |||
| 19667 | // DRW_DimLinear::encodeDwg (oType=21) | |||
| 19668 | // ---------------------------------------------------------------------------- | |||
| 19669 | bool DRW_DimLinear::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 19670 | (void)bs; | |||
| 19671 | oType = 21; | |||
| 19672 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 19673 | if (!encodeDwgDimBase(version, buf, strBuf)) return false; | |||
| 19674 | buf->put3BitDouble(getPt3()); // def1 | |||
| 19675 | buf->put3BitDouble(getPt4()); // def2 | |||
| 19676 | buf->put3BitDouble(getDefPoint()); // defPoint | |||
| 19677 | buf->putBitDouble(getOb52() / ARAD57.29577951308232); // oblique: degrees → radians | |||
| 19678 | buf->putBitDouble(getAn50() / ARAD57.29577951308232); // rotation angle: degrees → radians | |||
| 19679 | if (!encodeDwgEntHandle(version, buf, handleBuf)) return false; | |||
| 19680 | putDimHandles(buf, dimStyleH, blockH, handleBuf); | |||
| 19681 | return true; | |||
| 19682 | } | |||
| 19683 | ||||
| 19684 | // ---------------------------------------------------------------------------- | |||
| 19685 | // DRW_DimRadial::encodeDwg (oType=25) | |||
| 19686 | // ---------------------------------------------------------------------------- | |||
| 19687 | bool DRW_DimRadial::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 19688 | (void)bs; | |||
| 19689 | oType = 25; | |||
| 19690 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 19691 | if (!encodeDwgDimBase(version, buf, strBuf)) return false; | |||
| 19692 | buf->put3BitDouble(getDefPoint()); // center point (code 10) | |||
| 19693 | buf->put3BitDouble(getPt5()); // diameter point (code 15) | |||
| 19694 | buf->putBitDouble(getRa40()); // leader length (code 40) | |||
| 19695 | if (!encodeDwgEntHandle(version, buf, handleBuf)) return false; | |||
| 19696 | putDimHandles(buf, dimStyleH, blockH, handleBuf); | |||
| 19697 | return true; | |||
| 19698 | } | |||
| 19699 | ||||
| 19700 | // ---------------------------------------------------------------------------- | |||
| 19701 | // DRW_DimLargeRadial::encodeDwg (oType=519, custom AcDbRadialDimensionLarge) | |||
| 19702 | // ---------------------------------------------------------------------------- | |||
| 19703 | bool DRW_DimLargeRadial::encodeDwg(DRW::Version version, dwgBufferW *buf, | |||
| 19704 | std::uint32_t bs, dwgBufferW *strBuf, | |||
| 19705 | dwgBufferW *handleBuf) { | |||
| 19706 | (void)bs; | |||
| 19707 | oType = kDwgClassNum; | |||
| 19708 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 19709 | if (!encodeDwgDimBase(version, buf, strBuf)) return false; | |||
| 19710 | buf->put3BitDouble(getCenterPoint()); // definition point (code 10) | |||
| 19711 | buf->put3BitDouble(jogPoint); // jog vertex (code 15) | |||
| 19712 | buf->putBitDouble(jogAngle); // jog transverse angle (code 40) | |||
| 19713 | buf->put3BitDouble(getChordPoint()); // chord point (code 13) | |||
| 19714 | buf->put3BitDouble(overrideCenterPoint); // overridden center (code 14) | |||
| 19715 | if (!encodeDwgEntHandle(version, buf, handleBuf)) return false; | |||
| 19716 | putDimHandles(buf, dimStyleH, blockH, handleBuf); | |||
| 19717 | return true; | |||
| 19718 | } | |||
| 19719 | ||||
| 19720 | // ---------------------------------------------------------------------------- | |||
| 19721 | // DRW_DimDiametric::encodeDwg (oType=26) | |||
| 19722 | // ---------------------------------------------------------------------------- | |||
| 19723 | bool DRW_DimDiametric::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 19724 | (void)bs; | |||
| 19725 | oType = 26; | |||
| 19726 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 19727 | if (!encodeDwgDimBase(version, buf, strBuf)) return false; | |||
| 19728 | buf->put3BitDouble(getPt5()); // first diameter point (code 15) — matches parseDwg order | |||
| 19729 | buf->put3BitDouble(getDefPoint()); // opposite point (code 10) | |||
| 19730 | buf->putBitDouble(getRa40()); // leader length (code 40) | |||
| 19731 | if (!encodeDwgEntHandle(version, buf, handleBuf)) return false; | |||
| 19732 | putDimHandles(buf, dimStyleH, blockH, handleBuf); | |||
| 19733 | return true; | |||
| 19734 | } | |||
| 19735 | ||||
| 19736 | // ---------------------------------------------------------------------------- | |||
| 19737 | // DRW_DimAngular::encodeDwg (oType=24, 2-line angular) | |||
| 19738 | // ---------------------------------------------------------------------------- | |||
| 19739 | bool DRW_DimAngular::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 19740 | (void)bs; | |||
| 19741 | oType = 24; | |||
| 19742 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 19743 | if (!encodeDwgDimBase(version, buf, strBuf)) return false; | |||
| 19744 | // arcPoint is 2RD (not 3BD) in parseDwg — only x and y | |||
| 19745 | buf->putRawDouble(getPt6().x); | |||
| 19746 | buf->putRawDouble(getPt6().y); | |||
| 19747 | buf->put3BitDouble(getPt3()); // def1 (line 1 start) | |||
| 19748 | buf->put3BitDouble(getPt4()); // def2 (line 1 end) | |||
| 19749 | buf->put3BitDouble(getPt5()); // circlePoint (center) | |||
| 19750 | buf->put3BitDouble(getDefPoint()); // defPoint | |||
| 19751 | if (!encodeDwgEntHandle(version, buf, handleBuf)) return false; | |||
| 19752 | putDimHandles(buf, dimStyleH, blockH, handleBuf); | |||
| 19753 | return true; | |||
| 19754 | } | |||
| 19755 | ||||
| 19756 | // ---------------------------------------------------------------------------- | |||
| 19757 | // DRW_DimAngular3p::encodeDwg (oType=23, 3-point angular) | |||
| 19758 | // ---------------------------------------------------------------------------- | |||
| 19759 | bool DRW_DimAngular3p::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 19760 | (void)bs; | |||
| 19761 | oType = 23; | |||
| 19762 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 19763 | if (!encodeDwgDimBase(version, buf, strBuf)) return false; | |||
| 19764 | buf->put3BitDouble(getDefPoint()); // defPoint (code 10) | |||
| 19765 | buf->put3BitDouble(getPt3()); // def1 (code 13) | |||
| 19766 | buf->put3BitDouble(getPt4()); // def2 (code 14) | |||
| 19767 | buf->put3BitDouble(getPt5()); // circlePoint / vertex (code 15) | |||
| 19768 | if (!encodeDwgEntHandle(version, buf, handleBuf)) return false; | |||
| 19769 | putDimHandles(buf, dimStyleH, blockH, handleBuf); | |||
| 19770 | return true; | |||
| 19771 | } | |||
| 19772 | ||||
| 19773 | // ---------------------------------------------------------------------------- | |||
| 19774 | // DRW_DimArc::parseCode (DXF group-code parser) | |||
| 19775 | // ---------------------------------------------------------------------------- | |||
| 19776 | bool DRW_DimArc::parseCode(int code, const std::unique_ptr<dxfReader>& reader) { | |||
| 19777 | if (code == 100) { | |||
| 19778 | std::string s = reader->getString(); | |||
| 19779 | if (s == "AcDbArcDimension") { | |||
| 19780 | m_arcSubclassSeen = true; | |||
| 19781 | return true; | |||
| 19782 | } | |||
| 19783 | // Fall through for AcDbEntity / AcDbDimension so base classes see them | |||
| 19784 | return DRW_Dimension::parseCode(code, reader); | |||
| 19785 | } | |||
| 19786 | if (m_arcSubclassSeen) { | |||
| 19787 | switch (code) { | |||
| 19788 | case 40: arcStartAngle = reader->getDouble(); return true; | |||
| 19789 | case 41: arcEndAngle = reader->getDouble(); return true; | |||
| 19790 | case 70: arcSymbol = reader->getInt32(); return true; | |||
| 19791 | case 71: isPartial = reader->getInt32() != 0; return true; | |||
| 19792 | } | |||
| 19793 | } | |||
| 19794 | switch (code) { | |||
| 19795 | case 17: leaderPt2.x = reader->getDouble(); return true; | |||
| 19796 | case 27: leaderPt2.y = reader->getDouble(); return true; | |||
| 19797 | case 37: leaderPt2.z = reader->getDouble(); return true; | |||
| 19798 | } | |||
| 19799 | return DRW_Dimension::parseCode(code, reader); | |||
| 19800 | } | |||
| 19801 | ||||
| 19802 | // ---------------------------------------------------------------------------- | |||
| 19803 | // DRW_DimArc::parseDwg (ODA DWG spec §20.4.19) | |||
| 19804 | // ---------------------------------------------------------------------------- | |||
| 19805 | bool DRW_DimArc::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs) { | |||
| 19806 | DRW_Dimension::resetDwgState(); | |||
| 19807 | leaderPt2 = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 19808 | arcStartAngle = 0.0; | |||
| 19809 | arcEndAngle = 0.0; | |||
| 19810 | arcSymbol = 0; | |||
| 19811 | isPartial = false; | |||
| 19812 | hasLeader = false; | |||
| 19813 | m_arcSubclassSeen = false; | |||
| 19814 | dwgBuffer *sourceBuf = buf; | |||
| 19815 | auto fail = [this, sourceBuf]() { | |||
| 19816 | if (sourceBuf != nullptr) | |||
| 19817 | sourceBuf->invalidate(); | |||
| 19818 | DRW_Dimension::resetDwgState(); | |||
| 19819 | leaderPt2 = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 19820 | arcStartAngle = 0.0; | |||
| 19821 | arcEndAngle = 0.0; | |||
| 19822 | arcSymbol = 0; | |||
| 19823 | isPartial = false; | |||
| 19824 | hasLeader = false; | |||
| 19825 | m_arcSubclassSeen = false; | |||
| 19826 | return false; | |||
| 19827 | }; | |||
| 19828 | if (sourceBuf == nullptr) | |||
| 19829 | return fail(); | |||
| 19830 | ||||
| 19831 | dwgBuffer probe = sourceBuf->forkIndependent(); | |||
| 19832 | if (!DRW_Dimension::parseDwg(version, &probe, nullptr, bs)) | |||
| 19833 | return fail(); | |||
| 19834 | buf = &probe; | |||
| 19835 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 19836 | DRW_Coord parsedDefPoint; | |||
| 19837 | DRW_Coord parsedDef1; | |||
| 19838 | DRW_Coord parsedDef2; | |||
| 19839 | DRW_Coord parsedCenter; | |||
| 19840 | DRW_Coord parsedLeaderPoint1; | |||
| 19841 | DRW_Coord parsedLeaderPoint2; | |||
| 19842 | bool parsedPartial = false; | |||
| 19843 | double parsedStartAngle = 0.0; | |||
| 19844 | double parsedEndAngle = 0.0; | |||
| 19845 | bool parsedHasLeader = false; | |||
| 19846 | if (!readBoundedBitCoord(*buf, bodyEndBit, parsedDefPoint) | |||
| 19847 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedDef1) | |||
| 19848 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedDef2) | |||
| 19849 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedCenter) | |||
| 19850 | || !readBoundedBit(*buf, bodyEndBit, parsedPartial) | |||
| 19851 | || !readBoundedBitDouble(*buf, bodyEndBit, parsedStartAngle) | |||
| 19852 | || !readBoundedBitDouble(*buf, bodyEndBit, parsedEndAngle) | |||
| 19853 | || !readBoundedBit(*buf, bodyEndBit, parsedHasLeader) | |||
| 19854 | // ODA §20.4.19: leader points are unconditional in the stream. | |||
| 19855 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedLeaderPoint1) | |||
| 19856 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedLeaderPoint2)) | |||
| 19857 | return fail(); | |||
| 19858 | const auto finite = [](const DRW_Coord& point) { | |||
| 19859 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 19860 | && std::isfinite(point.z); | |||
| 19861 | }; | |||
| 19862 | if (!finite(parsedDefPoint) || !finite(parsedDef1) || !finite(parsedDef2) | |||
| 19863 | || !finite(parsedCenter) || !finite(parsedLeaderPoint1) | |||
| 19864 | || !finite(parsedLeaderPoint2) || !std::isfinite(parsedStartAngle) | |||
| 19865 | || !std::isfinite(parsedEndAngle)) | |||
| 19866 | return fail(); | |||
| 19867 | setDefPoint(parsedDefPoint); | |||
| 19868 | setPt3(parsedDef1); | |||
| 19869 | setPt4(parsedDef2); | |||
| 19870 | setPt5(parsedCenter); | |||
| 19871 | setPt6(parsedLeaderPoint1); | |||
| 19872 | leaderPt2 = parsedLeaderPoint2; | |||
| 19873 | isPartial = parsedPartial; | |||
| 19874 | arcStartAngle = parsedStartAngle; | |||
| 19875 | arcEndAngle = parsedEndAngle; | |||
| 19876 | hasLeader = parsedHasLeader; | |||
| 19877 | std::uint64_t handleEndBit = 0; | |||
| 19878 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, handleEndBit) | |||
| 19879 | || !parseDwgDimensionHandles(version, buf, handleEndBit)) | |||
| 19880 | return fail(); | |||
| 19881 | *sourceBuf = probe; | |||
| 19882 | return true; | |||
| 19883 | } | |||
| 19884 | ||||
| 19885 | // ---------------------------------------------------------------------------- | |||
| 19886 | // DRW_DimArc::encodeDwg (oType=500 — dynamic class, classNum from writeDwgClasses) | |||
| 19887 | // ---------------------------------------------------------------------------- | |||
| 19888 | bool DRW_DimArc::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, | |||
| 19889 | dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 19890 | (void)bs; | |||
| 19891 | oType = DRW_DimArc::kDwgClassNum; // assigned in writeDwgClasses; reader resolves via classesmap | |||
| 19892 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 19893 | if (!encodeDwgDimBase(version, buf, strBuf)) return false; | |||
| 19894 | buf->put3BitDouble(getDefPoint()); // arc dim-line arc point (code 10) | |||
| 19895 | buf->put3BitDouble(getPt3()); // extension line 1 (code 13) | |||
| 19896 | buf->put3BitDouble(getPt4()); // extension line 2 (code 14) | |||
| 19897 | buf->put3BitDouble(getPt5()); // arc center (code 15) | |||
| 19898 | buf->putBit(isPartial ? 1 : 0); | |||
| 19899 | buf->putBitDouble(arcStartAngle); | |||
| 19900 | buf->putBitDouble(arcEndAngle); | |||
| 19901 | buf->putBit(hasLeader ? 1 : 0); | |||
| 19902 | // ODA §20.4.19: leader points are UNCONDITIONAL — always written; default to ext-line pts | |||
| 19903 | DRW_Coord lp1 = hasLeader ? getPt6() : getPt3(); | |||
| 19904 | DRW_Coord lp2 = hasLeader ? leaderPt2 : getPt4(); | |||
| 19905 | buf->put3BitDouble(lp1); // leader point 1 (code 16) | |||
| 19906 | buf->put3BitDouble(lp2); // leader point 2 (code 17) | |||
| 19907 | if (!encodeDwgEntHandle(version, buf, handleBuf)) return false; | |||
| 19908 | putDimHandles(buf, dimStyleH, blockH, handleBuf); | |||
| 19909 | return true; | |||
| 19910 | } | |||
| 19911 | ||||
| 19912 | // ---------------------------------------------------------------------------- | |||
| 19913 | // DRW_DimOrdinate::encodeDwg (oType=20) | |||
| 19914 | // ---------------------------------------------------------------------------- | |||
| 19915 | bool DRW_DimOrdinate::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 19916 | (void)bs; | |||
| 19917 | oType = 20; | |||
| 19918 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 19919 | if (!encodeDwgDimBase(version, buf, strBuf)) return false; | |||
| 19920 | buf->put3BitDouble(getDefPoint()); // origin/definition point (code 10) | |||
| 19921 | buf->put3BitDouble(getPt3()); // feature location point (code 13) | |||
| 19922 | buf->put3BitDouble(getPt4()); // leader end point (code 14) | |||
| 19923 | // type2 byte encodes the x-vs-y ordinate flag (bit 6 / 0x40 of type, per | |||
| 19924 | // 0B.1) — keeps the DWG byte round-trip self-consistent with the parse | |||
| 19925 | // side while making the filter's `type & 64` check fire. | |||
| 19926 | std::uint8_t type2byte = (type & 0x40) ? 1 : 0; | |||
| 19927 | buf->putRawChar8(type2byte); | |||
| 19928 | if (!encodeDwgEntHandle(version, buf, handleBuf)) return false; | |||
| 19929 | putDimHandles(buf, dimStyleH, blockH, handleBuf); | |||
| 19930 | return true; | |||
| 19931 | } | |||
| 19932 | ||||
| 19933 | bool DRW_Leader::parseCode(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 19934 | switch (code) { | |||
| 19935 | case 3: | |||
| 19936 | style = reader->getUtf8String(); | |||
| 19937 | break; | |||
| 19938 | case 71: | |||
| 19939 | arrow = reader->getInt32(); | |||
| 19940 | break; | |||
| 19941 | case 72: | |||
| 19942 | leadertype = reader->getInt32(); | |||
| 19943 | break; | |||
| 19944 | case 73: | |||
| 19945 | flag = reader->getInt32(); | |||
| 19946 | break; | |||
| 19947 | case 74: | |||
| 19948 | hookline = reader->getInt32(); | |||
| 19949 | break; | |||
| 19950 | case 75: | |||
| 19951 | hookflag = reader->getInt32(); | |||
| 19952 | break; | |||
| 19953 | case 76: | |||
| 19954 | vertnum = reader->getInt32(); | |||
| 19955 | hasVertexCount = true; | |||
| 19956 | break; | |||
| 19957 | case 77: | |||
| 19958 | coloruse = reader->getInt32(); | |||
| 19959 | break; | |||
| 19960 | case 40: | |||
| 19961 | textheight = reader->getDouble(); | |||
| 19962 | break; | |||
| 19963 | case 41: | |||
| 19964 | textwidth = reader->getDouble(); | |||
| 19965 | break; | |||
| 19966 | case 10: | |||
| 19967 | vertexpoint= std::make_shared<DRW_Coord>(); | |||
| 19968 | vertexlist.push_back(vertexpoint); | |||
| 19969 | vertexpoint->x = reader->getDouble(); | |||
| 19970 | break; | |||
| 19971 | case 20: | |||
| 19972 | if(vertexpoint) | |||
| 19973 | vertexpoint->y = reader->getDouble(); | |||
| 19974 | break; | |||
| 19975 | case 30: | |||
| 19976 | if(vertexpoint) | |||
| 19977 | vertexpoint->z = reader->getDouble(); | |||
| 19978 | break; | |||
| 19979 | case 340: | |||
| 19980 | annotHandle = reader->getHandleString(); | |||
| 19981 | break; | |||
| 19982 | case 210: | |||
| 19983 | extrusionPoint.x = reader->getDouble(); | |||
| 19984 | break; | |||
| 19985 | case 220: | |||
| 19986 | extrusionPoint.y = reader->getDouble(); | |||
| 19987 | break; | |||
| 19988 | case 230: | |||
| 19989 | extrusionPoint.z = reader->getDouble(); | |||
| 19990 | break; | |||
| 19991 | case 211: | |||
| 19992 | horizdir.x = reader->getDouble(); | |||
| 19993 | break; | |||
| 19994 | case 221: | |||
| 19995 | horizdir.y = reader->getDouble(); | |||
| 19996 | break; | |||
| 19997 | case 231: | |||
| 19998 | horizdir.z = reader->getDouble(); | |||
| 19999 | break; | |||
| 20000 | case 212: | |||
| 20001 | offsetblock.x = reader->getDouble(); | |||
| 20002 | break; | |||
| 20003 | case 222: | |||
| 20004 | offsetblock.y = reader->getDouble(); | |||
| 20005 | break; | |||
| 20006 | case 232: | |||
| 20007 | offsetblock.z = reader->getDouble(); | |||
| 20008 | break; | |||
| 20009 | case 213: | |||
| 20010 | offsettext.x = reader->getDouble(); | |||
| 20011 | break; | |||
| 20012 | case 223: | |||
| 20013 | offsettext.y = reader->getDouble(); | |||
| 20014 | break; | |||
| 20015 | case 233: | |||
| 20016 | offsettext.z = reader->getDouble(); | |||
| 20017 | break; | |||
| 20018 | default: | |||
| 20019 | return DRW_Entity::parseCode(code, reader); | |||
| 20020 | } | |||
| 20021 | ||||
| 20022 | return true; | |||
| 20023 | } | |||
| 20024 | ||||
| 20025 | bool DRW_Leader::validatePayloadFields() const { | |||
| 20026 | const auto finite = [](const DRW_Coord& point) { | |||
| 20027 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 20028 | && std::isfinite(point.z); | |||
| 20029 | }; | |||
| 20030 | if ((arrow != 0 && arrow != 1) || (hookline != 0 && hookline != 1) | |||
| 20031 | || (hookflag != 0 && hookflag != 1) || leadertype < 0 | |||
| 20032 | || leadertype > 1 || flag < 0 || flag > 3 | |||
| 20033 | || coloruse < 0 | |||
| 20034 | || coloruse > static_cast<int>(std::numeric_limits<std::uint16_t>::max()) | |||
| 20035 | || vertexlist.size() > static_cast<std::size_t>(kMaxLeaderVertices) | |||
| 20036 | || !std::isfinite(textheight) || !std::isfinite(textwidth) | |||
| 20037 | || !finite(origin) || !finite(extrusionPoint) || !finite(horizdir) | |||
| 20038 | || !finite(offsetblock) || !finite(offsettext)) { | |||
| 20039 | return false; | |||
| 20040 | } | |||
| 20041 | return std::all_of(vertexlist.begin(), vertexlist.end(), | |||
| 20042 | [&finite](const std::shared_ptr<DRW_Coord>& point) { | |||
| 20043 | return point != nullptr && finite(*point); | |||
| 20044 | }); | |||
| 20045 | } | |||
| 20046 | ||||
| 20047 | bool DRW_Leader::validateDxf() const { | |||
| 20048 | if (!validatePayloadFields()) | |||
| 20049 | return false; | |||
| 20050 | if (!hasVertexCount) | |||
| 20051 | return true; | |||
| 20052 | return vertnum >= 0 | |||
| 20053 | && vertnum <= kMaxLeaderVertices | |||
| 20054 | && static_cast<std::size_t>(vertnum) == vertexlist.size(); | |||
| 20055 | } | |||
| 20056 | ||||
| 20057 | void DRW_Leader::resetDwgState() { | |||
| 20058 | DRW_Entity::reset(); | |||
| 20059 | style.clear(); | |||
| 20060 | arrow = 1; | |||
| 20061 | leadertype = 0; | |||
| 20062 | flag = 3; | |||
| 20063 | hookline = 1; | |||
| 20064 | hookflag = 1; | |||
| 20065 | textheight = 1.0; | |||
| 20066 | textwidth = 1.0; | |||
| 20067 | vertnum = 0; | |||
| 20068 | coloruse = 7; | |||
| 20069 | annotHandle = 0; | |||
| 20070 | origin = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 20071 | extrusionPoint = DRW_Coord{0.0, 0.0, 1.0}; | |||
| 20072 | horizdir = DRW_Coord{1.0, 0.0, 0.0}; | |||
| 20073 | offsetblock = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 20074 | offsettext = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 20075 | vertexlist.clear(); | |||
| 20076 | vertexpoint.reset(); | |||
| 20077 | hasVertexCount = false; | |||
| 20078 | dimStyleH = dwgHandle{}; | |||
| 20079 | AnnotH = dwgHandle{}; | |||
| 20080 | } | |||
| 20081 | ||||
| 20082 | bool DRW_Leader::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){ | |||
| 20083 | resetDwgState(); | |||
| 20084 | dwgBuffer *sourceBuf = buf; | |||
| 20085 | auto fail = [this, sourceBuf]() { | |||
| 20086 | if (sourceBuf != nullptr) | |||
| 20087 | sourceBuf->invalidate(); | |||
| 20088 | resetDwgState(); | |||
| 20089 | return false; | |||
| 20090 | }; | |||
| 20091 | if (sourceBuf == nullptr) | |||
| 20092 | return fail(); | |||
| 20093 | ||||
| 20094 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 20095 | buf = &bodyProbe; | |||
| 20096 | ||||
| 20097 | dwgBuffer sBuff = buf->forkIndependent(); | |||
| 20098 | dwgBuffer *sBuf = buf; | |||
| 20099 | if (version > DRW::AC1018) {//2007+ | |||
| 20100 | sBuf = &sBuff; //separate buffer for strings | |||
| 20101 | } | |||
| 20102 | bool ret = DRW_Entity::parseDwg(version, buf, sBuf, bs); | |||
| 20103 | if (!ret || !buf->isGood() || !sBuf->isGood()) | |||
| 20104 | return fail(); | |||
| 20105 | DRW_DBG("\n***************************** parsing leader *********************************************\n")DRW_dbg::dbg("\n***************************** parsing leader *********************************************\n" ); | |||
| 20106 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 20107 | bool ignoredBit = false; | |||
| 20108 | std::uint16_t ignoredShort = 0; | |||
| 20109 | std::uint16_t parsedAnnotationType = 0; | |||
| 20110 | std::uint16_t parsedLeaderType = 0; | |||
| 20111 | if (!readBoundedBit(*buf, bodyEndBit, ignoredBit) | |||
| 20112 | || !readBoundedBitShort(*buf, bodyEndBit, parsedAnnotationType) | |||
| 20113 | || !readBoundedBitShort(*buf, bodyEndBit, parsedLeaderType)) | |||
| 20114 | return fail(); | |||
| 20115 | if (parsedAnnotationType > 3 || parsedLeaderType > 1) | |||
| 20116 | return fail(); | |||
| 20117 | DRW_DBG(" Path type ")DRW_dbg::dbg(" Path type "); DRW_DBG(parsedLeaderType)DRW_dbg::dbg(parsedLeaderType); | |||
| 20118 | std::uint32_t parsedPointCount = 0; | |||
| 20119 | if (!readTableBodyCount(version, buf, objSize, kMaxLeaderVertices, 6, | |||
| 20120 | parsedPointCount)) | |||
| 20121 | return fail(); | |||
| 20122 | const std::int32_t nPt = static_cast<std::int32_t>(parsedPointCount); | |||
| 20123 | DRW_DBG(" Num pts ")DRW_dbg::dbg(" Num pts "); DRW_DBG(nPt)DRW_dbg::dbg(nPt); | |||
| 20124 | std::uint64_t pointBits = 0; | |||
| 20125 | if (!dwgSafety::multiply(parsedPointCount, 6, pointBits) | |||
| 20126 | || !proxyEntityHasBits(*buf, bodyEndBit, pointBits)) | |||
| 20127 | return fail(); | |||
| 20128 | ||||
| 20129 | // add vertexes | |||
| 20130 | std::vector<std::shared_ptr<DRW_Coord>> parsedVertices; | |||
| 20131 | if (!DRW::reserve(parsedVertices, nPt)) | |||
| 20132 | return fail(); | |||
| 20133 | for (std::uint32_t i = 0; i < parsedPointCount; i++){ | |||
| 20134 | DRW_Coord vertex; | |||
| 20135 | if (!readBoundedBitCoord(*buf, bodyEndBit, vertex)) | |||
| 20136 | return fail(); | |||
| 20137 | parsedVertices.push_back(std::make_shared<DRW_Coord>(vertex)); | |||
| 20138 | DRW_DBG("\nvertex ")DRW_dbg::dbg("\nvertex "); DRW_DBGPT(vertex.x, vertex.y, vertex.z)DRW_dbg::dbgPT(vertex.x, vertex.y, vertex.z); | |||
| 20139 | } | |||
| 20140 | DRW_Coord parsedOrigin; | |||
| 20141 | DRW_Coord parsedExtrusion; | |||
| 20142 | DRW_Coord parsedHorizdir; | |||
| 20143 | DRW_Coord parsedOffsetblock; | |||
| 20144 | DRW_Coord parsedOffsettext{0.0, 0.0, 0.0}; | |||
| 20145 | if (!readBoundedBitCoord(*buf, bodyEndBit, parsedOrigin) | |||
| 20146 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedExtrusion) | |||
| 20147 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedHorizdir) | |||
| 20148 | || !readBoundedBitCoord(*buf, bodyEndBit, parsedOffsetblock)) | |||
| 20149 | return fail(); | |||
| 20150 | DRW_DBG("\norigin ")DRW_dbg::dbg("\norigin "); DRW_DBGPT(parsedOrigin.x, parsedOrigin.y, parsedOrigin.z)DRW_dbg::dbgPT(parsedOrigin.x, parsedOrigin.y, parsedOrigin.z ); | |||
| 20151 | // ODA §20.4.47: Extrusion is plain 3DPOINT (3BD), not BE — confirmed by libreDWG dwg.spec:3439 | |||
| 20152 | if (leaderHasEndpointProjection(version)) { | |||
| 20153 | if (!readBoundedBitCoord(*buf, bodyEndBit, parsedOffsettext)) | |||
| 20154 | return fail(); | |||
| 20155 | DRW_DBG("\nEndptproj ")DRW_dbg::dbg("\nEndptproj "); DRW_DBGPT(parsedOffsettext.x, parsedOffsettext.y, parsedOffsettext.z)DRW_dbg::dbgPT(parsedOffsettext.x, parsedOffsettext.y, parsedOffsettext .z); | |||
| 20156 | } | |||
| 20157 | if (version < DRW::AC1015) { //R14 - | |||
| 20158 | double ignoredDouble = 0.0; | |||
| 20159 | if (!readBoundedBitDouble(*buf, bodyEndBit, ignoredDouble)) | |||
| 20160 | return fail(); | |||
| 20161 | } | |||
| 20162 | double parsedTextheight = 0.0; | |||
| 20163 | double parsedTextwidth = 0.0; | |||
| 20164 | bool parsedHookline = false; | |||
| 20165 | bool parsedArrow = false; | |||
| 20166 | std::uint16_t parsedColoruse = 7; | |||
| 20167 | if ((leaderHasTextBox(version) | |||
| 20168 | && (!readBoundedBitDouble(*buf, bodyEndBit, parsedTextheight) | |||
| 20169 | || !readBoundedBitDouble(*buf, bodyEndBit, parsedTextwidth))) | |||
| 20170 | || !readBoundedBit(*buf, bodyEndBit, parsedHookline) | |||
| 20171 | || !readBoundedBit(*buf, bodyEndBit, parsedArrow)) | |||
| 20172 | return fail(); | |||
| 20173 | DRW_DBG("\ntextheight ")DRW_dbg::dbg("\ntextheight "); DRW_DBG(parsedTextheight)DRW_dbg::dbg(parsedTextheight); DRW_DBG(" textwidth ")DRW_dbg::dbg(" textwidth "); DRW_DBG(parsedTextwidth)DRW_dbg::dbg(parsedTextwidth); | |||
| 20174 | DRW_DBG(" hookline ")DRW_dbg::dbg(" hookline "); DRW_DBG(parsedHookline)DRW_dbg::dbg(parsedHookline); DRW_DBG(" arrow flag ")DRW_dbg::dbg(" arrow flag "); DRW_DBG(parsedArrow)DRW_dbg::dbg(parsedArrow); | |||
| 20175 | ||||
| 20176 | // ODA §20.4.47 places arrowhead type immediately after the hook and | |||
| 20177 | // arrow flags in every DWG version. R2000+ keeps the field even though | |||
| 20178 | // the remaining legacy arrowhead data is absent. | |||
| 20179 | if (!readBoundedBitShort(*buf, bodyEndBit, ignoredShort)) | |||
| 20180 | return fail(); | |||
| 20181 | if (version < DRW::AC1015) { //R14 - | |||
| 20182 | double ignoredDimSize = 0.0; | |||
| 20183 | if (!readBoundedBitDouble(*buf, bodyEndBit, ignoredDimSize) | |||
| 20184 | || !readBoundedBit(*buf, bodyEndBit, ignoredBit) | |||
| 20185 | || !readBoundedBit(*buf, bodyEndBit, ignoredBit) | |||
| 20186 | || !readBoundedBitShort(*buf, bodyEndBit, ignoredShort) | |||
| 20187 | || !readBoundedBitShort(*buf, bodyEndBit, parsedColoruse) | |||
| 20188 | || !readBoundedBit(*buf, bodyEndBit, ignoredBit) | |||
| 20189 | || !readBoundedBit(*buf, bodyEndBit, ignoredBit)) | |||
| 20190 | return fail(); | |||
| 20191 | } else { //R2000+ | |||
| 20192 | if (!readBoundedBit(*buf, bodyEndBit, ignoredBit) | |||
| 20193 | || !readBoundedBit(*buf, bodyEndBit, ignoredBit)) | |||
| 20194 | return fail(); | |||
| 20195 | } | |||
| 20196 | DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 20197 | std::uint64_t handleEndBit = 0; | |||
| 20198 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, | |||
| 20199 | handleEndBit)) | |||
| 20200 | return fail(); | |||
| 20201 | ||||
| 20202 | dwgBuffer handleProbe = buf->forkIndependent(); | |||
| 20203 | ret = DRW_Entity::parseDwgEntHandle(version, &handleProbe, true, | |||
| 20204 | handleEndBit); | |||
| 20205 | if (!ret || !handleProbe.isGood()) | |||
| 20206 | return fail(); | |||
| 20207 | DRW_DBG("Remaining bytes: ")DRW_dbg::dbg("Remaining bytes: "); DRW_DBG(handleProbe.numRemainingBytes())DRW_dbg::dbg(handleProbe.numRemainingBytes()); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 20208 | dwgHandle parsedAnnotH; | |||
| 20209 | if (!readBoundedDwgHandle(handleProbe, handleEndBit, handle, false, | |||
| 20210 | parsedAnnotH)) | |||
| 20211 | return fail(); | |||
| 20212 | dwgHandle parsedDimStyleH; | |||
| 20213 | if (!readBoundedDwgHandle(handleProbe, handleEndBit, handle, false, | |||
| 20214 | parsedDimStyleH)) | |||
| 20215 | return fail(); /* H 7 STYLE (hard pointer) */ | |||
| 20216 | DRW_DBG("annot block Handle: ")DRW_dbg::dbg("annot block Handle: "); DRW_DBGHL(parsedAnnotH.code, parsedAnnotH.size, parsedAnnotH.ref)DRW_dbg::dbgHL(parsedAnnotH.code, parsedAnnotH.size, parsedAnnotH .ref); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 20217 | DRW_DBG("dim style Handle: ")DRW_dbg::dbg("dim style Handle: "); DRW_DBGHL(parsedDimStyleH.code, parsedDimStyleH.size, parsedDimStyleH.ref)DRW_dbg::dbgHL(parsedDimStyleH.code, parsedDimStyleH.size, parsedDimStyleH .ref); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 20218 | DRW_DBG("Remaining bytes: ")DRW_dbg::dbg("Remaining bytes: "); DRW_DBG(handleProbe.numRemainingBytes())DRW_dbg::dbg(handleProbe.numRemainingBytes()); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 20219 | // RS crc; //RS */ | |||
| 20220 | const auto finite = [](const DRW_Coord& point) { | |||
| 20221 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 20222 | && std::isfinite(point.z); | |||
| 20223 | }; | |||
| 20224 | if (!handleProbe.isGood() || !sBuf->isGood() | |||
| 20225 | || !finite(parsedOrigin) || !finite(parsedExtrusion) | |||
| 20226 | || !finite(parsedHorizdir) || !finite(parsedOffsetblock) | |||
| 20227 | || !finite(parsedOffsettext) || !std::isfinite(parsedTextheight) | |||
| 20228 | || !std::isfinite(parsedTextwidth) | |||
| 20229 | || !std::all_of(parsedVertices.begin(), parsedVertices.end(), | |||
| 20230 | [](const std::shared_ptr<DRW_Coord>& point) { | |||
| 20231 | return point != nullptr | |||
| 20232 | && std::isfinite(point->x) | |||
| 20233 | && std::isfinite(point->y) | |||
| 20234 | && std::isfinite(point->z); | |||
| 20235 | })) | |||
| 20236 | return fail(); | |||
| 20237 | *sourceBuf = handleProbe; | |||
| 20238 | flag = static_cast<int>(parsedAnnotationType); | |||
| 20239 | leadertype = parsedLeaderType; | |||
| 20240 | vertnum = nPt; | |||
| 20241 | origin = parsedOrigin; | |||
| 20242 | extrusionPoint = parsedExtrusion; | |||
| 20243 | horizdir = parsedHorizdir; | |||
| 20244 | offsetblock = parsedOffsetblock; | |||
| 20245 | offsettext = parsedOffsettext; | |||
| 20246 | textheight = parsedTextheight; | |||
| 20247 | textwidth = parsedTextwidth; | |||
| 20248 | hookline = parsedHookline; | |||
| 20249 | arrow = parsedArrow; | |||
| 20250 | coloruse = static_cast<int>(parsedColoruse); | |||
| 20251 | AnnotH = parsedAnnotH; | |||
| 20252 | annotHandle = AnnotH.ref; | |||
| 20253 | dimStyleH = parsedDimStyleH; | |||
| 20254 | vertexlist = std::move(parsedVertices); | |||
| 20255 | return true; | |||
| 20256 | } | |||
| 20257 | ||||
| 20258 | // DXF CONTEXT_DATA{} nested-block state machine (§20.4.86). The nested blocks | |||
| 20259 | // open with 300 "CONTEXT_DATA{" / 302 "LEADER{" / 304 "LEADER_LINE{" and close | |||
| 20260 | // with the distinct codes 301 / 303 / 305, so the open block is tracked with a | |||
| 20261 | // single state int (no stack needed). The numeric group codes are overloaded | |||
| 20262 | // by block — e.g. 40 is the overall scale in CONTEXT, the landing distance in | |||
| 20263 | // LEADER and the arrow size in LEADER_LINE; 10/20/30 are the content base point, | |||
| 20264 | // the connection point and a polyline vertex respectively — so they are routed | |||
| 20265 | // per state into `context`. Returns true when the code belongs to the context | |||
| 20266 | // block (consumed); false at entity level so parseCode handles it. | |||
| 20267 | bool DRW_MLeader::parseDxfContextCode(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 20268 | try { | |||
| 20269 | switch (code) { // block open/close markers | |||
| 20270 | case 300: | |||
| 20271 | if (m_dxfCtxState != 0 || reader->getString() != "CONTEXT_DATA{") | |||
| 20272 | return false; | |||
| 20273 | m_dxfCtxState = 1; | |||
| 20274 | return true; | |||
| 20275 | case 301: | |||
| 20276 | if (m_dxfCtxState != 1 || reader->getString() != "}") | |||
| 20277 | return false; | |||
| 20278 | m_dxfCtxState = 0; | |||
| 20279 | return true; | |||
| 20280 | case 302: | |||
| 20281 | if (m_dxfCtxState != 1 || reader->getString() != "LEADER{" | |||
| 20282 | || context.roots.size() >= static_cast<std::size_t>(kMaxMLeaderItems)) | |||
| 20283 | return false; | |||
| 20284 | context.roots.emplace_back(); | |||
| 20285 | m_dxfCtxState = 2; | |||
| 20286 | return true; | |||
| 20287 | case 303: | |||
| 20288 | if (m_dxfCtxState != 2 || reader->getString() != "}") | |||
| 20289 | return false; | |||
| 20290 | m_dxfCtxState = 1; | |||
| 20291 | return true; | |||
| 20292 | case 304: | |||
| 20293 | if (m_dxfCtxState == 1) { | |||
| 20294 | context.textLabel = reader->getUtf8String(); | |||
| 20295 | return true; | |||
| 20296 | } | |||
| 20297 | if (m_dxfCtxState != 2 || reader->getString() != "LEADER_LINE{" | |||
| 20298 | || context.roots.empty() | |||
| 20299 | || context.roots.back().leaderLines.size() | |||
| 20300 | >= static_cast<std::size_t>(kMaxMLeaderItems)) | |||
| 20301 | return false; | |||
| 20302 | context.roots.back().leaderLines.emplace_back(); | |||
| 20303 | m_dxfCtxState = 3; | |||
| 20304 | return true; | |||
| 20305 | case 305: | |||
| 20306 | if (m_dxfCtxState != 3 || reader->getString() != "}") | |||
| 20307 | return false; | |||
| 20308 | m_dxfCtxState = 2; | |||
| 20309 | return true; | |||
| 20310 | default: break; | |||
| 20311 | } | |||
| 20312 | ||||
| 20313 | if (m_dxfCtxState == 0) | |||
| 20314 | return false; // entity level — parseCode handles it | |||
| 20315 | ||||
| 20316 | if (m_dxfCtxState == 3) { // LEADER_LINE{}: a polyline + overrides | |||
| 20317 | DRW_MLeaderRoot* root = context.roots.empty() ? nullptr : &context.roots.back(); | |||
| 20318 | DRW_MLeaderLeaderLine* line = | |||
| 20319 | (root && !root->leaderLines.empty()) ? &root->leaderLines.back() : nullptr; | |||
| 20320 | if (line) switch (code) { | |||
| 20321 | case 10: | |||
| 20322 | if (line->points.size() >= static_cast<std::size_t>(kMaxLeaderVertices)) | |||
| 20323 | return false; | |||
| 20324 | line->points.emplace_back(reader->getDouble(), 0.0, 0.0); | |||
| 20325 | return true; | |||
| 20326 | case 20: if (!line->points.empty()) line->points.back().y = reader->getDouble(); return true; | |||
| 20327 | case 30: if (!line->points.empty()) line->points.back().z = reader->getDouble(); return true; | |||
| 20328 | case 40: line->arrowSize = reader->getDouble(); return true; | |||
| 20329 | case 90: line->segmentIndex = reader->getInt32(); return true; | |||
| 20330 | case 91: line->leaderLineIndex = reader->getInt32(); return true; | |||
| 20331 | case 92: line->color = reader->getInt32(); return true; | |||
| 20332 | case 93: line->overrideFlags = reader->getInt32(); return true; | |||
| 20333 | case 170: line->leaderType = reader->getInt32(); return true; | |||
| 20334 | case 171: line->lineWeight = reader->getInt32(); return true; | |||
| 20335 | default: break; | |||
| 20336 | } | |||
| 20337 | return true; // swallow other line codes | |||
| 20338 | } | |||
| 20339 | ||||
| 20340 | if (m_dxfCtxState == 2) { // LEADER{}: one root attachment | |||
| 20341 | DRW_MLeaderRoot* root = context.roots.empty() ? nullptr : &context.roots.back(); | |||
| 20342 | if (root) switch (code) { | |||
| 20343 | case 290: root->isContentValid = (reader->getInt32() != 0); return true; | |||
| 20344 | case 291: root->unknown291 = (reader->getInt32() != 0); return true; | |||
| 20345 | case 10: root->connectionPoint.x = reader->getDouble(); return true; | |||
| 20346 | case 20: root->connectionPoint.y = reader->getDouble(); return true; | |||
| 20347 | case 30: root->connectionPoint.z = reader->getDouble(); return true; | |||
| 20348 | case 11: root->direction.x = reader->getDouble(); return true; | |||
| 20349 | case 21: root->direction.y = reader->getDouble(); return true; | |||
| 20350 | case 31: root->direction.z = reader->getDouble(); return true; | |||
| 20351 | case 90: root->leaderIndex = reader->getInt32(); return true; | |||
| 20352 | case 40: root->landingDistance = reader->getDouble(); return true; | |||
| 20353 | case 271: root->attachmentDirection = reader->getInt32(); return true; | |||
| 20354 | default: break; | |||
| 20355 | } | |||
| 20356 | return true; // swallow other leader codes | |||
| 20357 | } | |||
| 20358 | ||||
| 20359 | switch (code) { // m_dxfCtxState == 1: CONTEXT_DATA{} | |||
| 20360 | case 40: context.overallScale = reader->getDouble(); return true; | |||
| 20361 | case 10: context.contentBasePoint.x = reader->getDouble(); return true; | |||
| 20362 | case 20: context.contentBasePoint.y = reader->getDouble(); return true; | |||
| 20363 | case 30: context.contentBasePoint.z = reader->getDouble(); return true; | |||
| 20364 | case 41: context.textHeight = reader->getDouble(); return true; | |||
| 20365 | case 140: context.arrowHeadSize = reader->getDouble(); return true; | |||
| 20366 | case 145: context.landingGap = reader->getDouble(); return true; | |||
| 20367 | case 174: context.styleLeftAttach = reader->getInt32(); return true; | |||
| 20368 | case 175: context.styleRightAttach = reader->getInt32(); return true; | |||
| 20369 | case 176: context.textAlignType = reader->getInt32(); return true; | |||
| 20370 | case 177: context.attachmentType = reader->getInt32(); return true; | |||
| 20371 | case 290: context.hasTextContents = (reader->getInt32() != 0); return true; | |||
| 20372 | /* text-content branch */ | |||
| 20373 | case 11: context.textNormal.x = reader->getDouble(); return true; | |||
| 20374 | case 21: context.textNormal.y = reader->getDouble(); return true; | |||
| 20375 | case 31: context.textNormal.z = reader->getDouble(); return true; | |||
| 20376 | case 12: context.textLocation.x = reader->getDouble(); return true; | |||
| 20377 | case 22: context.textLocation.y = reader->getDouble(); return true; | |||
| 20378 | case 32: context.textLocation.z = reader->getDouble(); return true; | |||
| 20379 | case 13: context.textDirection.x = reader->getDouble(); return true; | |||
| 20380 | case 23: context.textDirection.y = reader->getDouble(); return true; | |||
| 20381 | case 33: context.textDirection.z = reader->getDouble(); return true; | |||
| 20382 | case 42: context.textRotation = reader->getDouble(); return true; | |||
| 20383 | case 43: context.boundaryWidth = reader->getDouble(); return true; | |||
| 20384 | case 44: context.boundaryHeight = reader->getDouble(); return true; | |||
| 20385 | case 45: context.lineSpacingFactor = reader->getDouble(); return true; | |||
| 20386 | case 170: context.lineSpacingStyle = reader->getInt32(); return true; | |||
| 20387 | case 90: context.textColor = reader->getInt32(); return true; | |||
| 20388 | case 171: context.alignment = reader->getInt32(); return true; | |||
| 20389 | case 172: context.flowDirection = reader->getInt32(); return true; | |||
| 20390 | case 91: context.bgFillColor = reader->getInt32(); return true; | |||
| 20391 | case 141: context.bgScaleFactor = reader->getDouble(); return true; | |||
| 20392 | case 92: context.bgTransparency = reader->getInt32(); return true; | |||
| 20393 | case 291: context.bgFillEnabled = (reader->getInt32() != 0); return true; | |||
| 20394 | case 292: context.bgMaskFillOn = (reader->getInt32() != 0); return true; | |||
| 20395 | case 173: context.columnType = reader->getInt32(); return true; | |||
| 20396 | case 293: context.textHeightAuto = (reader->getInt32() != 0); return true; | |||
| 20397 | case 142: context.columnWidth = reader->getDouble(); return true; | |||
| 20398 | case 143: context.columnGutter = reader->getDouble(); return true; | |||
| 20399 | case 294: context.columnFlowReversed = (reader->getInt32() != 0); return true; | |||
| 20400 | case 144: | |||
| 20401 | if (context.columnSizes.size() >= static_cast<std::size_t>(kMaxMLeaderItems)) | |||
| 20402 | return false; | |||
| 20403 | context.columnSizes.push_back(reader->getDouble()); | |||
| 20404 | return true; | |||
| 20405 | case 295: context.wordBreak = (reader->getInt32() != 0); return true; | |||
| 20406 | /* block-content branch */ | |||
| 20407 | case 296: context.hasContentsBlock = (reader->getInt32() != 0); return true; | |||
| 20408 | case 14: context.blockNormal.x = reader->getDouble(); return true; | |||
| 20409 | case 24: context.blockNormal.y = reader->getDouble(); return true; | |||
| 20410 | case 34: context.blockNormal.z = reader->getDouble(); return true; | |||
| 20411 | case 15: context.blockLocation.x = reader->getDouble(); return true; | |||
| 20412 | case 25: context.blockLocation.y = reader->getDouble(); return true; | |||
| 20413 | case 35: context.blockLocation.z = reader->getDouble(); return true; | |||
| 20414 | case 16: context.blockScale.x = reader->getDouble(); return true; | |||
| 20415 | case 26: context.blockScale.y = reader->getDouble(); return true; | |||
| 20416 | case 36: context.blockScale.z = reader->getDouble(); return true; | |||
| 20417 | case 46: context.blockRotation = reader->getDouble(); return true; | |||
| 20418 | case 93: context.blockColor = reader->getInt32(); return true; | |||
| 20419 | /* common tail */ | |||
| 20420 | case 110: case 120: case 130: | |||
| 20421 | case 111: case 121: case 131: | |||
| 20422 | case 112: case 122: case 132: | |||
| 20423 | // The helper answers true for every code in this set, so this | |||
| 20424 | // matches the nine `return true` arms it replaces. | |||
| 20425 | return readCoordTripletCode(code, reader, context.basePoint, | |||
| 20426 | context.baseDirection, | |||
| 20427 | context.baseVertical); | |||
| 20428 | case 297: context.isNormalReversed = (reader->getInt32() != 0); return true; | |||
| 20429 | case 272: context.styleBottomAttach = reader->getInt32(); return true; | |||
| 20430 | case 273: context.styleTopAttach = reader->getInt32(); return true; | |||
| 20431 | default: return true; // swallow any other context code | |||
| 20432 | } | |||
| 20433 | } catch (...) { | |||
| 20434 | return false; | |||
| 20435 | } | |||
| 20436 | } | |||
| 20437 | ||||
| 20438 | bool DRW_MLeader::parseCode(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 20439 | // The embedded CONTEXT_DATA{} block (§20.4.86) is routed by the nested-block | |||
| 20440 | // state machine; the remaining (entity-level) fields are read below and | |||
| 20441 | // mirror the DWG body parser. | |||
| 20442 | if (parseDxfContextCode(code, reader)) | |||
| 20443 | return true; | |||
| 20444 | // A failed nested parse must not fall through to the permissive base | |||
| 20445 | // parser: that would silently discard malformed controls or over-limit | |||
| 20446 | // collections and still publish the entity. | |||
| 20447 | if (m_dxfCtxState != 0 || (code >= 300 && code <= 305)) | |||
| 20448 | return false; | |||
| 20449 | switch (code) { | |||
| 20450 | case 170: leaderType = reader->getInt32(); break; | |||
| 20451 | case 171: leaderLineWeight = reader->getInt32(); break; | |||
| 20452 | case 172: styleContentType = reader->getInt32(); break; | |||
| 20453 | case 173: styleLeftAttach = reader->getInt32(); break; | |||
| 20454 | case 95: styleRightAttach = reader->getInt32(); break; | |||
| 20455 | case 174: styleTextAngleType = reader->getInt32(); break; | |||
| 20456 | case 175: unknown175 = reader->getInt32(); break; | |||
| 20457 | case 176: styleAttachmentType = reader->getInt32(); break; | |||
| 20458 | case 178: ipeAlign = reader->getInt32(); break; | |||
| 20459 | case 179: justification = reader->getInt32(); break; | |||
| 20460 | case 271: attachmentDirection = reader->getInt32(); break; | |||
| 20461 | case 272: styleBottomAttach = reader->getInt32(); break; | |||
| 20462 | case 273: styleTopAttach = reader->getInt32(); break; | |||
| 20463 | case 90: overrideFlags = reader->getInt32(); break; | |||
| 20464 | case 91: leaderColor = reader->getInt32(); break; | |||
| 20465 | case 92: styleTextColor = reader->getInt32(); break; | |||
| 20466 | case 93: styleBlockColor = reader->getInt32(); break; | |||
| 20467 | case 41: landingDistance = reader->getDouble(); break; | |||
| 20468 | case 42: defaultArrowHeadSize = reader->getDouble(); break; | |||
| 20469 | case 43: styleBlockRotation = reader->getDouble(); break; | |||
| 20470 | case 45: scaleFactor = reader->getDouble(); break; | |||
| 20471 | case 290: landingEnabled = (reader->getInt32() != 0); break; | |||
| 20472 | case 291: doglegEnabled = (reader->getInt32() != 0); break; | |||
| 20473 | case 292: styleTextFrameEnabled = (reader->getInt32() != 0); break; | |||
| 20474 | case 293: isAnnotative = (reader->getInt32() != 0); break; | |||
| 20475 | case 294: isTextDirectionNegative = (reader->getInt32() != 0); break; | |||
| 20476 | case 295: leaderExtendedToText = (reader->getInt32() != 0); break; | |||
| 20477 | default: | |||
| 20478 | return DRW_Entity::parseCode(code, reader); | |||
| 20479 | } | |||
| 20480 | return true; | |||
| 20481 | } | |||
| 20482 | ||||
| 20483 | // Helper: parse one AcDbMLeaderObjectContextData::LeaderRoot entry (§20.4.86). | |||
| 20484 | // | |||
| 20485 | // Each root has: connection point + direction, optional break pairs, leader | |||
| 20486 | // index, landing distance, then a count-and-list of leader lines. Lines | |||
| 20487 | // themselves carry: point list, break-info pairs, and (R2010+) per-line | |||
| 20488 | // style overrides. The handles inside (line-type / arrow per leader line) | |||
| 20489 | // are deferred to the entity-level handle stream and not stored here. | |||
| 20490 | static bool parseMLeaderRoot(DRW::Version version, dwgBuffer *buf, | |||
| 20491 | std::uint32_t objectSize, | |||
| 20492 | std::uint64_t bodyEndBit, | |||
| 20493 | DRW_MLeaderRoot& root) { | |||
| 20494 | // Layout per libreDWG dwg2.spec:1316-1366 (Dwg_LEADER_Node + Dwg_LEADER_Line). | |||
| 20495 | // The two 3BD coords at the head of the node are conditional on the | |||
| 20496 | // preceding B flags; reading them unconditionally drifts the bit stream | |||
| 20497 | // when either flag is 0. | |||
| 20498 | bool hasLastPt = false; | |||
| 20499 | bool hasDogleg = false; | |||
| 20500 | if (!readBoundedBit(*buf, bodyEndBit, hasLastPt) | |||
| 20501 | || !readBoundedBit(*buf, bodyEndBit, hasDogleg)) | |||
| 20502 | return false; // 290 has_lastleaderlinepoint, 291 has_dogleg | |||
| 20503 | root.isContentValid = hasLastPt; | |||
| 20504 | root.unknown291 = hasDogleg; | |||
| 20505 | if (hasLastPt) { | |||
| 20506 | if (!readBoundedBitCoord(*buf, bodyEndBit, root.connectionPoint)) | |||
| 20507 | return false; | |||
| 20508 | } | |||
| 20509 | if (hasDogleg) { | |||
| 20510 | if (!readBoundedBitCoord(*buf, bodyEndBit, root.direction)) | |||
| 20511 | return false; | |||
| 20512 | } | |||
| 20513 | ||||
| 20514 | std::uint32_t nBreaks = 0; | |||
| 20515 | if (!readTableBodyCount(version, buf, objectSize, kMaxMLeaderItems, 12, | |||
| 20516 | nBreaks)) | |||
| 20517 | return false; | |||
| 20518 | if (!DRW::reserve(root.breaks, static_cast<int>(nBreaks))) | |||
| 20519 | return false; | |||
| 20520 | for (std::uint32_t i = 0; i < nBreaks; ++i) { | |||
| 20521 | DRW_Coord a; | |||
| 20522 | DRW_Coord b; | |||
| 20523 | if (!readBoundedBitCoord(*buf, bodyEndBit, a) | |||
| 20524 | || !readBoundedBitCoord(*buf, bodyEndBit, b)) | |||
| 20525 | return false; | |||
| 20526 | root.breaks.emplace_back(a, b); | |||
| 20527 | } | |||
| 20528 | ||||
| 20529 | if (!readBoundedBitLong(*buf, bodyEndBit, root.leaderIndex) | |||
| 20530 | || !readBoundedBitDouble(*buf, bodyEndBit, root.landingDistance)) | |||
| 20531 | return false; | |||
| 20532 | ||||
| 20533 | std::uint32_t nLines = 0; | |||
| 20534 | if (!readTableBodyCount(version, buf, objectSize, kMaxMLeaderItems, 6, | |||
| 20535 | nLines)) | |||
| 20536 | return false; | |||
| 20537 | if (!DRW::reserve(root.leaderLines, static_cast<int>(nLines))) | |||
| 20538 | return false; | |||
| 20539 | for (std::uint32_t i = 0; i < nLines; ++i) { | |||
| 20540 | DRW_MLeaderLeaderLine line; | |||
| 20541 | // Per libreDWG: BL num_points, points, BL num_breaks, breaks, BL line_index. | |||
| 20542 | // The previous 5-BL layout (brkInfoCount + segmentIndex + nPairs + | |||
| 20543 | // pairs + leaderLineIndex) inserted two spurious BL reads, drifting | |||
| 20544 | // every subsequent entity-level field (overallScale, contentType, …). | |||
| 20545 | std::uint32_t nPts = 0; | |||
| 20546 | if (!readTableBodyCount(version, buf, objectSize, kMaxMLeaderItems, 6, | |||
| 20547 | nPts)) | |||
| 20548 | return false; | |||
| 20549 | if (!DRW::reserve(line.points, static_cast<int>(nPts))) | |||
| 20550 | return false; | |||
| 20551 | for (std::uint32_t j = 0; j < nPts; ++j) { | |||
| 20552 | DRW_Coord point; | |||
| 20553 | if (!readBoundedBitCoord(*buf, bodyEndBit, point)) | |||
| 20554 | return false; | |||
| 20555 | line.points.push_back(point); | |||
| 20556 | } | |||
| 20557 | std::uint32_t nLineBreaks = 0; | |||
| 20558 | if (!readTableBodyCount(version, buf, objectSize, kMaxMLeaderItems, | |||
| 20559 | 12, nLineBreaks)) | |||
| 20560 | return false; | |||
| 20561 | for (std::uint32_t j = 0; j < nLineBreaks; ++j) { | |||
| 20562 | DRW_Coord a; | |||
| 20563 | DRW_Coord b; | |||
| 20564 | if (!readBoundedBitCoord(*buf, bodyEndBit, a) | |||
| 20565 | || !readBoundedBitCoord(*buf, bodyEndBit, b)) | |||
| 20566 | return false; | |||
| 20567 | line.breaks.emplace_back(a, b); | |||
| 20568 | } | |||
| 20569 | if (!readBoundedBitLong(*buf, bodyEndBit, line.leaderLineIndex)) | |||
| 20570 | return false; | |||
| 20571 | ||||
| 20572 | // R2010+ per-line override block. The spec marks this block "R2010" | |||
| 20573 | // (§20.4.86 page 215); the override flags BL 93 says which fields | |||
| 20574 | // were overridden. The handle fields (340 line-type, 341 arrow) are | |||
| 20575 | // deferred to the trailing handle stream. | |||
| 20576 | if (version >= DRW::AC1024) { | |||
| 20577 | if (!readBoundedBitShort(*buf, bodyEndBit, line.leaderType)) | |||
| 20578 | return false; | |||
| 20579 | std::uint32_t parsedColor = 0; | |||
| 20580 | if (!readBoundedCmColor(*buf, nullptr, bodyEndBit, version, | |||
| 20581 | parsedColor)) | |||
| 20582 | return false; | |||
| 20583 | line.color = static_cast<int>(parsedColor); | |||
| 20584 | // line type handle 340 — read from handles section later | |||
| 20585 | if (!readBoundedBitLong(*buf, bodyEndBit, line.lineWeight) | |||
| 20586 | || !readBoundedBitDouble(*buf, bodyEndBit, line.arrowSize) | |||
| 20587 | || !readBoundedBitLong(*buf, bodyEndBit, | |||
| 20588 | line.overrideFlags)) | |||
| 20589 | return false; | |||
| 20590 | // arrow handle 341 — handles section | |||
| 20591 | } | |||
| 20592 | root.leaderLines.push_back(std::move(line)); | |||
| 20593 | } | |||
| 20594 | ||||
| 20595 | if (version >= DRW::AC1024) { | |||
| 20596 | if (!readBoundedBitShort(*buf, bodyEndBit, root.attachmentDirection)) | |||
| 20597 | return false; | |||
| 20598 | } | |||
| 20599 | ||||
| 20600 | return buf->isGood(); | |||
| 20601 | } | |||
| 20602 | ||||
| 20603 | // Helper: parse the AcDbMLeaderObjectContextData (§20.4.86) payload, the | |||
| 20604 | // large embedded block at the start of the MLEADER body that carries the | |||
| 20605 | // leader geometry plus either text or block content. | |||
| 20606 | static bool parseMLeaderAnnotContext(DRW::Version version, dwgBuffer *buf, | |||
| 20607 | dwgBuffer *sBuf, | |||
| 20608 | std::uint32_t objectSize, | |||
| 20609 | std::uint64_t bodyEndBit, | |||
| 20610 | std::uint64_t stringEndBit, | |||
| 20611 | DRW_MLeaderAnnotContext& ctx) { | |||
| 20612 | // NOTE: when AcDbMLeaderObjectContextData is embedded INSIDE the MLEADER | |||
| 20613 | // entity body (rather than serialized as a standalone object), the | |||
| 20614 | // AcDbObjectContextData base preamble (BS version, B has-file-ext-dict, | |||
| 20615 | // B default-flag) does NOT appear in the bit stream — those fields are | |||
| 20616 | // standalone-object metadata. The embedded AnnotContext starts directly | |||
| 20617 | // with the leader-roots count. Its standalone-object scale handle is | |||
| 20618 | // likewise absent from this embedded payload. | |||
| 20619 | ||||
| 20620 | // Number of leader roots. | |||
| 20621 | std::int32_t nRoots = 0; | |||
| 20622 | if (!readBoundedBitLong(*buf, bodyEndBit, nRoots)) | |||
| 20623 | return false; | |||
| 20624 | if (nRoots == 0) { | |||
| 20625 | if (!proxyEntityHasBits(*buf, bodyEndBit, 7)) | |||
| 20626 | return false; | |||
| 20627 | bool rootCountBits[7] = {}; | |||
| 20628 | for (bool& rootCountBit : rootCountBits) { | |||
| 20629 | if (!readBoundedBit(*buf, bodyEndBit, rootCountBit)) | |||
| 20630 | return false; | |||
| 20631 | } | |||
| 20632 | nRoots = rootCountBits[5] ? 2 : 1; | |||
| 20633 | } | |||
| 20634 | if (!isValidCount(nRoots, kMaxMLeaderItems)) return false; | |||
| 20635 | std::uint64_t minimumRootBits = 0; | |||
| 20636 | if (!dwgSafety::multiply(static_cast<std::uint64_t>(nRoots), 10, | |||
| 20637 | minimumRootBits) | |||
| 20638 | || !proxyEntityHasBits(*buf, bodyEndBit, minimumRootBits)) { | |||
| 20639 | return false; | |||
| 20640 | } | |||
| 20641 | ctx.roots.clear(); | |||
| 20642 | if (!DRW::reserve(ctx.roots, nRoots)) | |||
| 20643 | return false; | |||
| 20644 | for (std::int32_t i = 0; i < nRoots; ++i) { | |||
| 20645 | DRW_MLeaderRoot root; | |||
| 20646 | if (!parseMLeaderRoot(version, buf, objectSize, bodyEndBit, root)) | |||
| 20647 | return false; | |||
| 20648 | ctx.roots.push_back(std::move(root)); | |||
| 20649 | } | |||
| 20650 | ||||
| 20651 | // Common content fields. | |||
| 20652 | if (!readBoundedBitDouble(*buf, bodyEndBit, ctx.overallScale) | |||
| 20653 | || !readBoundedBitCoord(*buf, bodyEndBit, ctx.contentBasePoint) | |||
| 20654 | || !readBoundedBitDouble(*buf, bodyEndBit, ctx.textHeight) | |||
| 20655 | || !readBoundedBitDouble(*buf, bodyEndBit, ctx.arrowHeadSize) | |||
| 20656 | || !readBoundedBitDouble(*buf, bodyEndBit, ctx.landingGap) | |||
| 20657 | || !readBoundedBitShort(*buf, bodyEndBit, ctx.styleLeftAttach) | |||
| 20658 | || !readBoundedBitShort(*buf, bodyEndBit, ctx.styleRightAttach) | |||
| 20659 | || !readBoundedBitShort(*buf, bodyEndBit, ctx.textAlignType) | |||
| 20660 | || !readBoundedBitShort(*buf, bodyEndBit, ctx.attachmentType) | |||
| 20661 | || !readBoundedBit(*buf, bodyEndBit, ctx.hasTextContents)) | |||
| 20662 | return false; | |||
| 20663 | ||||
| 20664 | if (ctx.hasTextContents) { | |||
| 20665 | if (!readBoundedVariableText(*sBuf, stringEndBit, version, | |||
| 20666 | ctx.textLabel)) | |||
| 20667 | return false; | |||
| 20668 | if (!readBoundedBitCoord(*buf, bodyEndBit, ctx.textNormal)) | |||
| 20669 | return false; | |||
| 20670 | // text style handle 340 — handles section | |||
| 20671 | if (!readBoundedBitCoord(*buf, bodyEndBit, ctx.textLocation) | |||
| 20672 | || !readBoundedBitCoord(*buf, bodyEndBit, ctx.textDirection) | |||
| 20673 | || !readBoundedBitDouble(*buf, bodyEndBit, ctx.textRotation) | |||
| 20674 | || !readBoundedBitDouble(*buf, bodyEndBit, ctx.boundaryWidth) | |||
| 20675 | || !readBoundedBitDouble(*buf, bodyEndBit, ctx.boundaryHeight) | |||
| 20676 | || !readBoundedBitDouble(*buf, bodyEndBit, | |||
| 20677 | ctx.lineSpacingFactor) | |||
| 20678 | || !readBoundedBitShort(*buf, bodyEndBit, ctx.lineSpacingStyle)) | |||
| 20679 | return false; | |||
| 20680 | std::uint32_t parsedTextColor = 0; | |||
| 20681 | if (!readBoundedCmColor(*buf, sBuf, bodyEndBit, version, | |||
| 20682 | parsedTextColor, nullptr, nullptr, nullptr, | |||
| 20683 | nullptr, stringEndBit)) | |||
| 20684 | return false; | |||
| 20685 | ctx.textColor = static_cast<int>(parsedTextColor); | |||
| 20686 | if (!readBoundedBitShort(*buf, bodyEndBit, ctx.alignment) | |||
| 20687 | || !readBoundedBitShort(*buf, bodyEndBit, ctx.flowDirection)) | |||
| 20688 | return false; | |||
| 20689 | std::uint32_t parsedBgFillColor = 0; | |||
| 20690 | if (!readBoundedCmColor(*buf, sBuf, bodyEndBit, version, | |||
| 20691 | parsedBgFillColor, nullptr, nullptr, nullptr, | |||
| 20692 | nullptr, stringEndBit)) | |||
| 20693 | return false; | |||
| 20694 | ctx.bgFillColor = static_cast<int>(parsedBgFillColor); | |||
| 20695 | if (!readBoundedBitDouble(*buf, bodyEndBit, ctx.bgScaleFactor) | |||
| 20696 | || !readBoundedBitLong(*buf, bodyEndBit, ctx.bgTransparency) | |||
| 20697 | || !readBoundedBit(*buf, bodyEndBit, ctx.bgFillEnabled) | |||
| 20698 | || !readBoundedBit(*buf, bodyEndBit, ctx.bgMaskFillOn) | |||
| 20699 | || !readBoundedBitShort(*buf, bodyEndBit, ctx.columnType) | |||
| 20700 | || !readBoundedBit(*buf, bodyEndBit, ctx.textHeightAuto) | |||
| 20701 | || !readBoundedBitDouble(*buf, bodyEndBit, ctx.columnWidth) | |||
| 20702 | || !readBoundedBitDouble(*buf, bodyEndBit, ctx.columnGutter) | |||
| 20703 | || !readBoundedBit(*buf, bodyEndBit, ctx.columnFlowReversed)) | |||
| 20704 | return false; | |||
| 20705 | std::uint32_t nColSizes = 0; | |||
| 20706 | if (!readTableBodyCount(version, buf, objectSize, kMaxMLeaderItems, 2, | |||
| 20707 | nColSizes)) | |||
| 20708 | return false; | |||
| 20709 | if (!DRW::reserve(ctx.columnSizes, static_cast<int>(nColSizes))) | |||
| 20710 | return false; | |||
| 20711 | for (std::uint32_t i = 0; i < nColSizes; ++i) { | |||
| 20712 | double columnSize = 0.0; | |||
| 20713 | if (!readBoundedBitDouble(*buf, bodyEndBit, columnSize)) | |||
| 20714 | return false; | |||
| 20715 | ctx.columnSizes.push_back(columnSize); | |||
| 20716 | } | |||
| 20717 | bool ignoredBit = false; | |||
| 20718 | if (!readBoundedBit(*buf, bodyEndBit, ctx.wordBreak) | |||
| 20719 | || !readBoundedBit(*buf, bodyEndBit, ignoredBit)) | |||
| 20720 | return false; // unknown trailing bit | |||
| 20721 | } else { | |||
| 20722 | if (!readBoundedBit(*buf, bodyEndBit, ctx.hasContentsBlock)) | |||
| 20723 | return false; | |||
| 20724 | if (ctx.hasContentsBlock) { | |||
| 20725 | // BlockTableRecord handle 341 — deferred | |||
| 20726 | if (!readBoundedBitCoord(*buf, bodyEndBit, ctx.blockNormal) | |||
| 20727 | || !readBoundedBitCoord(*buf, bodyEndBit, ctx.blockLocation) | |||
| 20728 | || !readBoundedBitCoord(*buf, bodyEndBit, ctx.blockScale) | |||
| 20729 | || !readBoundedBitDouble(*buf, bodyEndBit, | |||
| 20730 | ctx.blockRotation)) | |||
| 20731 | return false; | |||
| 20732 | std::uint32_t parsedBlockColor = 0; | |||
| 20733 | if (!readBoundedCmColor(*buf, sBuf, bodyEndBit, version, | |||
| 20734 | parsedBlockColor, nullptr, nullptr, nullptr, | |||
| 20735 | nullptr, stringEndBit)) | |||
| 20736 | return false; | |||
| 20737 | ctx.blockColor = static_cast<int>(parsedBlockColor); | |||
| 20738 | for (size_t i = 0; i < 16; ++i) { | |||
| 20739 | if (!readBoundedBitDouble(*buf, bodyEndBit, | |||
| 20740 | ctx.blockTransform[i])) | |||
| 20741 | return false; | |||
| 20742 | } | |||
| 20743 | } | |||
| 20744 | } | |||
| 20745 | ||||
| 20746 | // Common tail. | |||
| 20747 | if (!readBoundedBitCoord(*buf, bodyEndBit, ctx.basePoint) | |||
| 20748 | || !readBoundedBitCoord(*buf, bodyEndBit, ctx.baseDirection) | |||
| 20749 | || !readBoundedBitCoord(*buf, bodyEndBit, ctx.baseVertical) | |||
| 20750 | || !readBoundedBit(*buf, bodyEndBit, ctx.isNormalReversed)) | |||
| 20751 | return false; | |||
| 20752 | ||||
| 20753 | if (version >= DRW::AC1024) { | |||
| 20754 | if (!readBoundedBitShort(*buf, bodyEndBit, ctx.styleTopAttach) | |||
| 20755 | || !readBoundedBitShort(*buf, bodyEndBit, ctx.styleBottomAttach)) | |||
| 20756 | return false; | |||
| 20757 | } | |||
| 20758 | ||||
| 20759 | return buf->isGood() && sBuf->isGood(); | |||
| 20760 | } | |||
| 20761 | ||||
| 20762 | static bool encodeMLeaderRoot(DRW::Version version, dwgBufferW *buf, | |||
| 20763 | const DRW_MLeaderRoot& root) { | |||
| 20764 | if (root.breaks.size() > DRW_MLeader::kMaxLeaderPoints | |||
| 20765 | || root.leaderLines.size() > DRW_MLeader::kMaxLeaderLines) | |||
| 20766 | return false; | |||
| 20767 | ||||
| 20768 | buf->putBit(root.isContentValid ? 1 : 0); | |||
| 20769 | buf->putBit(root.unknown291 ? 1 : 0); | |||
| 20770 | if (root.isContentValid) | |||
| 20771 | buf->put3BitDouble(root.connectionPoint); | |||
| 20772 | if (root.unknown291) | |||
| 20773 | buf->put3BitDouble(root.direction); | |||
| 20774 | ||||
| 20775 | buf->putBitLong(static_cast<std::int32_t>(root.breaks.size())); | |||
| 20776 | for (const auto& brk : root.breaks) { | |||
| 20777 | buf->put3BitDouble(brk.first); | |||
| 20778 | buf->put3BitDouble(brk.second); | |||
| 20779 | } | |||
| 20780 | ||||
| 20781 | buf->putBitLong(root.leaderIndex); | |||
| 20782 | buf->putBitDouble(root.landingDistance); | |||
| 20783 | ||||
| 20784 | buf->putBitLong(static_cast<std::int32_t>(root.leaderLines.size())); | |||
| 20785 | for (const DRW_MLeaderLeaderLine& line : root.leaderLines) { | |||
| 20786 | if (line.points.size() > DRW_MLeader::kMaxLeaderPoints | |||
| 20787 | || line.breaks.size() > DRW_MLeader::kMaxLeaderPoints) | |||
| 20788 | return false; | |||
| 20789 | buf->putBitLong(static_cast<std::int32_t>(line.points.size())); | |||
| 20790 | for (const DRW_Coord& point : line.points) | |||
| 20791 | buf->put3BitDouble(point); | |||
| 20792 | ||||
| 20793 | buf->putBitLong(static_cast<std::int32_t>(line.breaks.size())); | |||
| 20794 | for (const auto& brk : line.breaks) { | |||
| 20795 | buf->put3BitDouble(brk.first); | |||
| 20796 | buf->put3BitDouble(brk.second); | |||
| 20797 | } | |||
| 20798 | buf->putBitLong(line.leaderLineIndex); | |||
| 20799 | ||||
| 20800 | if (version >= DRW::AC1024) { | |||
| 20801 | buf->putBitShort(line.leaderType); | |||
| 20802 | buf->putCmColor(version, static_cast<std::uint16_t>(line.color)); | |||
| 20803 | buf->putBitLong(line.lineWeight); | |||
| 20804 | buf->putBitDouble(line.arrowSize); | |||
| 20805 | buf->putBitLong(line.overrideFlags); | |||
| 20806 | } | |||
| 20807 | } | |||
| 20808 | ||||
| 20809 | if (version >= DRW::AC1024) | |||
| 20810 | buf->putBitShort(root.attachmentDirection); | |||
| 20811 | ||||
| 20812 | return true; | |||
| 20813 | } | |||
| 20814 | ||||
| 20815 | static bool encodeMLeaderAnnotContext(DRW::Version version, dwgBufferW *buf, | |||
| 20816 | dwgBufferW *strBuf, | |||
| 20817 | const DRW_MLeaderAnnotContext& ctx) { | |||
| 20818 | if (ctx.roots.size() > DRW_MLeader::kMaxRoots | |||
| 20819 | || ctx.columnSizes.size() > DRW_MLeader::kMaxLeaderPoints) | |||
| 20820 | return false; | |||
| 20821 | if (ctx.hasContentsBlock) | |||
| 20822 | return false; | |||
| 20823 | ||||
| 20824 | buf->putBitLong(static_cast<std::int32_t>(ctx.roots.size())); | |||
| 20825 | for (const DRW_MLeaderRoot& root : ctx.roots) { | |||
| 20826 | if (!encodeMLeaderRoot(version, buf, root)) | |||
| 20827 | return false; | |||
| 20828 | } | |||
| 20829 | ||||
| 20830 | buf->putBitDouble(ctx.overallScale); | |||
| 20831 | buf->put3BitDouble(ctx.contentBasePoint); | |||
| 20832 | buf->putBitDouble(ctx.textHeight); | |||
| 20833 | buf->putBitDouble(ctx.arrowHeadSize); | |||
| 20834 | buf->putBitDouble(ctx.landingGap); | |||
| 20835 | buf->putBitShort(ctx.styleLeftAttach); | |||
| 20836 | buf->putBitShort(ctx.styleRightAttach); | |||
| 20837 | buf->putBitShort(ctx.textAlignType); | |||
| 20838 | buf->putBitShort(ctx.attachmentType); | |||
| 20839 | buf->putBit(ctx.hasTextContents ? 1 : 0); | |||
| 20840 | ||||
| 20841 | if (ctx.hasTextContents) { | |||
| 20842 | (strBuf ? strBuf : buf)->putVariableText(version, ctx.textLabel); | |||
| 20843 | buf->put3BitDouble(ctx.textNormal); | |||
| 20844 | buf->put3BitDouble(ctx.textLocation); | |||
| 20845 | buf->put3BitDouble(ctx.textDirection); | |||
| 20846 | buf->putBitDouble(ctx.textRotation); | |||
| 20847 | buf->putBitDouble(ctx.boundaryWidth); | |||
| 20848 | buf->putBitDouble(ctx.boundaryHeight); | |||
| 20849 | buf->putBitDouble(ctx.lineSpacingFactor); | |||
| 20850 | buf->putBitShort(ctx.lineSpacingStyle); | |||
| 20851 | buf->putCmColor(version, static_cast<std::uint16_t>(ctx.textColor)); | |||
| 20852 | buf->putBitShort(ctx.alignment); | |||
| 20853 | buf->putBitShort(ctx.flowDirection); | |||
| 20854 | buf->putCmColor(version, static_cast<std::uint16_t>(ctx.bgFillColor)); | |||
| 20855 | buf->putBitDouble(ctx.bgScaleFactor); | |||
| 20856 | buf->putBitLong(ctx.bgTransparency); | |||
| 20857 | buf->putBit(ctx.bgFillEnabled ? 1 : 0); | |||
| 20858 | buf->putBit(ctx.bgMaskFillOn ? 1 : 0); | |||
| 20859 | buf->putBitShort(ctx.columnType); | |||
| 20860 | buf->putBit(ctx.textHeightAuto ? 1 : 0); | |||
| 20861 | buf->putBitDouble(ctx.columnWidth); | |||
| 20862 | buf->putBitDouble(ctx.columnGutter); | |||
| 20863 | buf->putBit(ctx.columnFlowReversed ? 1 : 0); | |||
| 20864 | buf->putBitLong(static_cast<std::int32_t>(ctx.columnSizes.size())); | |||
| 20865 | for (double columnSize : ctx.columnSizes) | |||
| 20866 | buf->putBitDouble(columnSize); | |||
| 20867 | buf->putBit(ctx.wordBreak ? 1 : 0); | |||
| 20868 | buf->putBit(0); | |||
| 20869 | } else { | |||
| 20870 | buf->putBit(0); // hasContentsBlock | |||
| 20871 | } | |||
| 20872 | ||||
| 20873 | buf->put3BitDouble(ctx.basePoint); | |||
| 20874 | buf->put3BitDouble(ctx.baseDirection); | |||
| 20875 | buf->put3BitDouble(ctx.baseVertical); | |||
| 20876 | buf->putBit(ctx.isNormalReversed ? 1 : 0); | |||
| 20877 | ||||
| 20878 | if (version >= DRW::AC1024) { | |||
| 20879 | buf->putBitShort(ctx.styleTopAttach); | |||
| 20880 | buf->putBitShort(ctx.styleBottomAttach); | |||
| 20881 | } | |||
| 20882 | ||||
| 20883 | return true; | |||
| 20884 | } | |||
| 20885 | ||||
| 20886 | void DRW_MLeader::resetDwgState() { | |||
| 20887 | DRW_Entity::reset(); | |||
| 20888 | context = DRW_MLeaderAnnotContext{}; | |||
| 20889 | classVersion = 2; | |||
| 20890 | styleHandle = dwgHandle{}; | |||
| 20891 | overrideFlags = 0; | |||
| 20892 | leaderType = 1; | |||
| 20893 | leaderColor = 0; | |||
| 20894 | leaderLineTypeHandle = dwgHandle{}; | |||
| 20895 | leaderLineWeight = 0; | |||
| 20896 | landingEnabled = true; | |||
| 20897 | doglegEnabled = true; | |||
| 20898 | landingDistance = 0.0; | |||
| 20899 | arrowHeadHandle = dwgHandle{}; | |||
| 20900 | defaultArrowHeadSize = 0.0; | |||
| 20901 | styleContentType = 2; | |||
| 20902 | styleTextStyleHandle = dwgHandle{}; | |||
| 20903 | styleLeftAttach = 0; | |||
| 20904 | styleRightAttach = 0; | |||
| 20905 | styleTextAngleType = 0; | |||
| 20906 | unknown175 = 0; | |||
| 20907 | styleTextColor = 0; | |||
| 20908 | styleTextFrameEnabled = false; | |||
| 20909 | styleBlockHandle = dwgHandle{}; | |||
| 20910 | styleBlockColor = 0; | |||
| 20911 | styleBlockScale = DRW_Coord{1.0, 1.0, 1.0}; | |||
| 20912 | styleBlockRotation = 0.0; | |||
| 20913 | styleAttachmentType = 0; | |||
| 20914 | isAnnotative = false; | |||
| 20915 | arrowHeads.clear(); | |||
| 20916 | blockLabels.clear(); | |||
| 20917 | isTextDirectionNegative = false; | |||
| 20918 | ipeAlign = 0; | |||
| 20919 | justification = 0; | |||
| 20920 | scaleFactor = 1.0; | |||
| 20921 | attachmentDirection = 0; | |||
| 20922 | styleTopAttach = 0; | |||
| 20923 | styleBottomAttach = 0; | |||
| 20924 | leaderExtendedToText = false; | |||
| 20925 | m_dxfCtxState = 0; | |||
| 20926 | } | |||
| 20927 | ||||
| 20928 | bool DRW_MLeader::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){ | |||
| 20929 | resetDwgState(); | |||
| 20930 | dwgBuffer *sourceBuf = buf; | |||
| 20931 | auto fail = [this, sourceBuf]() { | |||
| 20932 | if (sourceBuf != nullptr) | |||
| 20933 | sourceBuf->invalidate(); | |||
| 20934 | resetDwgState(); | |||
| 20935 | return false; | |||
| 20936 | }; | |||
| 20937 | if (sourceBuf == nullptr) | |||
| 20938 | return fail(); | |||
| 20939 | ||||
| 20940 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 20941 | buf = &bodyProbe; | |||
| 20942 | ||||
| 20943 | dwgBuffer sBuff = buf->forkIndependent(); | |||
| 20944 | dwgBuffer *sBuf = buf; | |||
| 20945 | if (version > DRW::AC1018) { // 2007+ | |||
| 20946 | sBuf = &sBuff; | |||
| 20947 | } | |||
| 20948 | bool ret = DRW_Entity::parseDwg(version, buf, sBuf, bs); | |||
| 20949 | if (!ret) return fail(); | |||
| 20950 | DRW_DBG("\n***************************** parsing MLEADER ***************\n")DRW_dbg::dbg("\n***************************** parsing MLEADER ***************\n" ); | |||
| 20951 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 20952 | std::uint64_t stringEndBit = bodyEndBit; | |||
| 20953 | if (version > DRW::AC1021) { | |||
| 20954 | std::uint64_t ignoredBodyEndBit = 0; | |||
| 20955 | if (!entityBodyDataEndBit(*sBuf, version, objSize, | |||
| 20956 | ignoredBodyEndBit, &stringEndBit)) | |||
| 20957 | return fail(); | |||
| 20958 | } | |||
| 20959 | ||||
| 20960 | // R2010b+ class version (BS, default 2; <=R2004 was 1). libreDWG | |||
| 20961 | // dwg2.spec:1303-1306. Absent in R2007 streams; reading it would drift. | |||
| 20962 | if (version >= DRW::AC1024) { | |||
| 20963 | if (!readBoundedBitShort(*buf, bodyEndBit, classVersion)) | |||
| 20964 | return fail(); | |||
| 20965 | if (classVersion > 10) { | |||
| 20966 | DRW_DBG("\nMLEADER: implausible classVersion=")DRW_dbg::dbg("\nMLEADER: implausible classVersion="); | |||
| 20967 | DRW_DBG(static_cast<int>(classVersion))DRW_dbg::dbg(static_cast<int>(classVersion)); | |||
| 20968 | DRW_DBG(", aborting body\n")DRW_dbg::dbg(", aborting body\n"); | |||
| 20969 | return fail(); | |||
| 20970 | } | |||
| 20971 | } | |||
| 20972 | ||||
| 20973 | // Phase 4 — embedded AcDbMLeaderObjectContextData / MLeaderAnnotContext. | |||
| 20974 | if (!parseMLeaderAnnotContext(version, buf, sBuf, objSize, bodyEndBit, | |||
| 20975 | stringEndBit, context)) { | |||
| 20976 | DRW_DBG("\nMLEADER: AnnotContext parse failed\n")DRW_dbg::dbg("\nMLEADER: AnnotContext parse failed\n"); | |||
| 20977 | return fail(); | |||
| 20978 | } | |||
| 20979 | ||||
| 20980 | // Phase 3 — entity-level fields per §20.4.48 (after the AnnotContext). | |||
| 20981 | // Many handle slots are deferred to the trailing handle stream and not | |||
| 20982 | // stored here yet (resolution comes in Phase 7). | |||
| 20983 | if (!readBoundedBitLong(*buf, bodyEndBit, overrideFlags) | |||
| 20984 | || !readBoundedBitShort(*buf, bodyEndBit, leaderType)) | |||
| 20985 | return fail(); | |||
| 20986 | std::uint32_t parsedColor = 0; | |||
| 20987 | if (!readBoundedCmColor(*buf, sBuf, bodyEndBit, version, parsedColor, | |||
| 20988 | nullptr, nullptr, nullptr, nullptr, | |||
| 20989 | stringEndBit)) | |||
| 20990 | return fail(); | |||
| 20991 | leaderColor = static_cast<int>(parsedColor); | |||
| 20992 | // leader line type handle 341 — handle stream | |||
| 20993 | if (!readBoundedBitLong(*buf, bodyEndBit, leaderLineWeight) | |||
| 20994 | || !readBoundedBit(*buf, bodyEndBit, landingEnabled) | |||
| 20995 | || !readBoundedBit(*buf, bodyEndBit, doglegEnabled) | |||
| 20996 | || !readBoundedBitDouble(*buf, bodyEndBit, landingDistance)) | |||
| 20997 | return fail(); | |||
| 20998 | // arrow head handle 342 — handle stream | |||
| 20999 | if (!readBoundedBitDouble(*buf, bodyEndBit, defaultArrowHeadSize) | |||
| 21000 | || !readBoundedBitShort(*buf, bodyEndBit, styleContentType)) | |||
| 21001 | return fail(); | |||
| 21002 | // text style handle 343 — handle stream | |||
| 21003 | if (!readBoundedBitShort(*buf, bodyEndBit, styleLeftAttach) | |||
| 21004 | || !readBoundedBitShort(*buf, bodyEndBit, styleRightAttach) | |||
| 21005 | || !readBoundedBitShort(*buf, bodyEndBit, styleTextAngleType) | |||
| 21006 | || !readBoundedBitShort(*buf, bodyEndBit, unknown175)) | |||
| 21007 | return fail(); | |||
| 21008 | if (!readBoundedCmColor(*buf, sBuf, bodyEndBit, version, parsedColor, | |||
| 21009 | nullptr, nullptr, nullptr, nullptr, | |||
| 21010 | stringEndBit)) | |||
| 21011 | return fail(); | |||
| 21012 | styleTextColor = static_cast<int>(parsedColor); | |||
| 21013 | if (!readBoundedBit(*buf, bodyEndBit, styleTextFrameEnabled)) | |||
| 21014 | return fail(); | |||
| 21015 | // style block handle 344 — handle stream (optional) | |||
| 21016 | if (!readBoundedCmColor(*buf, sBuf, bodyEndBit, version, parsedColor, | |||
| 21017 | nullptr, nullptr, nullptr, nullptr, | |||
| 21018 | stringEndBit)) | |||
| 21019 | return fail(); | |||
| 21020 | styleBlockColor = static_cast<int>(parsedColor); | |||
| 21021 | if (!readBoundedBitCoord(*buf, bodyEndBit, styleBlockScale) | |||
| 21022 | || !readBoundedBitDouble(*buf, bodyEndBit, styleBlockRotation) | |||
| 21023 | || !readBoundedBitShort(*buf, bodyEndBit, styleAttachmentType) | |||
| 21024 | || !readBoundedBit(*buf, bodyEndBit, isAnnotative)) | |||
| 21025 | return fail(); | |||
| 21026 | ||||
| 21027 | // R2007 arrays (pre-R2010 only): per spec §20.4.48. Bounds-check the | |||
| 21028 | // counts; a misaligned bit stream would produce huge nonsense values. | |||
| 21029 | if (version < DRW::AC1024) { | |||
| 21030 | std::uint32_t nArrows = 0; | |||
| 21031 | if (!readTableBodyCount(version, buf, objSize, kMaxMLeaderItems, 1, | |||
| 21032 | nArrows)) | |||
| 21033 | return fail(); | |||
| 21034 | if (!DRW::reserve(arrowHeads, static_cast<int>(nArrows))) | |||
| 21035 | return fail(); | |||
| 21036 | for (std::uint32_t i = 0; i < nArrows; ++i) { | |||
| 21037 | ArrowHeadEntry e; | |||
| 21038 | if (!readBoundedBit(*buf, bodyEndBit, e.isDefault)) | |||
| 21039 | return fail(); | |||
| 21040 | arrowHeads.push_back(e); | |||
| 21041 | } | |||
| 21042 | std::uint32_t nLabels = 0; | |||
| 21043 | if (!readTableBodyCount(version, buf, objSize, kMaxMLeaderItems, 4, | |||
| 21044 | nLabels)) | |||
| 21045 | return fail(); | |||
| 21046 | if (!DRW::reserve(blockLabels, static_cast<int>(nLabels))) | |||
| 21047 | return fail(); | |||
| 21048 | for (std::uint32_t i = 0; i < nLabels; ++i) { | |||
| 21049 | BlockLabelEntry e; | |||
| 21050 | if (!readBoundedVariableText(*sBuf, stringEndBit, version, | |||
| 21051 | e.labelText)) | |||
| 21052 | return fail(); | |||
| 21053 | if (!readBoundedBitShort(*buf, bodyEndBit, e.uiIndex) | |||
| 21054 | || !readBoundedBitDouble(*buf, bodyEndBit, e.width)) | |||
| 21055 | return fail(); | |||
| 21056 | blockLabels.push_back(std::move(e)); | |||
| 21057 | } | |||
| 21058 | if (!readBoundedBit(*buf, bodyEndBit, isTextDirectionNegative) | |||
| 21059 | || !readBoundedBitShort(*buf, bodyEndBit, ipeAlign) | |||
| 21060 | || !readBoundedBitShort(*buf, bodyEndBit, justification) | |||
| 21061 | || !readBoundedBitDouble(*buf, bodyEndBit, scaleFactor)) | |||
| 21062 | return fail(); | |||
| 21063 | } else { // R2010+ | |||
| 21064 | if (!readBoundedBitShort(*buf, bodyEndBit, attachmentDirection) | |||
| 21065 | || !readBoundedBitShort(*buf, bodyEndBit, styleTopAttach) | |||
| 21066 | || !readBoundedBitShort(*buf, bodyEndBit, styleBottomAttach)) | |||
| 21067 | return fail(); | |||
| 21068 | } | |||
| 21069 | if (version >= DRW::AC1027) { // R2013+ | |||
| 21070 | if (!readBoundedBit(*buf, bodyEndBit, leaderExtendedToText)) | |||
| 21071 | return fail(); | |||
| 21072 | } | |||
| 21073 | ||||
| 21074 | if (!buf->isGood() || !sBuf->isGood() | |||
| 21075 | || currentDwgBit(buf) > bodyEndBit | |||
| 21076 | || currentDwgBit(sBuf) > stringEndBit) | |||
| 21077 | return fail(); | |||
| 21078 | ||||
| 21079 | std::uint64_t handleEndBit = 0; | |||
| 21080 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, | |||
| 21081 | handleEndBit)) | |||
| 21082 | return fail(); | |||
| 21083 | // Common entity handles first (owner/reactors/xdic/layer/ltype/...) — | |||
| 21084 | // entity-specific handles follow in declared order from libreDWG | |||
| 21085 | // dwg2.spec. Read order in the trailing handle stream: | |||
| 21086 | // 1. (R2010b+ only) per-leader-line ltype + arrow handles, in the | |||
| 21087 | // same iteration order as the body block. | |||
| 21088 | // 2. AnnotContext content handle (text_style 340 if hasTextContents, | |||
| 21089 | // else block_table 341 if hasContentsBlock). | |||
| 21090 | // 3. mleaderstyle (340), line_ltype (341), arrow_handle (342), | |||
| 21091 | // text_style (343), block_style (344) entity-level handles. | |||
| 21092 | // 4. (R14-R2007 only) per-arrowhead + per-blocklabel handles. | |||
| 21093 | ret = DRW_Entity::parseDwgEntHandle(version, buf, true, handleEndBit); | |||
| 21094 | if (!ret) | |||
| 21095 | return fail(); | |||
| 21096 | ||||
| 21097 | auto safeHandle = [&](dwgHandle& slot, const char* tag) { | |||
| 21098 | if (!readBoundedDwgHandle(*buf, handleEndBit, 0, false, slot)) | |||
| 21099 | return false; | |||
| 21100 | DRW_DBG(" ")DRW_dbg::dbg(" "); DRW_DBG(tag)DRW_dbg::dbg(tag); DRW_DBG(": ")DRW_dbg::dbg(": "); | |||
| 21101 | DRW_DBGHL(slot.code, slot.size, slot.ref)DRW_dbg::dbgHL(slot.code, slot.size, slot.ref); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 21102 | return true; | |||
| 21103 | }; | |||
| 21104 | ||||
| 21105 | // 1. R2010b+ per-line handles, in body iteration order. | |||
| 21106 | if (version >= DRW::AC1024) { | |||
| 21107 | for (auto& root : context.roots) { | |||
| 21108 | for (auto& line : root.leaderLines) { | |||
| 21109 | if (!safeHandle(line.lineTypeHandle, "line.ltype")) return fail(); | |||
| 21110 | if (!safeHandle(line.arrowHandle, "line.arrow")) return fail(); | |||
| 21111 | } | |||
| 21112 | } | |||
| 21113 | } | |||
| 21114 | ||||
| 21115 | // 2. AnnotContext content handle. | |||
| 21116 | if (context.hasTextContents) { | |||
| 21117 | if (!safeHandle(context.textStyleHandle, "ctx.text_style")) return fail(); | |||
| 21118 | } else if (context.hasContentsBlock) { | |||
| 21119 | if (!safeHandle(context.blockTableRecordHandle, "ctx.block_table")) return fail(); | |||
| 21120 | } | |||
| 21121 | ||||
| 21122 | // 3. Entity-level handles. | |||
| 21123 | if (!safeHandle(styleHandle, "mleaderstyle")) return fail(); | |||
| 21124 | if (!safeHandle(leaderLineTypeHandle, "line_ltype")) return fail(); | |||
| 21125 | if (!safeHandle(arrowHeadHandle, "arrow_handle")) return fail(); | |||
| 21126 | if (!safeHandle(styleTextStyleHandle, "text_style")) return fail(); | |||
| 21127 | if (!safeHandle(styleBlockHandle, "block_style")) return fail(); | |||
| 21128 | ||||
| 21129 | // 4. R14-R2007 per-arrowhead + per-blocklabel handles (counts came | |||
| 21130 | // from the body-side arrays read earlier). | |||
| 21131 | if (version < DRW::AC1024) { | |||
| 21132 | for (auto& a : arrowHeads) | |||
| 21133 | if (!safeHandle(a.handle, "arrowheads.handle")) return fail(); | |||
| 21134 | for (auto& bl : blockLabels) | |||
| 21135 | if (!safeHandle(bl.attDefHandle, "blocklabels.attdef")) return fail(); | |||
| 21136 | } | |||
| 21137 | ||||
| 21138 | const int rb = buf->numRemainingBytes(); | |||
| 21139 | DRW_DBG("\nMLEADER tail rb=")DRW_dbg::dbg("\nMLEADER tail rb="); DRW_DBG(rb)DRW_dbg::dbg(rb); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 21140 | if (rb > 4) { | |||
| 21141 | DRW_DBG("MLEADER: handle-stream tail ")DRW_dbg::dbg("MLEADER: handle-stream tail "); DRW_DBG(rb)DRW_dbg::dbg(rb); | |||
| 21142 | DRW_DBG(" bytes unconsumed (handle ")DRW_dbg::dbg(" bytes unconsumed (handle "); | |||
| 21143 | DRW_DBGH(handle)DRW_dbg::dbgH(handle); DRW_DBG(") — review tail handle list\n")DRW_dbg::dbg(") — review tail handle list\n"); | |||
| 21144 | } | |||
| 21145 | ||||
| 21146 | if (!buf->isGood() || !sBuf->isGood()) | |||
| 21147 | return fail(); | |||
| 21148 | *sourceBuf = *buf; | |||
| 21149 | return true; | |||
| 21150 | } | |||
| 21151 | ||||
| 21152 | bool DRW_MLeader::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, | |||
| 21153 | dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 21154 | (void)bs; | |||
| 21155 | if (version < DRW::AC1024) | |||
| 21156 | return false; | |||
| 21157 | ||||
| 21158 | oType = kDwgClassNum; | |||
| 21159 | if (!encodeDwgCommon(version, buf, strBuf)) | |||
| 21160 | return false; | |||
| 21161 | ||||
| 21162 | buf->putBitShort(classVersion == 0 ? 2 : classVersion); | |||
| 21163 | if (!encodeMLeaderAnnotContext(version, buf, strBuf, context)) | |||
| 21164 | return false; | |||
| 21165 | ||||
| 21166 | buf->putBitLong(overrideFlags); | |||
| 21167 | buf->putBitShort(leaderType); | |||
| 21168 | buf->putCmColor(version, static_cast<std::uint16_t>(leaderColor)); | |||
| 21169 | buf->putBitLong(leaderLineWeight); | |||
| 21170 | buf->putBit(landingEnabled ? 1 : 0); | |||
| 21171 | buf->putBit(doglegEnabled ? 1 : 0); | |||
| 21172 | buf->putBitDouble(landingDistance); | |||
| 21173 | buf->putBitDouble(defaultArrowHeadSize); | |||
| 21174 | buf->putBitShort(styleContentType); | |||
| 21175 | buf->putBitShort(styleLeftAttach); | |||
| 21176 | buf->putBitShort(styleRightAttach); | |||
| 21177 | buf->putBitShort(styleTextAngleType); | |||
| 21178 | buf->putBitShort(unknown175); | |||
| 21179 | buf->putCmColor(version, static_cast<std::uint16_t>(styleTextColor)); | |||
| 21180 | buf->putBit(styleTextFrameEnabled ? 1 : 0); | |||
| 21181 | buf->putCmColor(version, static_cast<std::uint16_t>(styleBlockColor)); | |||
| 21182 | buf->put3BitDouble(styleBlockScale); | |||
| 21183 | buf->putBitDouble(styleBlockRotation); | |||
| 21184 | buf->putBitShort(styleAttachmentType); | |||
| 21185 | buf->putBit(isAnnotative ? 1 : 0); | |||
| 21186 | buf->putBitShort(attachmentDirection); | |||
| 21187 | buf->putBitShort(styleTopAttach); | |||
| 21188 | buf->putBitShort(styleBottomAttach); | |||
| 21189 | if (version >= DRW::AC1027) | |||
| 21190 | buf->putBit(leaderExtendedToText ? 1 : 0); | |||
| 21191 | ||||
| 21192 | if (!encodeDwgEntHandle(version, buf, handleBuf)) | |||
| 21193 | return false; | |||
| 21194 | ||||
| 21195 | dwgBufferW *hb = handleBuf ? handleBuf : buf; | |||
| 21196 | for (const DRW_MLeaderRoot& root : context.roots) { | |||
| 21197 | for (const DRW_MLeaderLeaderLine& line : root.leaderLines) { | |||
| 21198 | putHardPointerHandle(hb, line.lineTypeHandle.ref); | |||
| 21199 | putHardPointerHandle(hb, line.arrowHandle.ref); | |||
| 21200 | } | |||
| 21201 | } | |||
| 21202 | ||||
| 21203 | if (context.hasTextContents) { | |||
| 21204 | putHardPointerHandle(hb, context.textStyleHandle.ref); | |||
| 21205 | } else if (context.hasContentsBlock) { | |||
| 21206 | putHardPointerHandle(hb, context.blockTableRecordHandle.ref); | |||
| 21207 | } | |||
| 21208 | ||||
| 21209 | putHardPointerHandle(hb, styleHandle.ref); | |||
| 21210 | putHardPointerHandle(hb, leaderLineTypeHandle.ref); | |||
| 21211 | putHardPointerHandle(hb, arrowHeadHandle.ref); | |||
| 21212 | putHardPointerHandle(hb, styleTextStyleHandle.ref); | |||
| 21213 | putHardPointerHandle(hb, styleBlockHandle.ref); | |||
| 21214 | ||||
| 21215 | return true; | |||
| 21216 | } | |||
| 21217 | ||||
| 21218 | bool DRW_Viewport::parseCode(int code, const std::unique_ptr<dxfReader>& reader){ | |||
| 21219 | switch (code) { | |||
| 21220 | case 40: | |||
| 21221 | pswidth = reader->getDouble(); | |||
| 21222 | break; | |||
| 21223 | case 41: | |||
| 21224 | psheight = reader->getDouble(); | |||
| 21225 | break; | |||
| 21226 | case 68: | |||
| 21227 | vpstatus = reader->getInt32(); | |||
| 21228 | break; | |||
| 21229 | case 69: | |||
| 21230 | vpID = reader->getInt32(); | |||
| 21231 | break; | |||
| 21232 | case 12: | |||
| 21233 | centerPX = reader->getDouble(); | |||
| 21234 | break; | |||
| 21235 | case 22: | |||
| 21236 | centerPY = reader->getDouble(); | |||
| 21237 | break; | |||
| 21238 | case 13: | |||
| 21239 | snapPX = reader->getDouble(); | |||
| 21240 | break; | |||
| 21241 | case 23: | |||
| 21242 | snapPY = reader->getDouble(); | |||
| 21243 | break; | |||
| 21244 | case 14: | |||
| 21245 | snapSpPX = reader->getDouble(); | |||
| 21246 | break; | |||
| 21247 | case 24: | |||
| 21248 | snapSpPY = reader->getDouble(); | |||
| 21249 | break; | |||
| 21250 | case 15: | |||
| 21251 | gridSpX = reader->getDouble(); | |||
| 21252 | break; | |||
| 21253 | case 25: | |||
| 21254 | gridSpY = reader->getDouble(); | |||
| 21255 | break; | |||
| 21256 | case 16: | |||
| 21257 | viewDir.x = reader->getDouble(); | |||
| 21258 | break; | |||
| 21259 | case 26: | |||
| 21260 | viewDir.y = reader->getDouble(); | |||
| 21261 | break; | |||
| 21262 | case 36: | |||
| 21263 | viewDir.z = reader->getDouble(); | |||
| 21264 | break; | |||
| 21265 | case 17: | |||
| 21266 | viewTarget.x = reader->getDouble(); | |||
| 21267 | break; | |||
| 21268 | case 27: | |||
| 21269 | viewTarget.y = reader->getDouble(); | |||
| 21270 | break; | |||
| 21271 | case 37: | |||
| 21272 | viewTarget.z = reader->getDouble(); | |||
| 21273 | break; | |||
| 21274 | case 42: | |||
| 21275 | viewLength = reader->getDouble(); | |||
| 21276 | break; | |||
| 21277 | case 43: | |||
| 21278 | frontClip = reader->getDouble(); | |||
| 21279 | break; | |||
| 21280 | case 44: | |||
| 21281 | backClip = reader->getDouble(); | |||
| 21282 | break; | |||
| 21283 | case 45: | |||
| 21284 | viewHeight = reader->getDouble(); | |||
| 21285 | break; | |||
| 21286 | case 50: | |||
| 21287 | snapAngle = reader->getDouble(); | |||
| 21288 | break; | |||
| 21289 | case 51: | |||
| 21290 | twistAngle = reader->getDouble(); | |||
| 21291 | break; | |||
| 21292 | case 46: | |||
| 21293 | circleZoom = reader->getInt32(); | |||
| 21294 | break; | |||
| 21295 | case 61: | |||
| 21296 | majorGridLines = reader->getInt32(); | |||
| 21297 | break; | |||
| 21298 | case 63: | |||
| 21299 | ambientColor = static_cast<std::uint32_t>(reader->getInt32()); | |||
| 21300 | break; | |||
| 21301 | case 72: | |||
| 21302 | circleZoom = reader->getInt32(); | |||
| 21303 | break; | |||
| 21304 | case 90: | |||
| 21305 | statusFlags = reader->getInt32(); | |||
| 21306 | break; | |||
| 21307 | case 1: | |||
| 21308 | styleSheet = reader->getUtf8String(); | |||
| 21309 | break; | |||
| 21310 | case 281: | |||
| 21311 | renderMode = reader->getInt32(); | |||
| 21312 | break; | |||
| 21313 | case 71: | |||
| 21314 | ucsPerViewport = reader->getInt32() != 0; | |||
| 21315 | break; | |||
| 21316 | case 74: | |||
| 21317 | ucsAtOrigin = reader->getInt32() != 0; | |||
| 21318 | break; | |||
| 21319 | case 110: case 120: case 130: | |||
| 21320 | case 111: case 121: case 131: | |||
| 21321 | case 112: case 122: case 132: | |||
| 21322 | readCoordTripletCode(code, reader, ucsOrigin, ucsXAxis, ucsYAxis); | |||
| 21323 | break; | |||
| 21324 | case 146: | |||
| 21325 | ucsElevation = reader->getDouble(); | |||
| 21326 | break; | |||
| 21327 | case 76: | |||
| 21328 | break; | |||
| 21329 | case 79: | |||
| 21330 | ucsOrthographicType = reader->getInt32(); | |||
| 21331 | break; | |||
| 21332 | case 148: | |||
| 21333 | shadePlotMode = reader->getInt32(); | |||
| 21334 | break; | |||
| 21335 | case 170: | |||
| 21336 | shadePlotMode = reader->getInt32(); | |||
| 21337 | break; | |||
| 21338 | case 292: | |||
| 21339 | useDefaultLighting = reader->getInt32() != 0; | |||
| 21340 | break; | |||
| 21341 | case 282: | |||
| 21342 | defaultLightingType = reader->getInt32(); | |||
| 21343 | break; | |||
| 21344 | case 451: | |||
| 21345 | brightness = reader->getDouble(); | |||
| 21346 | break; | |||
| 21347 | case 452: | |||
| 21348 | contrast = reader->getDouble(); | |||
| 21349 | break; | |||
| 21350 | case 141: | |||
| 21351 | brightness = reader->getDouble(); | |||
| 21352 | break; | |||
| 21353 | case 142: | |||
| 21354 | contrast = reader->getDouble(); | |||
| 21355 | break; | |||
| 21356 | case 421: | |||
| 21357 | ambientColorRgb = reader->getInt32(); | |||
| 21358 | break; | |||
| 21359 | case 431: | |||
| 21360 | ambientColorName = reader->getUtf8String(); | |||
| 21361 | break; | |||
| 21362 | case 331: | |||
| 21363 | frozenLayerHandles.push_back( | |||
| 21364 | static_cast<std::uint32_t>(reader->getHandleString())); | |||
| 21365 | break; | |||
| 21366 | case 332: | |||
| 21367 | backgroundHandle = static_cast<std::uint32_t>(reader->getHandleString()); | |||
| 21368 | break; | |||
| 21369 | case 333: | |||
| 21370 | shadePlotHandle = static_cast<std::uint32_t>(reader->getHandleString()); | |||
| 21371 | break; | |||
| 21372 | case 340: | |||
| 21373 | clipBoundaryHandle = static_cast<std::uint32_t>(reader->getHandleString()); | |||
| 21374 | break; | |||
| 21375 | case 345: | |||
| 21376 | namedUcsHandle = static_cast<std::uint32_t>(reader->getHandleString()); | |||
| 21377 | break; | |||
| 21378 | case 346: | |||
| 21379 | baseUcsHandle = static_cast<std::uint32_t>(reader->getHandleString()); | |||
| 21380 | break; | |||
| 21381 | case 361: | |||
| 21382 | m_sunHandle = static_cast<std::uint32_t>(reader->getHandleString()); | |||
| 21383 | break; | |||
| 21384 | case 348: | |||
| 21385 | visualStyleHandle = static_cast<std::uint32_t>(reader->getHandleString()); | |||
| 21386 | fullVisualStyleHandle = visualStyleHandle; | |||
| 21387 | break; | |||
| 21388 | case 349: | |||
| 21389 | shadePlotHandle = static_cast<std::uint32_t>(reader->getHandleString()); | |||
| 21390 | break; | |||
| 21391 | default: | |||
| 21392 | return DRW_Point::parseCode(code, reader); | |||
| 21393 | } | |||
| 21394 | ||||
| 21395 | return true; | |||
| 21396 | } | |||
| 21397 | ||||
| 21398 | bool DRW_Viewport::validatePayloadFields() const { | |||
| 21399 | const auto finite = [](const DRW_Coord& point) { | |||
| 21400 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 21401 | && std::isfinite(point.z); | |||
| 21402 | }; | |||
| 21403 | const auto fitsSignedShort = [](int value) { | |||
| 21404 | return value >= static_cast<int>(std::numeric_limits<std::int16_t>::min()) | |||
| 21405 | && value <= static_cast<int>(std::numeric_limits<std::int16_t>::max()); | |||
| 21406 | }; | |||
| 21407 | const auto fitsByte = [](int value) { | |||
| 21408 | return value >= 0 | |||
| 21409 | && value <= static_cast<int>(std::numeric_limits<std::uint8_t>::max()); | |||
| 21410 | }; | |||
| 21411 | const auto fitsBitShort = [](int value) { | |||
| 21412 | return value >= 0 | |||
| 21413 | && value <= static_cast<int>(std::numeric_limits<std::uint16_t>::max()); | |||
| 21414 | }; | |||
| 21415 | const bool integralCircleZoom = std::isfinite(circleZoom) | |||
| 21416 | && std::trunc(circleZoom) == circleZoom; | |||
| 21417 | return finite(basePoint) && finite(viewTarget) && finite(viewDir) | |||
| 21418 | && finite(ucsOrigin) && finite(ucsXAxis) && finite(ucsYAxis) | |||
| 21419 | && std::isfinite(pswidth) && std::isfinite(psheight) | |||
| 21420 | && std::isfinite(centerPX) && std::isfinite(centerPY) | |||
| 21421 | && std::isfinite(snapPX) && std::isfinite(snapPY) | |||
| 21422 | && std::isfinite(snapSpPX) && std::isfinite(snapSpPY) | |||
| 21423 | && std::isfinite(gridSpX) && std::isfinite(gridSpY) | |||
| 21424 | && std::isfinite(viewLength) && std::isfinite(frontClip) | |||
| 21425 | && std::isfinite(backClip) && std::isfinite(viewHeight) | |||
| 21426 | && std::isfinite(snapAngle) && std::isfinite(twistAngle) | |||
| 21427 | && std::isfinite(ucsElevation) && std::isfinite(brightness) | |||
| 21428 | && std::isfinite(contrast) && fitsSignedShort(vpstatus) | |||
| 21429 | && fitsSignedShort(vpID) && integralCircleZoom | |||
| 21430 | && circleZoom >= 0.0 | |||
| 21431 | && circleZoom <= static_cast<double>(std::numeric_limits<std::uint16_t>::max()) | |||
| 21432 | && fitsBitShort(majorGridLines) && fitsByte(renderMode) | |||
| 21433 | && fitsBitShort(ucsOrthographicType) && fitsBitShort(shadePlotMode) | |||
| 21434 | && fitsByte(defaultLightingType) | |||
| 21435 | && ambientColor <= std::numeric_limits<std::uint16_t>::max() | |||
| 21436 | && ambientColorRgb >= -1 && ambientColorRgb <= 0xFFFFFF | |||
| 21437 | && frozenLayerHandles.size() <= kMaxViewportFrozenLayers; | |||
| 21438 | } | |||
| 21439 | ||||
| 21440 | bool DRW_Viewport::validateDxf() const { | |||
| 21441 | return validatePayloadFields(); | |||
| 21442 | } | |||
| 21443 | //ex 22 dec 34 | |||
| 21444 | void DRW_Viewport::resetDwgState() { | |||
| 21445 | DRW_Point::resetDwgState(); | |||
| 21446 | pswidth = 205.0; | |||
| 21447 | psheight = 156.0; | |||
| 21448 | vpstatus = 0; | |||
| 21449 | vpID = 0; | |||
| 21450 | centerPX = 128.5; | |||
| 21451 | centerPY = 97.5; | |||
| 21452 | snapPX = snapPY = 0.0; | |||
| 21453 | snapSpPX = snapSpPY = 10.0; | |||
| 21454 | gridSpX = gridSpY = 10.0; | |||
| 21455 | viewDir = DRW_Coord{0.0, 0.0, 1.0}; | |||
| 21456 | viewTarget = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 21457 | viewLength = 50.0; | |||
| 21458 | frontClip = backClip = 0.0; | |||
| 21459 | viewHeight = 1.0; | |||
| 21460 | snapAngle = twistAngle = 0.0; | |||
| 21461 | circleZoom = 100.0; | |||
| 21462 | majorGridLines = 0; | |||
| 21463 | statusFlags = 0; | |||
| 21464 | styleSheet.clear(); | |||
| 21465 | renderMode = 0; | |||
| 21466 | ucsAtOrigin = false; | |||
| 21467 | ucsPerViewport = false; | |||
| 21468 | ucsOrigin = DRW_Coord{0.0, 0.0, 0.0}; | |||
| 21469 | ucsXAxis = DRW_Coord{1.0, 0.0, 0.0}; | |||
| 21470 | ucsYAxis = DRW_Coord{0.0, 1.0, 0.0}; | |||
| 21471 | ucsElevation = 0.0; | |||
| 21472 | ucsOrthographicType = 0; | |||
| 21473 | shadePlotMode = 0; | |||
| 21474 | useDefaultLighting = true; | |||
| 21475 | defaultLightingType = 1; | |||
| 21476 | brightness = contrast = 0.0; | |||
| 21477 | ambientColor = 250; | |||
| 21478 | ambientColorRgb = -1; | |||
| 21479 | ambientColorMethod = 0; | |||
| 21480 | ambientColorName.clear(); | |||
| 21481 | vpHeaderHandle = 0; | |||
| 21482 | clipBoundaryHandle = 0; | |||
| 21483 | namedUcsHandle = 0; | |||
| 21484 | baseUcsHandle = 0; | |||
| 21485 | backgroundHandle = 0; | |||
| 21486 | visualStyleHandle = 0; | |||
| 21487 | shadePlotHandle = 0; | |||
| 21488 | m_sunHandle = 0; | |||
| 21489 | frozenLayerHandles.clear(); | |||
| 21490 | frozenLyCount = 0; | |||
| 21491 | } | |||
| 21492 | ||||
| 21493 | bool DRW_Viewport::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs){ | |||
| 21494 | resetDwgState(); | |||
| 21495 | dwgBuffer *sourceBuf = buf; | |||
| 21496 | auto fail = [this, sourceBuf]() { | |||
| 21497 | if (sourceBuf != nullptr) | |||
| 21498 | sourceBuf->invalidate(); | |||
| 21499 | resetDwgState(); | |||
| 21500 | return false; | |||
| 21501 | }; | |||
| 21502 | if (sourceBuf == nullptr) | |||
| 21503 | return fail(); | |||
| 21504 | ||||
| 21505 | dwgBuffer bodyProbe = sourceBuf->forkIndependent(); | |||
| 21506 | buf = &bodyProbe; | |||
| 21507 | dwgBuffer sBuff = bodyProbe.forkIndependent(); | |||
| 21508 | dwgBuffer *sBuf = buf; | |||
| 21509 | if (version > DRW::AC1018) {//2007+ | |||
| 21510 | sBuf = &sBuff; //separate buffer for strings | |||
| 21511 | } | |||
| 21512 | bool ret = DRW_Entity::parseDwg(version, buf, sBuf, bs); | |||
| 21513 | if (!ret) | |||
| 21514 | return fail(); | |||
| 21515 | DRW_DBG("\n***************************** parsing viewport *****************************************\n")DRW_dbg::dbg("\n***************************** parsing viewport *****************************************\n" ); | |||
| 21516 | const std::uint64_t bodyEndBit = dwgDataEndBit; | |||
| 21517 | std::uint64_t stringEndBit = bodyEndBit; | |||
| 21518 | if (version > DRW::AC1021) { | |||
| 21519 | std::uint64_t ignoredBodyEndBit = 0; | |||
| 21520 | if (!entityBodyDataEndBit(*sBuf, version, objSize, | |||
| 21521 | ignoredBodyEndBit, &stringEndBit)) | |||
| 21522 | return fail(); | |||
| 21523 | } | |||
| 21524 | if (!readBoundedBitCoord(*buf, bodyEndBit, basePoint) | |||
| 21525 | || !readBoundedBitDouble(*buf, bodyEndBit, pswidth) | |||
| 21526 | || !readBoundedBitDouble(*buf, bodyEndBit, psheight)) | |||
| 21527 | return fail(); | |||
| 21528 | DRW_DBG("center ")DRW_dbg::dbg("center "); DRW_DBGPT(basePoint.x, basePoint.y, basePoint.z)DRW_dbg::dbgPT(basePoint.x, basePoint.y, basePoint.z); | |||
| 21529 | DRW_DBG("\nWidth: ")DRW_dbg::dbg("\nWidth: "); DRW_DBG(pswidth)DRW_dbg::dbg(pswidth); DRW_DBG(", Height: ")DRW_dbg::dbg(", Height: "); DRW_DBG(psheight)DRW_dbg::dbg(psheight); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 21530 | //RLZ TODO: complete in dxf | |||
| 21531 | if (version > DRW::AC1014) {//2000+ | |||
| 21532 | if (!readBoundedBitCoord(*buf, bodyEndBit, viewTarget) | |||
| 21533 | || !readBoundedBitCoord(*buf, bodyEndBit, viewDir) | |||
| 21534 | || !readBoundedBitDouble(*buf, bodyEndBit, twistAngle) | |||
| 21535 | || !readBoundedBitDouble(*buf, bodyEndBit, viewHeight) | |||
| 21536 | || !readBoundedBitDouble(*buf, bodyEndBit, viewLength) | |||
| 21537 | || !readBoundedBitDouble(*buf, bodyEndBit, frontClip) | |||
| 21538 | || !readBoundedBitDouble(*buf, bodyEndBit, backClip) | |||
| 21539 | || !readBoundedBitDouble(*buf, bodyEndBit, snapAngle) | |||
| 21540 | || !readBoundedRawDouble(*buf, bodyEndBit, centerPX) | |||
| 21541 | || !readBoundedRawDouble(*buf, bodyEndBit, centerPY) | |||
| 21542 | || !readBoundedRawDouble(*buf, bodyEndBit, snapPX) | |||
| 21543 | || !readBoundedRawDouble(*buf, bodyEndBit, snapPY) | |||
| 21544 | || !readBoundedRawDouble(*buf, bodyEndBit, snapSpPX) | |||
| 21545 | || !readBoundedRawDouble(*buf, bodyEndBit, snapSpPY) | |||
| 21546 | || !readBoundedRawDouble(*buf, bodyEndBit, gridSpX) | |||
| 21547 | || !readBoundedRawDouble(*buf, bodyEndBit, gridSpY)) | |||
| 21548 | return fail(); | |||
| 21549 | DRW_DBG("view Target ")DRW_dbg::dbg("view Target "); DRW_DBGPT(viewTarget.x, viewTarget.y, viewTarget.z)DRW_dbg::dbgPT(viewTarget.x, viewTarget.y, viewTarget.z); | |||
| 21550 | DRW_DBG("\nview direction ")DRW_dbg::dbg("\nview direction "); DRW_DBGPT(viewDir.x, viewDir.y, viewDir.z)DRW_dbg::dbgPT(viewDir.x, viewDir.y, viewDir.z); | |||
| 21551 | DRW_DBG("\nView twist Angle: ")DRW_dbg::dbg("\nView twist Angle: "); DRW_DBG(twistAngle)DRW_dbg::dbg(twistAngle); | |||
| 21552 | DRW_DBG("\nview Height: ")DRW_dbg::dbg("\nview Height: "); DRW_DBG(viewHeight)DRW_dbg::dbg(viewHeight); | |||
| 21553 | DRW_DBG(" Lens Length: ")DRW_dbg::dbg(" Lens Length: "); DRW_DBG(viewLength)DRW_dbg::dbg(viewLength); | |||
| 21554 | DRW_DBG("\nfront Clip Z: ")DRW_dbg::dbg("\nfront Clip Z: "); DRW_DBG(frontClip)DRW_dbg::dbg(frontClip); | |||
| 21555 | DRW_DBG(" back Clip Z: ")DRW_dbg::dbg(" back Clip Z: "); DRW_DBG(backClip)DRW_dbg::dbg(backClip); | |||
| 21556 | DRW_DBG("\n snap Angle: ")DRW_dbg::dbg("\n snap Angle: "); DRW_DBG(snapAngle)DRW_dbg::dbg(snapAngle); | |||
| 21557 | DRW_DBG("\nview center X: ")DRW_dbg::dbg("\nview center X: "); DRW_DBG(centerPX)DRW_dbg::dbg(centerPX); DRW_DBG(", Y: ")DRW_dbg::dbg(", Y: "); DRW_DBG(centerPX)DRW_dbg::dbg(centerPX); | |||
| 21558 | DRW_DBG("\nSnap base point X: ")DRW_dbg::dbg("\nSnap base point X: "); DRW_DBG(snapPX)DRW_dbg::dbg(snapPX); DRW_DBG(", Y: ")DRW_dbg::dbg(", Y: "); DRW_DBG(snapPY)DRW_dbg::dbg(snapPY); | |||
| 21559 | DRW_DBG("\nSnap spacing X: ")DRW_dbg::dbg("\nSnap spacing X: "); DRW_DBG(snapSpPX)DRW_dbg::dbg(snapSpPX); DRW_DBG(", Y: ")DRW_dbg::dbg(", Y: "); DRW_DBG(snapSpPY)DRW_dbg::dbg(snapSpPY); | |||
| 21560 | std::uint16_t parsedCircleZoom = 0; | |||
| 21561 | if (!readBoundedBitShort(*buf, bodyEndBit, parsedCircleZoom)) | |||
| 21562 | return fail(); | |||
| 21563 | circleZoom = parsedCircleZoom; | |||
| 21564 | } | |||
| 21565 | if (version > DRW::AC1018) {//2007+ | |||
| 21566 | std::uint16_t parsedMajorGridLines = 0; | |||
| 21567 | if (!readBoundedBitShort(*buf, bodyEndBit, parsedMajorGridLines)) | |||
| 21568 | return fail(); | |||
| 21569 | majorGridLines = parsedMajorGridLines; | |||
| 21570 | } | |||
| 21571 | if (version > DRW::AC1014) {//2000+ | |||
| 21572 | std::int32_t parsedFrozenLyCount = 0; | |||
| 21573 | if (!readBoundedBitLong(*buf, bodyEndBit, parsedFrozenLyCount)) | |||
| 21574 | return fail(); | |||
| 21575 | if (!isValidCount(parsedFrozenLyCount, kMaxViewportFrozenLayers)) | |||
| 21576 | return fail(); | |||
| 21577 | frozenLyCount = static_cast<std::uint32_t>(parsedFrozenLyCount); | |||
| 21578 | DRW_DBG("Frozen Layer count?: ")DRW_dbg::dbg("Frozen Layer count?: "); DRW_DBG(frozenLyCount)DRW_dbg::dbg(frozenLyCount); DRW_DBG("\n")DRW_dbg::dbg("\n"); | |||
| 21579 | if (!readBoundedBitLong(*buf, bodyEndBit, statusFlags)) | |||
| 21580 | return fail(); | |||
| 21581 | if (!readBoundedVariableText(*sBuf, stringEndBit, version, | |||
| 21582 | styleSheet)) | |||
| 21583 | return fail(); | |||
| 21584 | std::uint8_t parsedRenderMode = 0; | |||
| 21585 | if (!readBoundedRawChar8(*buf, bodyEndBit, parsedRenderMode)) | |||
| 21586 | return fail(); | |||
| 21587 | renderMode = parsedRenderMode; | |||
| 21588 | // ODA order is UCS-at-origin (74), then UCS-per-viewport (71). | |||
| 21589 | if (!readBoundedBit(*buf, bodyEndBit, ucsAtOrigin) | |||
| 21590 | || !readBoundedBit(*buf, bodyEndBit, ucsPerViewport) | |||
| 21591 | || !readBoundedBitCoord(*buf, bodyEndBit, ucsOrigin) | |||
| 21592 | || !readBoundedBitCoord(*buf, bodyEndBit, ucsXAxis) | |||
| 21593 | || !readBoundedBitCoord(*buf, bodyEndBit, ucsYAxis) | |||
| 21594 | || !readBoundedBitDouble(*buf, bodyEndBit, ucsElevation)) | |||
| 21595 | return fail(); | |||
| 21596 | std::uint16_t parsedUcsOrthographicType = 0; | |||
| 21597 | if (!readBoundedBitShort(*buf, bodyEndBit, | |||
| 21598 | parsedUcsOrthographicType)) | |||
| 21599 | return fail(); | |||
| 21600 | ucsOrthographicType = parsedUcsOrthographicType; | |||
| 21601 | } | |||
| 21602 | if (version > DRW::AC1015) {//2004+ | |||
| 21603 | std::uint16_t parsedShadePlotMode = 0; | |||
| 21604 | if (!readBoundedBitShort(*buf, bodyEndBit, parsedShadePlotMode)) | |||
| 21605 | return fail(); | |||
| 21606 | shadePlotMode = parsedShadePlotMode; | |||
| 21607 | } | |||
| 21608 | if (version > DRW::AC1018) {//2007+ | |||
| 21609 | std::uint8_t parsedDefaultLightingType = 0; | |||
| 21610 | if (!readBoundedBit(*buf, bodyEndBit, useDefaultLighting) | |||
| 21611 | || !readBoundedRawChar8(*buf, bodyEndBit, | |||
| 21612 | parsedDefaultLightingType) | |||
| 21613 | || !readBoundedBitDouble(*buf, bodyEndBit, brightness) | |||
| 21614 | || !readBoundedBitDouble(*buf, bodyEndBit, contrast)) | |||
| 21615 | return fail(); | |||
| 21616 | defaultLightingType = parsedDefaultLightingType; | |||
| 21617 | // ODA §20.4.38: ambient color is CMC, not ENC — confirmed by libreDWG dwg.spec:2512 | |||
| 21618 | bool hasRgbColor = false; | |||
| 21619 | int parsedAmbientColorRgb = -1; | |||
| 21620 | UTF8STRINGstd::string parsedAmbientColorName; | |||
| 21621 | UTF8STRINGstd::string parsedAmbientColorBookName; | |||
| 21622 | dwgBuffer colorProbe = buf->forkIndependent(); | |||
| 21623 | dwgBuffer colorStringProbe = sBuf->forkIndependent(); | |||
| 21624 | const std::uint32_t parsedAmbientColor = colorProbe.getCmColor( | |||
| 21625 | version, &parsedAmbientColorRgb, &colorStringProbe, | |||
| 21626 | &parsedAmbientColorName, &parsedAmbientColorBookName, | |||
| 21627 | &hasRgbColor); | |||
| 21628 | if (!colorProbe.isGood() || !colorStringProbe.isGood() | |||
| 21629 | || currentDwgBit(&colorProbe) > bodyEndBit | |||
| 21630 | || currentDwgBit(&colorStringProbe) > stringEndBit) | |||
| 21631 | return fail(); | |||
| 21632 | *buf = colorProbe; | |||
| 21633 | *sBuf = colorStringProbe; | |||
| 21634 | ambientColor = parsedAmbientColor; | |||
| 21635 | ambientColorRgb = parsedAmbientColorRgb; | |||
| 21636 | ambientColorName = parsedAmbientColorBookName.empty() | |||
| 21637 | ? std::move(parsedAmbientColorName) | |||
| 21638 | : (parsedAmbientColorBookName + "$" | |||
| 21639 | + parsedAmbientColorName); | |||
| 21640 | if (!hasRgbColor) | |||
| 21641 | ambientColorRgb = -1; | |||
| 21642 | } | |||
| 21643 | const auto finite = [](const DRW_Coord& point) { | |||
| 21644 | return std::isfinite(point.x) && std::isfinite(point.y) | |||
| 21645 | && std::isfinite(point.z); | |||
| 21646 | }; | |||
| 21647 | if (!finite(basePoint) || !finite(viewTarget) || !finite(viewDir) | |||
| 21648 | || !finite(ucsOrigin) || !finite(ucsXAxis) || !finite(ucsYAxis) | |||
| 21649 | || !std::isfinite(pswidth) || !std::isfinite(psheight) | |||
| 21650 | || !std::isfinite(centerPX) || !std::isfinite(centerPY) | |||
| 21651 | || !std::isfinite(snapPX) || !std::isfinite(snapPY) | |||
| 21652 | || !std::isfinite(snapSpPX) || !std::isfinite(snapSpPY) | |||
| 21653 | || !std::isfinite(gridSpX) || !std::isfinite(gridSpY) | |||
| 21654 | || !std::isfinite(viewLength) || !std::isfinite(frontClip) | |||
| 21655 | || !std::isfinite(backClip) || !std::isfinite(viewHeight) | |||
| 21656 | || !std::isfinite(snapAngle) || !std::isfinite(twistAngle) | |||
| 21657 | || !std::isfinite(ucsElevation) || !std::isfinite(brightness) | |||
| 21658 | || !std::isfinite(contrast)) | |||
| 21659 | return fail(); | |||
| 21660 | if (!validatePayloadFields()) | |||
| 21661 | return fail(); | |||
| 21662 | std::uint64_t handleEndBit = 0; | |||
| 21663 | if (!dwgHandleStreamEndBit(*sourceBuf, version, objSize, bs, | |||
| 21664 | handleEndBit)) | |||
| 21665 | return fail(); | |||
| 21666 | ret = DRW_Entity::parseDwgEntHandle(version, buf, true, handleEndBit); | |||
| 21667 | if (!ret || !buf->isGood() || !sBuf->isGood()) | |||
| 21668 | return fail(); | |||
| 21669 | ||||
| 21670 | if (!buf->isGood() || !sBuf->isGood() | |||
| 21671 | || currentDwgBit(sBuf) > stringEndBit) | |||
| 21672 | return fail(); | |||
| 21673 | ||||
| 21674 | dwgBuffer handleProbe = buf->forkIndependent(); | |||
| 21675 | auto readHandleRef = [&handleProbe, handleEndBit](std::uint32_t& target) { | |||
| 21676 | dwgHandle parsed; | |||
| 21677 | if (!readBoundedDwgHandle(handleProbe, handleEndBit, 0, false, | |||
| 21678 | parsed)) { | |||
| 21679 | return false; | |||
| 21680 | } | |||
| 21681 | target = parsed.ref; | |||
| 21682 | return true; | |||
| 21683 | }; | |||
| 21684 | if (version < DRW::AC1015) {//R13 & R14 only | |||
| 21685 | if (!readHandleRef(vpHeaderHandle)) | |||
| 21686 | return fail(); | |||
| 21687 | } | |||
| 21688 | if (version > DRW::AC1014) {//2000+ | |||
| 21689 | if (!DRW::reserve(frozenLayerHandles, static_cast<int>(frozenLyCount))) | |||
| 21690 | return fail(); | |||
| 21691 | for (std::uint32_t i = 0; i < frozenLyCount; ++i) { | |||
| 21692 | std::uint32_t ref = 0; | |||
| 21693 | if (!readHandleRef(ref)) | |||
| 21694 | return fail(); | |||
| 21695 | frozenLayerHandles.push_back(ref); | |||
| 21696 | } | |||
| 21697 | if (!readHandleRef(clipBoundaryHandle)) | |||
| 21698 | return fail(); | |||
| 21699 | if (version == DRW::AC1015) {//2000 only | |||
| 21700 | if (!readHandleRef(vpHeaderHandle)) | |||
| 21701 | return fail(); | |||
| 21702 | } | |||
| 21703 | if (!readHandleRef(namedUcsHandle) || !readHandleRef(baseUcsHandle)) | |||
| 21704 | return fail(); | |||
| 21705 | } | |||
| 21706 | if (version > DRW::AC1018) {//2007+ | |||
| 21707 | if (!readHandleRef(backgroundHandle) | |||
| 21708 | || !readHandleRef(visualStyleHandle) | |||
| 21709 | || !readHandleRef(shadePlotHandle)) | |||
| 21710 | return fail(); | |||
| 21711 | } | |||
| 21712 | if (version > DRW::AC1018 && !readHandleRef(m_sunHandle)) | |||
| 21713 | return fail(); | |||
| 21714 | if (!handleProbe.isGood() || !sBuf->isGood()) | |||
| 21715 | return fail(); | |||
| 21716 | *sourceBuf = handleProbe; | |||
| 21717 | return true; | |||
| 21718 | } | |||
| 21719 | ||||
| 21720 | // --------------------------------------------------------------------------- | |||
| 21721 | // Write helpers shared by the new encoders below. | |||
| 21722 | // --------------------------------------------------------------------------- | |||
| 21723 | ||||
| 21724 | namespace { | |||
| 21725 | // ODA handle reference codes: 3 hard owner, 4 soft pointer, 5 hard pointer. | |||
| 21726 | static void putTypedHandle(dwgBufferW *hb, std::uint32_t ref, | |||
| 21727 | std::uint8_t code) { | |||
| 21728 | dwgHandle h; | |||
| 21729 | h.code = ref == 0 ? 0 : code; | |||
| 21730 | h.ref = ref; | |||
| 21731 | h.ref64 = ref; | |||
| 21732 | h.size = 0; | |||
| 21733 | if (h.ref != 0) { | |||
| 21734 | std::uint32_t t = h.ref; | |||
| 21735 | while (t != 0) { t >>= 8; ++h.size; } | |||
| 21736 | } | |||
| 21737 | hb->putHandle(h); | |||
| 21738 | } | |||
| 21739 | ||||
| 21740 | static void putAbsHandle(dwgBufferW *hb, std::uint32_t ref) { | |||
| 21741 | putTypedHandle(hb, ref, 5); | |||
| 21742 | } | |||
| 21743 | } // namespace | |||
| 21744 | ||||
| 21745 | // --------------------------------------------------------------------------- | |||
| 21746 | // DRW_MLine::encodeDwg — OT=47 (AC1015/AC1018/AC1024) | |||
| 21747 | // --------------------------------------------------------------------------- | |||
| 21748 | ||||
| 21749 | bool DRW_MLine::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, | |||
| 21750 | dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 21751 | (void)bs; (void)strBuf; | |||
| 21752 | if (!validatePayloadFields()) | |||
| 21753 | return false; | |||
| 21754 | oType = 47; | |||
| 21755 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 21756 | ||||
| 21757 | buf->putBitDouble(scale); | |||
| 21758 | buf->putRawChar8(justification); | |||
| 21759 | buf->put3BitDouble(basePoint); | |||
| 21760 | buf->putExtrusion(extPoint, false); // false = pre-2000 style (getExtrusion(false) in parser) | |||
| 21761 | buf->putBitShort(static_cast<std::uint16_t>(openClosed)); | |||
| 21762 | buf->putRawChar8(numLines); | |||
| 21763 | buf->putBitShort(numVerts); | |||
| 21764 | ||||
| 21765 | for (const auto& vtx : vertlist) { | |||
| 21766 | buf->put3BitDouble(vtx.position); | |||
| 21767 | buf->put3BitDouble(vtx.vertexDir); | |||
| 21768 | buf->put3BitDouble(vtx.miterDir); | |||
| 21769 | for (int li = 0; li < static_cast<int>(numLines); ++li) { | |||
| 21770 | const auto& segs = (li < static_cast<int>(vtx.segParms.size())) | |||
| 21771 | ? vtx.segParms[li] : std::vector<double>{}; | |||
| 21772 | const auto& fills = (li < static_cast<int>(vtx.areaFillParms.size())) | |||
| 21773 | ? vtx.areaFillParms[li] : std::vector<double>{}; | |||
| 21774 | buf->putBitShort(static_cast<std::uint16_t>(segs.size())); | |||
| 21775 | for (double s : segs) buf->putBitDouble(s); | |||
| 21776 | buf->putBitShort(static_cast<std::uint16_t>(fills.size())); | |||
| 21777 | for (double f : fills) buf->putBitDouble(f); | |||
| 21778 | } | |||
| 21779 | } | |||
| 21780 | ||||
| 21781 | if (!encodeDwgEntHandle(version, buf, handleBuf)) return false; | |||
| 21782 | ||||
| 21783 | // MLINE style handle — extra handle after standard entity handles. | |||
| 21784 | if (version > DRW::AC1014) { | |||
| 21785 | dwgBufferW *hb = (handleBuf != nullptr) ? handleBuf : buf; | |||
| 21786 | putAbsHandle(hb, styleHandle); | |||
| 21787 | } | |||
| 21788 | return true; | |||
| 21789 | } | |||
| 21790 | ||||
| 21791 | // --------------------------------------------------------------------------- | |||
| 21792 | // DRW_Vertex::encodeDwg — OT varies by flags | |||
| 21793 | // --------------------------------------------------------------------------- | |||
| 21794 | ||||
| 21795 | bool DRW_Vertex::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, | |||
| 21796 | dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 21797 | (void)bs; (void)strBuf; | |||
| 21798 | if (buf == nullptr || !validatePayloadFields()) | |||
| 21799 | return false; | |||
| 21800 | switch (m_dwgSubtype) { | |||
| 21801 | case DwgSubtype::Vertex2D: oType = 0x0A; break; | |||
| 21802 | case DwgSubtype::Vertex3D: oType = 0x0B; break; | |||
| 21803 | case DwgSubtype::Mesh: oType = 0x0C; break; | |||
| 21804 | case DwgSubtype::Polyface: oType = 0x0D; break; | |||
| 21805 | case DwgSubtype::PolyfaceFace: oType = 0x0E; break; | |||
| 21806 | case DwgSubtype::Auto: | |||
| 21807 | if ((flags & 64) != 0) | |||
| 21808 | oType = 0x0D; // VERTEX_PFACE coordinate vertex | |||
| 21809 | else if ((flags & 128) != 0) | |||
| 21810 | oType = 0x0E; // VERTEX_PFACE_FACE | |||
| 21811 | else if ((flags & 16) != 0) | |||
| 21812 | oType = 0x0C; // VERTEX_MESH | |||
| 21813 | else if ((flags & 32) != 0 || (flags & 8) != 0) | |||
| 21814 | oType = 0x0B; // VERTEX_3D | |||
| 21815 | else | |||
| 21816 | oType = 0x0A; // VERTEX_2D | |||
| 21817 | break; | |||
| 21818 | } | |||
| 21819 | ||||
| 21820 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 21821 | ||||
| 21822 | if (oType == 0x0A) { | |||
| 21823 | buf->putRawChar8(static_cast<std::uint8_t>(flags)); | |||
| 21824 | buf->put3BitDouble(basePoint); | |||
| 21825 | buf->putBitDouble(stawidth); | |||
| 21826 | buf->putBitDouble(endwidth); | |||
| 21827 | buf->putBitDouble(bulge); | |||
| 21828 | if (version > DRW::AC1021) | |||
| 21829 | buf->putBitLong(static_cast<std::int32_t>(identifier)); | |||
| 21830 | buf->putBitDouble(tgdir); | |||
| 21831 | } else if (oType == 0x0B || oType == 0x0C || oType == 0x0D) { | |||
| 21832 | buf->putRawChar8(static_cast<std::uint8_t>(flags)); | |||
| 21833 | buf->put3BitDouble(basePoint); | |||
| 21834 | } else { // 0x0E pface face | |||
| 21835 | buf->putBitShort(static_cast<std::uint16_t>(vindex1)); | |||
| 21836 | buf->putBitShort(static_cast<std::uint16_t>(vindex2)); | |||
| 21837 | buf->putBitShort(static_cast<std::uint16_t>(vindex3)); | |||
| 21838 | buf->putBitShort(static_cast<std::uint16_t>(vindex4)); | |||
| 21839 | } | |||
| 21840 | ||||
| 21841 | return encodeDwgEntHandle(version, buf, handleBuf); | |||
| 21842 | } | |||
| 21843 | ||||
| 21844 | bool DRW_SeqEnd::parseDwg(DRW::Version version, dwgBuffer *buf, std::uint32_t bs) { | |||
| 21845 | DRW_Entity::reset(); | |||
| 21846 | if (buf == nullptr) | |||
| 21847 | return false; | |||
| 21848 | ||||
| 21849 | auto fail = [this, buf]() { | |||
| 21850 | buf->invalidate(); | |||
| 21851 | DRW_Entity::reset(); | |||
| 21852 | return false; | |||
| 21853 | }; | |||
| 21854 | dwgBuffer probe = buf->forkIndependent(); | |||
| 21855 | if (!DRW_Entity::parseDwgCommon(version, &probe, bs) | |||
| 21856 | || !probe.isGood()) | |||
| 21857 | return fail(); | |||
| 21858 | std::uint64_t handleEndBit = 0; | |||
| 21859 | if (!dwgHandleStreamEndBit(*buf, version, objSize, bs, handleEndBit) | |||
| 21860 | || !DRW_Entity::parseDwgEntHandle(version, &probe, true, | |||
| 21861 | handleEndBit) | |||
| 21862 | || !probe.isGood()) | |||
| 21863 | return fail(); | |||
| 21864 | ||||
| 21865 | *buf = probe; | |||
| 21866 | return true; | |||
| 21867 | } | |||
| 21868 | ||||
| 21869 | bool DRW_SeqEnd::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, | |||
| 21870 | dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 21871 | (void)bs; (void)strBuf; | |||
| 21872 | oType = 0x06; | |||
| 21873 | if (!encodeDwgCommon(version, buf)) | |||
| 21874 | return false; | |||
| 21875 | return encodeDwgEntHandle(version, buf, handleBuf); | |||
| 21876 | } | |||
| 21877 | ||||
| 21878 | // --------------------------------------------------------------------------- | |||
| 21879 | // DRW_Polyline::encodeDwg — OT varies by flags; vertex handles emitted here. | |||
| 21880 | // --------------------------------------------------------------------------- | |||
| 21881 | ||||
| 21882 | bool DRW_Polyline::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, | |||
| 21883 | dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 21884 | (void)bs; (void)strBuf; | |||
| 21885 | if (buf == nullptr || !validatePayloadFields()) | |||
| 21886 | return false; | |||
| 21887 | // Determine object type from stored flags (mirror of parseDwg dispatch). | |||
| 21888 | if (flags & 64) oType = 0x1D; // POLYLINE_PFACE | |||
| 21889 | else if (flags & 16) oType = 0x1E; // POLYLINE_MESH | |||
| 21890 | else if (flags & 8) oType = 0x10; // POLYLINE_3D | |||
| 21891 | else oType = 0x0F; // POLYLINE_2D | |||
| 21892 | ||||
| 21893 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 21894 | ||||
| 21895 | if (oType == 0x0F) { | |||
| 21896 | buf->putBitShort(static_cast<std::uint16_t>(flags)); | |||
| 21897 | buf->putBitShort(static_cast<std::uint16_t>(curvetype)); | |||
| 21898 | buf->putBitDouble(defstawidth); | |||
| 21899 | buf->putBitDouble(defendwidth); | |||
| 21900 | buf->putThickness(thickness, version > DRW::AC1014); | |||
| 21901 | buf->putBitDouble(basePoint.z); | |||
| 21902 | buf->putExtrusion(extPoint, version > DRW::AC1014); | |||
| 21903 | } else if (oType == 0x10) { | |||
| 21904 | // curvetype → 2 RC flag bytes (mirror of parser decode) | |||
| 21905 | std::uint8_t rc1 = 0; | |||
| 21906 | if (curvetype == 5) rc1 = 1; | |||
| 21907 | else if (curvetype == 6) rc1 = 2; | |||
| 21908 | else if (curvetype == 8) rc1 = 3; | |||
| 21909 | buf->putRawChar8(rc1); | |||
| 21910 | buf->putRawChar8(static_cast<std::uint8_t>(flags & 1)); // bit 0 = closed | |||
| 21911 | } else if (oType == 0x1D) { | |||
| 21912 | buf->putBitShort(static_cast<std::uint16_t>(vertexcount)); | |||
| 21913 | buf->putBitShort(static_cast<std::uint16_t>(facecount)); | |||
| 21914 | } else { // 0x1E MESH | |||
| 21915 | buf->putBitShort(static_cast<std::uint16_t>(flags & ~16)); // strip reader-added bit 4 | |||
| 21916 | buf->putBitShort(static_cast<std::uint16_t>(curvetype)); | |||
| 21917 | buf->putBitShort(static_cast<std::uint16_t>(vertexcount)); // M count | |||
| 21918 | buf->putBitShort(static_cast<std::uint16_t>(facecount)); // N count | |||
| 21919 | buf->putBitShort(static_cast<std::uint16_t>(smoothM)); // mDensity, DXF 73 | |||
| 21920 | buf->putBitShort(static_cast<std::uint16_t>(smoothN)); // nDensity, DXF 74 | |||
| 21921 | } | |||
| 21922 | ||||
| 21923 | // AC2004+ (>AC1015): emit vertex count before the handle section. | |||
| 21924 | std::int32_t ooCount = static_cast<std::int32_t>(vertlist.size()); | |||
| 21925 | if (version > DRW::AC1015) | |||
| 21926 | buf->putBitLong(ooCount); | |||
| 21927 | ||||
| 21928 | if (!encodeDwgEntHandle(version, buf, handleBuf)) return false; | |||
| 21929 | ||||
| 21930 | dwgBufferW *hb = (handleBuf != nullptr) ? handleBuf : buf; | |||
| 21931 | ||||
| 21932 | if (version < DRW::AC1018) { | |||
| 21933 | // R2000-: first/last vertex handles (absolute hard pointers). | |||
| 21934 | putAbsHandle(hb, vertlist.empty() ? 0u : vertlist.front()->handle); | |||
| 21935 | putAbsHandle(hb, vertlist.empty() ? 0u : vertlist.back()->handle); | |||
| 21936 | } else { | |||
| 21937 | // R2004+: one handle per vertex. | |||
| 21938 | for (const auto& v : vertlist) | |||
| 21939 | putAbsHandle(hb, v ? v->handle : 0u); | |||
| 21940 | } | |||
| 21941 | putAbsHandle(hb, seqEndH.ref); | |||
| 21942 | ||||
| 21943 | return true; | |||
| 21944 | } | |||
| 21945 | ||||
| 21946 | // --------------------------------------------------------------------------- | |||
| 21947 | // DRW_Leader::encodeDwg — OT=45 (AC1015/AC1018/AC1024) | |||
| 21948 | // --------------------------------------------------------------------------- | |||
| 21949 | ||||
| 21950 | bool DRW_Leader::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, | |||
| 21951 | dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 21952 | (void)bs; (void)strBuf; | |||
| 21953 | if (buf == nullptr || !validatePayloadFields()) | |||
| 21954 | return false; | |||
| 21955 | oType = 45; | |||
| 21956 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 21957 | ||||
| 21958 | buf->putBit(0); // unknown bit | |||
| 21959 | buf->putBitShort(static_cast<std::uint16_t>(flag)); // annotation type | |||
| 21960 | buf->putBitShort(static_cast<std::int16_t>(leadertype)); // pathType (DXF code 72) | |||
| 21961 | buf->putBitLong(static_cast<std::int32_t>(vertexlist.size())); | |||
| 21962 | for (const auto& vp : vertexlist) | |||
| 21963 | buf->put3BitDouble(*vp); | |||
| 21964 | buf->put3BitDouble(origin); // leader plane origin | |||
| 21965 | // ODA §20.4.47: Extrusion is plain 3DPOINT (3BD), not BE — matches parseDwg. | |||
| 21966 | buf->put3BitDouble(extrusionPoint); | |||
| 21967 | ||||
| 21968 | buf->put3BitDouble(horizdir); | |||
| 21969 | buf->put3BitDouble(offsetblock); | |||
| 21970 | ||||
| 21971 | if (leaderHasEndpointProjection(version)) | |||
| 21972 | buf->put3BitDouble(offsettext); // endpoint projection | |||
| 21973 | ||||
| 21974 | if (version < DRW::AC1015) | |||
| 21975 | buf->putBitDouble(0.0); // dimgap (pre-R2000) | |||
| 21976 | ||||
| 21977 | if (leaderHasTextBox(version)) { | |||
| 21978 | buf->putBitDouble(textheight); | |||
| 21979 | buf->putBitDouble(textwidth); | |||
| 21980 | } | |||
| 21981 | ||||
| 21982 | buf->putBit(static_cast<std::uint8_t>(hookline)); | |||
| 21983 | buf->putBit(static_cast<std::uint8_t>(arrow)); | |||
| 21984 | ||||
| 21985 | buf->putBitShort(0); // arrowHeadType (present in every DWG version) | |||
| 21986 | if (version < DRW::AC1015) { | |||
| 21987 | buf->putBitDouble(0.0); // dimasz | |||
| 21988 | buf->putBit(0); // unk | |||
| 21989 | buf->putBit(0); // unk | |||
| 21990 | buf->putBitShort(0); // unk short | |||
| 21991 | buf->putBitShort(static_cast<std::uint16_t>(coloruse)); // byBlock color | |||
| 21992 | buf->putBit(0); // unk | |||
| 21993 | buf->putBit(0); // unk | |||
| 21994 | } else { | |||
| 21995 | buf->putBit(0); // unk | |||
| 21996 | buf->putBit(0); // unk | |||
| 21997 | } | |||
| 21998 | ||||
| 21999 | if (!encodeDwgEntHandle(version, buf, handleBuf)) return false; | |||
| 22000 | ||||
| 22001 | dwgBufferW *hb = (handleBuf != nullptr) ? handleBuf : buf; | |||
| 22002 | putAbsHandle(hb, 0); // AnnotH — null (no annotation entity) | |||
| 22003 | putAbsHandle(hb, 0x15); // dimStyleH — hard ptr to STANDARD (handle 0x15) | |||
| 22004 | ||||
| 22005 | return buf->isGood() && hb->isGood(); | |||
| 22006 | } | |||
| 22007 | ||||
| 22008 | // --------------------------------------------------------------------------- | |||
| 22009 | // DRW_Viewport::encodeDwg — OT=34 (AC1015/AC1018/AC1024) | |||
| 22010 | // --------------------------------------------------------------------------- | |||
| 22011 | ||||
| 22012 | bool DRW_Viewport::encodeDwg(DRW::Version version, dwgBufferW *buf, std::uint32_t bs, | |||
| 22013 | dwgBufferW *strBuf, dwgBufferW *handleBuf) { | |||
| 22014 | (void)bs; | |||
| 22015 | if (buf == nullptr || !validatePayloadFields()) | |||
| 22016 | return false; | |||
| 22017 | oType = 34; | |||
| 22018 | // Use strBuf for TV strings in AC1024; for AC1015/AC1018 strings go inline. | |||
| 22019 | dwgBufferW *sb = (strBuf && version > DRW::AC1018) ? strBuf : buf; | |||
| 22020 | if (!encodeDwgCommon(version, buf)) return false; | |||
| 22021 | ||||
| 22022 | buf->putBitDouble(basePoint.x); | |||
| 22023 | buf->putBitDouble(basePoint.y); | |||
| 22024 | buf->putBitDouble(basePoint.z); | |||
| 22025 | buf->putBitDouble(pswidth); | |||
| 22026 | buf->putBitDouble(psheight); | |||
| 22027 | ||||
| 22028 | if (version > DRW::AC1014) { | |||
| 22029 | buf->putBitDouble(viewTarget.x); | |||
| 22030 | buf->putBitDouble(viewTarget.y); | |||
| 22031 | buf->putBitDouble(viewTarget.z); | |||
| 22032 | buf->putBitDouble(viewDir.x); | |||
| 22033 | buf->putBitDouble(viewDir.y); | |||
| 22034 | buf->putBitDouble(viewDir.z); | |||
| 22035 | buf->putBitDouble(twistAngle); | |||
| 22036 | buf->putBitDouble(viewHeight); | |||
| 22037 | buf->putBitDouble(viewLength); // lens length | |||
| 22038 | buf->putBitDouble(frontClip); | |||
| 22039 | buf->putBitDouble(backClip); | |||
| 22040 | buf->putBitDouble(snapAngle); | |||
| 22041 | buf->putRawDouble(centerPX); | |||
| 22042 | buf->putRawDouble(centerPY); | |||
| 22043 | buf->putRawDouble(snapPX); | |||
| 22044 | buf->putRawDouble(snapPY); | |||
| 22045 | buf->putRawDouble(snapSpPX); | |||
| 22046 | buf->putRawDouble(snapSpPY); | |||
| 22047 | buf->putRawDouble(gridSpX); | |||
| 22048 | buf->putRawDouble(gridSpY); | |||
| 22049 | buf->putBitShort(static_cast<std::uint16_t>(circleZoom)); | |||
| 22050 | } | |||
| 22051 | ||||
| 22052 | if (version > DRW::AC1018) | |||
| 22053 | buf->putBitShort(static_cast<std::uint16_t>(majorGridLines)); | |||
| 22054 | ||||
| 22055 | if (version > DRW::AC1014) { | |||
| 22056 | buf->putBitLong(static_cast<std::int32_t>(frozenLayerHandles.size())); | |||
| 22057 | buf->putBitLong(statusFlags); | |||
| 22058 | sb->putVariableText(version, styleSheet); | |||
| 22059 | buf->putRawChar8(static_cast<std::uint8_t>(renderMode)); | |||
| 22060 | buf->putBit(ucsAtOrigin ? 1 : 0); | |||
| 22061 | buf->putBit(ucsPerViewport ? 1 : 0); | |||
| 22062 | buf->put3BitDouble(ucsOrigin); | |||
| 22063 | buf->put3BitDouble(ucsXAxis); | |||
| 22064 | buf->put3BitDouble(ucsYAxis); | |||
| 22065 | buf->putBitDouble(ucsElevation); | |||
| 22066 | buf->putBitShort(static_cast<std::uint16_t>(ucsOrthographicType)); | |||
| 22067 | } | |||
| 22068 | ||||
| 22069 | if (version > DRW::AC1015) | |||
| 22070 | buf->putBitShort(static_cast<std::uint16_t>(shadePlotMode)); | |||
| 22071 | ||||
| 22072 | if (version > DRW::AC1018) { | |||
| 22073 | buf->putBit(useDefaultLighting ? 1 : 0); | |||
| 22074 | buf->putRawChar8(defaultLightingType); | |||
| 22075 | buf->putBitDouble(brightness); | |||
| 22076 | buf->putBitDouble(contrast); | |||
| 22077 | if (ambientColorRgb >= 0) { | |||
| 22078 | buf->putCmColor(version, static_cast<std::uint16_t>(ambientColor), | |||
| 22079 | ambientColorRgb, ambientColorName, "", strBuf); | |||
| 22080 | } else { | |||
| 22081 | buf->putCmColor(version, static_cast<std::uint16_t>(ambientColor)); | |||
| 22082 | } | |||
| 22083 | } | |||
| 22084 | ||||
| 22085 | if (!encodeDwgEntHandle(version, buf, handleBuf)) return false; | |||
| 22086 | ||||
| 22087 | dwgBufferW *hb = (handleBuf != nullptr) ? handleBuf : buf; | |||
| 22088 | ||||
| 22089 | if (version < DRW::AC1015) { | |||
| 22090 | putTypedHandle(hb, vpHeaderHandle, 5); | |||
| 22091 | } | |||
| 22092 | if (version > DRW::AC1014) { | |||
| 22093 | const std::uint8_t frozenCode = version == DRW::AC1015 ? 5 : 4; | |||
| 22094 | for (const std::uint32_t ref : frozenLayerHandles) | |||
| 22095 | putTypedHandle(hb, ref, frozenCode); | |||
| 22096 | putTypedHandle(hb, clipBoundaryHandle, 4); | |||
| 22097 | if (version == DRW::AC1015) | |||
| 22098 | putTypedHandle(hb, vpHeaderHandle, 5); | |||
| 22099 | putTypedHandle(hb, namedUcsHandle, 5); | |||
| 22100 | putTypedHandle(hb, baseUcsHandle, 5); | |||
| 22101 | } | |||
| 22102 | if (version > DRW::AC1018) { | |||
| 22103 | putTypedHandle(hb, backgroundHandle, 4); | |||
| 22104 | putTypedHandle(hb, visualStyleHandle, 5); | |||
| 22105 | putTypedHandle(hb, shadePlotHandle, 4); | |||
| 22106 | putTypedHandle(hb, m_sunHandle, 3); | |||
| 22107 | } | |||
| 22108 | ||||
| 22109 | return buf->isGood() && sb->isGood() && hb->isGood(); | |||
| 22110 | } |